This is bowling. There are rules

Cette semaine, c'est Damien qui vous propose un #KataOfTheWeek : This is bowling. There are rules.

Briefing du Kata : Pour calculer le score d'une partie de bowling, les règles sont les suivantes:

  • chaque partie se compose de 10 tours
  • à chaque tour, le lanceur a jusqu'à 2 essais (appelés lancés) pour renverser les 10 quilles
  • si le lanceur ne réussit pas à renverser toutes les quilles au bout de 2 essais, le score pour ce tour est égal au nombre de quilles renversées
  • si en 2 essais, le lanceur a réussi à renverser toutes les quilles (ce qui s'appelle un spare et se note /), le score pour ce tour est égal à 10 plus le nombre de quilles renversées au prochain lancé (au prochain tour)
  • si dès le premier lancé, toutes les quilles sont renversées (ce qui s'appelle un strike et se note X), le tour prend fin immédiatement et le score pour ce tour est égal à 10 plus le nombre total de quilles renversées aux 2 prochains lancés
  • si le lanceur obtient un spare ou un strike au dernier (10ème) tour, il peut lancer respectivement 1 boule bonus en cas de spare ou 2 boules bonus en cas de strike. Ces bonus font partie du même tour et ne sont utilisés que pour calculer le score du dernier tour, le processus ne se répète donc pas si toutes les quilles sont renversées à nouveau.
  • le score d'une partie est égal au total des scores de tous les tours

Pour tes tests, tu peux utiliser les cas suivants:

  • 9- 9- 9- 9- 9- 9- 9- 9- 9- 9-: série de tours avec 9 quilles renversées au 1er lancé, manqué au 2e lancé. Score total de 90
  • -5 -5 -5 -5 -5 -5 -5 -5 -5 -5: série de tours avec manqué au 1er lancé, 5 quilles renversées au 2e lancé. Score total de 50
  • 58 58 58 58 58 58 58 58 58 58: série de tours avec 5 quilles renversées au 1er lancé, puis 3 de plus au 2e lancé, pour un total de 8 par tour. Score total de 80
  • 5/ 5/ 5/ 5/ 5/ 5/ 5/ 5/ 5/ 5/5: série de tours avec 5 quilles renversées au 1er lancé, puis spare au 2e lancé. Lancé bonus de 5 en fin de partie. Score total de 150
  • X X X X X X X X X XXX: série de 10 tours avec strike, plus 2 strikes bonus en fin de partie. Score total de 300

Saurez-vous résoudre le problème ?

Bon courage !


Et voici une solution proposée par l'auteur en Java :

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();
    }

}

Votre équipe TakiVeille

TakiVeille

TakiVeille