3
\$\begingroup\$

I finished the Snakes and Ladders kata in the Agile Katas and I would like to know if there's a way to improve my code (specifically the part where the turn order is determined).

Game

public class Game {
    private Map<Player, Token> playerTokenMap;
    private Player winner;
    private final int lastSquareLocation = 101;
    private Space[] board;
    private final Player computer = new Player("COMPUTER");
    private LinkedList<Player> turnOrder;
    private int turnNumber;

    public Game(SpecialEnds specialEnds) {
        playerTokenMap = new HashMap<Player, Token>();
        turnOrder = new LinkedList<Player>();
        board = new Space[lastSquareLocation];
        for(int squareLocation = 1; squareLocation < lastSquareLocation; squareLocation++){
            Space space = new Space();
            if(specialEnds.leadsToAnotherSquareLocation(squareLocation))
                space.setDestination(specialEnds.getDestination(squareLocation));
            board[squareLocation] = space;
        }
        this.winner = Player.NO_ONE;
    }

    public void addPlayer(Player player) {
        turnOrder.clear();
        playerTokenMap.put(player, new Token());
    }

    public int getPositionOfTokenOf(Player tokenOwner) {
        return playerTokenMap.get(tokenOwner).getLocation();
    }

    public void turnPlayerMove(int spaces) {
        Player turnPlayer = getTurnPlayer();
        Token token = playerTokenMap.get(turnPlayer);
        if(tokenWillGoPastTheLastSquare(token, spaces))
            return;
        token.move(spaces);
        int tokenLocation = token.getLocation();
        if(hasSpecialEnd(tokenLocation))
            token.move(this.board[tokenLocation].getDestination() - tokenLocation);
        if(hasWonTheGame(token))
            this.winner = turnPlayer;
        turnNumber++;
    }

    private boolean hasSpecialEnd(int squareLocationOfToken) {
        return board[squareLocationOfToken].isYieldingToAnotherDestination();
    }

    private boolean hasWonTheGame(Token token) {
        return token.getLocation() == lastSquareLocation - 1;
    }

    private boolean tokenWillGoPastTheLastSquare(Token token, int numberOfSpacesToMove) {
        return token.getLocation() + numberOfSpacesToMove >  lastSquareLocation - 1;
    }

    public Player getWinner() {
        return winner;
    }

    public Player getTurnPlayer() {
        if(turnOrder.isEmpty())
            return Player.NO_ONE;
        return turnOrder.get(turnNumber % playerTokenMap.size());
    }

    public void determinePlayOrder() {
        SortedMap<Integer, Player> playOrderPlayerMap = new TreeMap<Integer, Player>();
        for(Player player : playerTokenMap.keySet()){
            int dieRollResult = player.rollDice();
            if(!playOrderPlayerMap.containsKey(dieRollResult))
                playOrderPlayerMap.put(dieRollResult, player);
            else{
                while(playOrderPlayerMap.containsKey(dieRollResult)){
                    dieRollResult = player.rollDice();
                }
                playOrderPlayerMap.put(dieRollResult, player);
            }
        }
        turnOrder.addAll(playOrderPlayerMap.values());
        Collections.reverse(turnOrder);
    }

    public void addComputerToGame() {
        addPlayer(computer);
    }
}

Space

public class Space {
    private int destination;

    public Space() {
        this.destination = -1;
    }

    public void setDestination(int destination) {
        this.destination = destination;
    }

    public boolean isYieldingToAnotherDestination() {
        return destination != -1;
    }

    public int getDestination() {
        return destination;
    }
}

SpecialEnds

public class SpecialEnds {
    private Map<Integer, Integer> mapOfSpecialEnds;

    public SpecialEnds() {
        mapOfSpecialEnds = new HashMap<Integer, Integer>();
    }

    public void add(int source, int destination){
        mapOfSpecialEnds.put(source, destination);
    }

    public boolean leadsToAnotherSquareLocation(int squareLocation) {
        return mapOfSpecialEnds.containsKey(squareLocation);
    }

    public int getDestination(int squareLocation) {
        return mapOfSpecialEnds.get(squareLocation);
    }
}

GameTest

public class GameTest {
    private Game game;
    private Player player1;

    @Before
    public void setUp() throws Exception {
        SpecialEnds specialEnds = new SpecialEnds();
        specialEnds.add(12, 2);
        specialEnds.add(3, 13);
        game = new Game(specialEnds);
        player1 = new Player("Rome");
        game.addPlayer(player1);
        game.determinePlayOrder();
    }

