Skip to content

Instantly share code, notes, and snippets.

@williamhogman
Created June 11, 2018 18:48
Show Gist options
  • Select an option

  • Save williamhogman/0201f06ec6e92ee0766491718d0ac84f to your computer and use it in GitHub Desktop.

Select an option

Save williamhogman/0201f06ec6e92ee0766491718d0ac84f to your computer and use it in GitHub Desktop.
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;
}
}
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;
}
}
}
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 : "));
}
}
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));
}
}
package com.perfectial.assessment.tennis.exception;
public class MalformedGameException extends RuntimeException {
public MalformedGameException(String message) {
super(message);
}
}
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);
}
}
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