package de.edu.hsfulda.ccip.tdd.purefunction; import java.util.regex.Matcher; import java.util.regex.Pattern; public class BowlingCalculator { private static final String FOUL = "-"; private static final int SPLIT_NEXT_ROLL = 2; private static final int STRIKE_NEXT_ROLL = 1; private static final int MAX_PIN_COUNT = 10; @FunctionalInterface interface FrameScorer { int score(Matcher frameMatcher); } private static final int INITIAL_SCORE = 0; private static final Pattern SINGLE_ROLL_PATTERN = Pattern.compile("\\d"); private static final Pattern SPARE_PATTERN = Pattern.compile("(\\d)/ ([-\\d])"); private static final Pattern STRIKE_PATTERN = Pattern.compile("X ([-\\d])([-\\d])"); public int score(String rolls) { int score = INITIAL_SCORE; Matcher singleRollMatcher = SINGLE_ROLL_PATTERN.matcher(rolls); score = scoreFrameType(score, singleRollMatcher, matcher -> Integer.parseInt(singleRollMatcher.group())); Matcher spareMatcher = SPARE_PATTERN.matcher(rolls); score = scoreFrameType(score, spareMatcher, matcher -> scoreSpareFrame(spareMatcher)); Matcher strikeMatcher = STRIKE_PATTERN.matcher(rolls); score = scoreFrameType(score, strikeMatcher, matcher -> scoreStrike(strikeMatcher)); return score; } private int scoreStrike(Matcher strikeMatcher) { int frameScore = MAX_PIN_COUNT; for (int nextRollIndex = STRIKE_NEXT_ROLL; nextRollIndex <= STRIKE_NEXT_ROLL + 1; nextRollIndex++) { frameScore = addNextRollToCurrentFrame(strikeMatcher, frameScore, nextRollIndex); } return frameScore; } private int scoreSpareFrame(Matcher spareMatcher) { int frameScore = MAX_PIN_COUNT - Integer.parseInt(spareMatcher.group(1)); int nextRollIndex = SPLIT_NEXT_ROLL; return addNextRollToCurrentFrame(spareMatcher, frameScore, nextRollIndex); } private int scoreFrameType(int score, Matcher scoreMatcher, FrameScorer frameScorer) { while (scoreMatcher.find()) { score += frameScorer.score(scoreMatcher); } return score; } private int addNextRollToCurrentFrame(Matcher frameMatcher, int frameScore, int nextRollIndex) { String nextRoll = frameMatcher.group(nextRollIndex); if (!FOUL.equalsIgnoreCase(nextRoll)) { frameScore += Integer.parseInt(nextRoll); } return frameScore; } }