Created
June 11, 2018 18:48
-
-
Save williamhogman/0201f06ec6e92ee0766491718d0ac84f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import com.perfectial.assessment.tennis.exception.MalformedGameException; | |
| public class Game { | |
| private Player player1; | |
| private Player player2; | |
| private GameState gameState; | |
| private boolean inProgress; | |
| private Player wonBy; | |
| public GameState getGameState() { | |
| return gameState; | |
| } | |
| public void pointWonBy(Player player) { | |
| Integer wonPointPlayerScore = gameState.getScoreByPlayer(player); | |
| Integer opponentScore = gameState.getScoreByPlayer(getOppositeToPlayer(player)); | |
| if ((wonPointPlayerScore == 3 && wonPointPlayerScore.compareTo(opponentScore) > 0) || | |
| ((wonPointPlayerScore >= 3 && opponentScore >= 3) && | |
| (wonPointPlayerScore - opponentScore == 1) | |
| ) | |
| ) { | |
| inProgress = false; | |
| wonBy = player; | |
| } else { | |
| gameState = GameState.pointWonBy(gameState, player); | |
| } | |
| } | |
| public Player getGameWinner() { | |
| return wonBy; | |
| } | |
| private Player getOppositeToPlayer(Player player) { | |
| return player == player1 ? player2 : player1; | |
| } | |
| public Game(Player player1, Player player2) { | |
| if (isEmpty(player1) || isEmpty(player2)) { | |
| throw new MalformedGameException("To start the game you need two players"); | |
| } | |
| this.player1 = player1; | |
| this.player2 = player2; | |
| gameState = new GameState(player1, player2); | |
| inProgress = true; | |
| } | |
| public boolean isInProgress() { | |
| return inProgress; | |
| } | |
| private boolean isEmpty(Player player) { | |
| return player == null; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import java.util.*; | |
| public class GameState implements Cloneable { | |
| private Map<Player, Integer> scoreMap; | |
| private static final String NUMERIC_FORMAT = "%s : %s"; | |
| private static final String EMPTY = ""; | |
| public GameState(Player player1, Player player2) { | |
| scoreMap = new LinkedHashMap<>(); | |
| scoreMap.put(player1, 0); | |
| scoreMap.put(player2, 0); | |
| } | |
| public GameState(GameState gameState){ | |
| this.scoreMap = new LinkedHashMap<>(gameState.getScoreMap()); | |
| } | |
| public static GameState pointWonBy(GameState gameState, Player player) { | |
| GameState newGameState = new GameState(gameState); | |
| newGameState.scoreMap.merge(player, 1, (oldValue, one) -> oldValue + one); | |
| return newGameState; | |
| } | |
| public Integer getScoreByPlayer(Player player) { | |
| return scoreMap.get(player); | |
| } | |
| public static String getScore(GameState gameState) { | |
| List<Integer> scores = new ArrayList<>(gameState.getScoreMap().values()); | |
| if (scores.get(0) >= 3 && scores.get(1) >= 3) { | |
| if (scores.get(0).compareTo(scores.get(1)) == 0) { | |
| return Score.DEUCE.getScore(); | |
| } | |
| if (scores.get(0) - scores.get(1) > 0) { | |
| return String.format(NUMERIC_FORMAT, Score.ADVANTAGE.getScore(), EMPTY); | |
| } else { | |
| return String.format(NUMERIC_FORMAT, EMPTY, Score.ADVANTAGE.getScore()); | |
| } | |
| } | |
| return String.format(NUMERIC_FORMAT, Score.values()[scores.get(0)].score, | |
| Score.values()[scores.get(1)].score); | |
| } | |
| public Map<Player, Integer> getScoreMap() { | |
| return scoreMap; | |
| } | |
| enum Score { | |
| ZERO("0"), FIFTEEN("15"), THIRTY("30"), FOURTY("40"), DEUCE("DEUCE"), ADVANTAGE("ADVANTAGE"); | |
| String score; | |
| Score(String score) { | |
| this.score = score; | |
| } | |
| String getScore() { | |
| return score; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import org.junit.Test; | |
| import static com.perfectial.assessment.tennis.GameTest.*; | |
| import static org.hamcrest.MatcherAssert.assertThat; | |
| import static org.hamcrest.Matchers.is; | |
| public class GameStateTest { | |
| @Test | |
| public void numericValues() { | |
| GameState gameStateInitial = new GameState(player1, player2); | |
| GameState gameState = GameState.pointWonBy(gameStateInitial, player1); | |
| assertThat(gameState == gameStateInitial, is(false)); | |
| assertThat(GameState.getScore(gameState), is("15 : 0")); | |
| gameState = GameState.pointWonBy(gameState, player2); | |
| assertThat(GameState.getScore(gameState), is("15 : 15")); | |
| gameState = GameState.pointWonBy(gameState, player2); | |
| assertThat(GameState.getScore(gameState), is("15 : 30")); | |
| gameState = GameState.pointWonBy(gameState, player1); | |
| gameState = GameState.pointWonBy(gameState, player1); | |
| assertThat(GameState.getScore(gameState), is("40 : 30")); | |
| gameState = GameState.pointWonBy(gameState, player2); | |
| assertThat(GameState.getScore(gameState), is("DEUCE")); | |
| gameState = GameState.pointWonBy(gameState, player2); | |
| assertThat(GameState.getScore(gameState), is(" : ADVANTAGE")); | |
| gameState = GameState.pointWonBy(gameState, player1); | |
| assertThat(GameState.getScore(gameState), is("DEUCE")); | |
| gameState = GameState.pointWonBy(gameState, player1); | |
| assertThat(GameState.getScore(gameState), is("ADVANTAGE : ")); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import com.perfectial.assessment.tennis.exception.MalformedGameException; | |
| import org.junit.Test; | |
| import static org.hamcrest.Matchers.is; | |
| import static org.junit.Assert.*; | |
| public class GameTest { | |
| public static Player player1 = PlayerFactory.makePlayer("Nadal"); | |
| public static Player player2 = PlayerFactory.makePlayer("Federer"); | |
| @Test(expected = Test.None.class) | |
| public void thereAreExactlyTwoPlayersHappyPath() { | |
| new Game(player1, player2); | |
| } | |
| @Test(expected = MalformedGameException.class) | |
| public void thereAreExactlyTwoPlayersBothNotPresent() { | |
| new Game(null, null); | |
| } | |
| @Test(expected = MalformedGameException.class) | |
| public void thereAreExactlyTwoPlayersFirstNotPresent() { | |
| new Game(null, player2); | |
| } | |
| @Test(expected = MalformedGameException.class) | |
| public void thereAreExactlyTwoPlayersSecondNotPresent() { | |
| new Game(player1, null); | |
| } | |
| @Test | |
| public void player1Scores() { | |
| Game game = new Game(player1, player2); | |
| game.pointWonBy(player1); | |
| assertThat(game.getGameState().getScoreByPlayer(player1), is(1)); | |
| assertThat(game.getGameState().getScoreByPlayer(player2), is(0)); | |
| } | |
| @Test | |
| public void player2Scores() { | |
| Game game = new Game(player1, player2); | |
| game.pointWonBy(player2); | |
| assertThat(game.getGameState().getScoreByPlayer(player1), is(0)); | |
| assertThat(game.getGameState().getScoreByPlayer(player2), is(1)); | |
| } | |
| @Test | |
| public void startedGameNotEndedState() { | |
| Game game = new Game(player1, player2); | |
| assertThat(game.isInProgress(), is(true)); | |
| } | |
| @Test | |
| public void finishedGameHasEndedStateForPlayer1() { | |
| Game game = new Game(player1, player2); | |
| sequentialPointsWonByPlayer(game, player1); | |
| } | |
| @Test | |
| public void finishedGameHasEndedStateForPlayer2() { | |
| Game game = new Game(player1, player2); | |
| sequentialPointsWonByPlayer(game, player2); | |
| } | |
| private void sequentialPointsWonByPlayer(Game game, Player player) { | |
| game.pointWonBy(player); | |
| game.pointWonBy(player); | |
| game.pointWonBy(player); | |
| game.pointWonBy(player); | |
| assertThat(game.isInProgress(), is(false)); | |
| } | |
| private void followToDeuceState(Game game, Player player1, Player player2) { | |
| game.pointWonBy(player2); | |
| game.pointWonBy(player2); | |
| game.pointWonBy(player2); | |
| game.pointWonBy(player1); | |
| game.pointWonBy(player1); | |
| game.pointWonBy(player1); | |
| } | |
| @Test | |
| public void deuceTest() { | |
| Game game = new Game(player1, player2); | |
| followToDeuceState(game, player1, player2); | |
| assertThat(game.isInProgress(), is(true)); | |
| } | |
| @Test | |
| public void winPLayer1AfterDeuce() { | |
| Game game = new Game(player1, player2); | |
| followToDeuceState(game, player1, player2); | |
| scoreTwoTimesByPlayer(game, player1); | |
| } | |
| @Test | |
| public void winPLayer2AfterDeuce() { | |
| Game game = new Game(player1, player2); | |
| followToDeuceState(game, player1, player2); | |
| scoreTwoTimesByPlayer(game, player2); | |
| } | |
| private void scoreTwoTimesByPlayer(Game game, Player player) { | |
| game.pointWonBy(player); | |
| game.pointWonBy(player); | |
| assertThat(game.isInProgress(), is(false)); | |
| assertThat(game.getGameWinner(), is(player)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis.exception; | |
| public class MalformedGameException extends RuntimeException { | |
| public MalformedGameException(String message) { | |
| super(message); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import java.util.Objects; | |
| public class Player { | |
| private String name; | |
| public Player(String name) { | |
| this.name = name; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) return true; | |
| if (o == null || getClass() != o.getClass()) return false; | |
| Player player = (Player) o; | |
| return Objects.equals(name, player.name); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return Objects.hash(name); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.perfectial.assessment.tennis; | |
| import com.perfectial.assessment.tennis.Player; | |
| public class PlayerFactory { | |
| public static Player makePlayer(String name){ | |
| return new Player(name); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment