On se retrouve aujourd'hui pour la solution du précédent #KataOfTheWeek proposé par Damien en début de semaine !
La solution complète et testée de Ron Jeffries en C# ici. Il décrit tout son processus d'analyse et de TDD, c'est hyper intéressant.
Ma solution perso en Java, avec le parsing de la ligne de score:
import java.util.ArrayList;
import java.util.List;
interface Frame {
int getScore();
}
enum Roll {
STRIKE('X', 10),
SPARE('/', 10),
NINE('9', 9),
EIGHT('8', 8),
SEVEN('7', 7),
SIX('6', 6),
FIVE('5', 5),
FOUR('4', 4),
THREE('3', 3),
TWO('2', 2),
ONE('1', 1),
MISS('-', 0);
private final char output;
private final int points;
Roll(char output, int points) {
this.output = output;
this.points = points;
}
public int getPoints() {
return points;
}
public static Roll of(char c) {
return Arrays.stream(values())
.filter(it -> it.output == c)
.findAny()
.orElse(null);
}
}
final class SimpleFrame implements Frame {
private final Roll first;
private final Roll second;
public SimpleFrame(Roll first, Roll second) {
this.first = first;
this.second = second;
}
@Override
public int getScore() {
return second.getPoints();
}
}
final class Spare implements Frame {
private final Roll first;
private final Roll third;
public Spare(Roll first, Roll third) {
this.first = first;
this.third = third;
}
@Override
public int getScore() {
return Roll.SPARE.getPoints() + third.getPoints();
}
}
final class Strike implements Frame {
private final Roll second;
private final Roll third;
public Strike(Roll second, Roll third) {
this.second = second;
this.third = third;
}
private int pointsFromNextFrame() {
if (second == Roll.STRIKE) return second.getPoints() + third.getPoints();
return third.getPoints();
}
@Override
public int getScore() {
return Roll.STRIKE.getPoints() + pointsFromNextFrame();
}
}
final class Strings {
static String skip(String s, int skip) {
return s.substring(skip);
}
private Strings() {
}
}
public final class Line {
private static final int NUMBER_OF_FRAMES = 10;
public static Line parse(String line) {
line = line.replace(" ", "");
List<Frame> frames = new ArrayList<>();
int remainingFrames = NUMBER_OF_FRAMES;
while (remainingFrames > 0) {
Roll first = Roll.of(line.charAt(0));
Roll second = Roll.of(line.charAt(1));
if (first == Roll.STRIKE) {
frames.add(new Strike(second, Roll.of(line.charAt(2))));
line = Strings.skip(line, 1);
} else if (second == Roll.SPARE) {
frames.add(new Spare(first, Roll.of(line.charAt(2))));
line = Strings.skip(line, 2);
} else {
frames.add(new SimpleFrame(first, second));
line = Strings.skip(line, 2);
}
remainingFrames--;
}
return new Line(frames);
}
private final List<Frame> frames;
public Line(List<Frame> frames) {
this.frames = frames;
}
public int getScore() {
return frames.stream()
.mapToInt(Frame::getScore)
.sum();
}
}
Et les tests:
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class LineTest {
@Test
public void getPoints_of_full_miss_should_return_0() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- --").getScore()).isEqualTo(0);
}
@Test
public void getPoints_of_full_miss_spare_should_return_0() {
assertThat(Line.parse("-/ -/ -/ -/ -/ -/ -/ -/ -/ -/-").getScore()).isEqualTo(100);
}
@Test
public void getPoints_spare_five_should_return_20() {
assertThat(Line.parse("-/ 55 -- -- -- -- -- -- -- --").getScore()).isEqualTo(20);
}
@Test
public void getPoints_spare_strike_should_return_30() {
assertThat(Line.parse("-/ X -- -- -- -- -- -- -- --").getScore()).isEqualTo(30);
}
@Test
public void getPoints_spare_five_at_end_should_return_15() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- -/5").getScore()).isEqualTo(15);
}
@Test
public void getPoints_spare_strike_at_end_should_return_20() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- -/X").getScore()).isEqualTo(20);
}
@Test
public void getPoints_strike_five_five_should_return_20() {
assertThat(Line.parse("X 55 -- -- -- -- -- -- -- --").getScore()).isEqualTo(20);
}
@Test
public void getPoints_strike_five_eight_should_return_26() {
assertThat(Line.parse("X 58 -- -- -- -- -- -- -- --").getScore()).isEqualTo(26);
}
@Test
public void getPoints_strike_strike_miss_should_return_30() {
assertThat(Line.parse("X X -- -- -- -- -- -- -- --").getScore()).isEqualTo(30);
}
@Test
public void getPoints_strike_strike_five_should_return_45() {
assertThat(Line.parse("X X 55 -- -- -- -- -- -- --").getScore()).isEqualTo(45);
}
@Test
public void getPoints_strike_five_eight_at_end_should_return_18() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- X58").getScore()).isEqualTo(18);
}
@Test
public void getPoints_strike_strike_miss_at_end_should_return_20() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- XX-").getScore()).isEqualTo(20);
}
@Test
public void getPoints_strike_strike_five_at_end_should_return_25() {
assertThat(Line.parse("-- -- -- -- -- -- -- -- -- XX5").getScore()).isEqualTo(25);
}
@Test
public void getPoints_of_full_strike_should_return_300() {
assertThat(Line.parse("X X X X X X X X X XXX").getScore()).isEqualTo(300);
}
}
A bientôt pour un nouveau #KataOfTheWeek !