    @Test
    public void tokenShouldStartOnSquareOne() throws Exception {
        int expectedSquareLocation = 1;
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void tokenShouldBeInSquare4AfterMoving3SpacesFromSquare1() throws Exception {
        int expectedSquareLocation = 4;
        int numberOfSpacesToMove = 3;
        turnPlayerMove(numberOfSpacesToMove);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void tokenShouldBeInSquare8AfterMoving3SpacesThen4SpacesFromSquare1() throws Exception {
        int expectedSquareLocation = 8;
        int firstNumberOfSpacesToMove = 3;
        int secondNumberOfSpacesToMove = 4;
        turnPlayerMove(firstNumberOfSpacesToMove);
        turnPlayerMove(secondNumberOfSpacesToMove);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    private void turnPlayerMove(int spaces) {
        game.turnPlayerMove(spaces);
    }

    @Test
    public void numberOfMovesShouldBeDecidedByDieRolls() throws Exception {
        int dieResult = 1;
        int expectedSquareLocation = 5;
        while (dieResult != 4) {
            dieResult = player1.rollDice();
        }
        turnPlayerMove(dieResult);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void playerShouldWinTheGameWhenTheirTokenReachesThe100thSquare() throws Exception {
        turnPlayerMove(96);
        int numberOfSpacesToMove = 3;
        turnPlayerMove(numberOfSpacesToMove);
        assertEquals(player1, game.getWinner());
    }

    @Test
    public void playerShouldNotYetWinTheGameWhenTheirTokenMovementWillExceedThe100thSquare() throws Exception {
        turnPlayerMove(96);
        int numberOfSpacesToMove = 4;
        turnPlayerMove(numberOfSpacesToMove);
        assertNotEquals(player1, game.getWinner());
    }

    @Test
    public void tokenThatLandsOnASnakeHeadShouldGoDownOnTheTail() throws Exception {
        int expectedSquareLocation = 2;
        turnPlayerMove(11);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void tokenThatLandsOnASnakeTailShouldStayThere() throws Exception {
        int expectedSquareLocation = 2;
        turnPlayerMove(1);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void tokenThatLandsOnLowerEndOfTheLadderShouldGoUpTheLadder() throws Exception {
        int expectedSquareLocation = 13;
        turnPlayerMove(2);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void tokenThatLandsOnUpperEndOfTheLadderShouldStayThere() throws Exception {
        int expectedSquareLocation = 13;
        turnPlayerMove(12);
        assertPlayerIsIn(player1, expectedSquareLocation);
    }

    @Test
    public void player1ShouldBeFirstIfPlayer1RollsHigherThanPlayer2() throws Exception {
        Player player2 = new Player("Ein");
        game.addPlayer(player2);
        while (isNotFirstToRoll(player1))
            game.determinePlayOrder();
        assertTurnPlayerIs(player1);
    }

    @Test
    public void player2ShouldBeFirstIfPlayer2RollsHigherThanPlayer1() throws Exception {
        Player player2 = new Player("Ein");
        game.addPlayer(player2);
        while (isNotFirstToRoll(player2))
            game.determinePlayOrder();
        assertTurnPlayerIs(player2);
    }

    private void assertTurnPlayerIs(Player player2) {
        assertEquals(player2, game.getTurnPlayer());
    }

    @Test
    public void player2ShouldGoNextAfterPlayer1() throws Exception {
        Player player2 = new Player("Ein");
        game.addPlayer(player2);
        while (isNotFirstToRoll(player1))
            game.determinePlayOrder();
        turnPlayerMove(2);
        assertTurnPlayerIs(player2);
    }

    @Test
    public void player1ShouldGoNextAfterPlayer2GoingAfterPlayer1() throws Exception {
        Player player2 = new Player("Ein");
        game.addPlayer(player2);
        while (isNotFirstToRoll(player1))
            game.determinePlayOrder();
        turnPlayerMove(2);
        turnPlayerMove(2);
        assertTurnPlayerIs(player1);
    }

    private boolean isNotFirstToRoll(Player player) {
        return !player.equals(game.getTurnPlayer());
    }

    @Test
    public void computerShouldGoFirstIfComputerRollsHigherThanPlayer1() throws Exception {
        Player expectedTurnPlayer = new Player("COMPUTER");
        game.addComputerToGame();
        while (isNotFirstToRoll(expectedTurnPlayer))
            game.determinePlayOrder();
        assertTurnPlayerIs(expectedTurnPlayer);
    }

    @Test
    public void computerShouldBeAbleToRollTheDie() throws Exception {
        int expectedSquareLocation = 2;
        Player computer = new Player("COMPUTER");
        game.addComputerToGame();
        while (isNotFirstToRoll(computer))
            game.determinePlayOrder();
        turnPlayerMove(1);
        assertPlayerIsIn(computer, expectedSquareLocation);
    }

    private void assertPlayerIsIn(Player computer, int expectedSquareLocation) {
        assertTrue(game.getPositionOfTokenOf(computer) == expectedSquareLocation);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.