From bf099f2ee34a3640b91e99a6d76ff086b77c2cc1 Mon Sep 17 00:00:00 2001 From: Joffrey BION Date: Thu, 2 Feb 2017 01:02:02 +0100 Subject: Decouple Lobby and Players from the Game itself --- .../sevenwonders/controllers/GameController.java | 27 +-- .../sevenwonders/controllers/LobbyController.java | 15 +- .../java/org/luxons/sevenwonders/game/Game.java | 62 +++---- .../java/org/luxons/sevenwonders/game/Lobby.java | 142 ---------------- .../java/org/luxons/sevenwonders/game/Player.java | 59 ------- .../java/org/luxons/sevenwonders/game/State.java | 6 - .../sevenwonders/game/api/PlayerTurnInfo.java | 12 +- .../luxons/sevenwonders/game/api/PreparedCard.java | 24 --- .../org/luxons/sevenwonders/game/boards/Board.java | 17 +- .../sevenwonders/game/data/GameDefinition.java | 18 +- .../sevenwonders/game/scoring/PlayerScore.java | 7 +- .../java/org/luxons/sevenwonders/lobby/Lobby.java | 143 ++++++++++++++++ .../java/org/luxons/sevenwonders/lobby/Player.java | 60 +++++++ .../java/org/luxons/sevenwonders/lobby/State.java | 6 + .../luxons/sevenwonders/output/PreparedCard.java | 24 +++ .../sevenwonders/repositories/GameRepository.java | 49 ------ .../sevenwonders/repositories/LobbyRepository.java | 4 +- .../repositories/PlayerRepository.java | 2 +- .../validation/DestinationAccessValidator.java | 16 +- .../org/luxons/sevenwonders/game/LobbyTest.java | 179 -------------------- .../luxons/sevenwonders/game/boards/BoardTest.java | 12 +- .../luxons/sevenwonders/game/cards/CardTest.java | 8 +- .../sevenwonders/game/data/GameDefinitionTest.java | 10 +- .../luxons/sevenwonders/game/test/TestUtils.java | 34 +--- .../org/luxons/sevenwonders/lobby/LobbyTest.java | 181 +++++++++++++++++++++ .../repositories/GameRepositoryTest.java | 61 ------- .../repositories/LobbyRepositoryTest.java | 4 +- .../repositories/PlayerRepositoryTest.java | 2 +- .../validation/DestinationAccessValidatorTest.java | 22 +-- 29 files changed, 504 insertions(+), 702 deletions(-) delete mode 100644 backend/src/main/java/org/luxons/sevenwonders/game/Lobby.java delete mode 100644 backend/src/main/java/org/luxons/sevenwonders/game/Player.java delete mode 100644 backend/src/main/java/org/luxons/sevenwonders/game/State.java delete mode 100644 backend/src/main/java/org/luxons/sevenwonders/game/api/PreparedCard.java create mode 100644 backend/src/main/java/org/luxons/sevenwonders/lobby/Lobby.java create mode 100644 backend/src/main/java/org/luxons/sevenwonders/lobby/Player.java create mode 100644 backend/src/main/java/org/luxons/sevenwonders/lobby/State.java create mode 100644 backend/src/main/java/org/luxons/sevenwonders/output/PreparedCard.java delete mode 100644 backend/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java delete mode 100644 backend/src/test/java/org/luxons/sevenwonders/game/LobbyTest.java create mode 100644 backend/src/test/java/org/luxons/sevenwonders/lobby/LobbyTest.java delete mode 100644 backend/src/test/java/org/luxons/sevenwonders/repositories/GameRepositoryTest.java (limited to 'backend') diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java index 3f3a02db..390d3e83 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/GameController.java @@ -4,9 +4,12 @@ import java.security.Principal; import org.luxons.sevenwonders.actions.PrepareCardAction; import org.luxons.sevenwonders.game.Game; +import org.luxons.sevenwonders.lobby.Lobby; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.game.api.PlayerTurnInfo; -import org.luxons.sevenwonders.game.api.PreparedCard; -import org.luxons.sevenwonders.repositories.GameRepository; +import org.luxons.sevenwonders.output.PreparedCard; +import org.luxons.sevenwonders.game.cards.CardBack; +import org.luxons.sevenwonders.repositories.PlayerRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -22,23 +25,25 @@ public class GameController { private final SimpMessagingTemplate template; - private final GameRepository gameRepository; + private final PlayerRepository playerRepository; @Autowired - public GameController(SimpMessagingTemplate template, GameRepository gameRepository) { + public GameController(SimpMessagingTemplate template, PlayerRepository playerRepository) { this.template = template; - this.gameRepository = gameRepository; + this.playerRepository = playerRepository; } @MessageMapping("/game/{gameId}/prepare") public void prepareCard(@DestinationVariable long gameId, PrepareCardAction action, Principal principal) { - Game game = gameRepository.find(gameId); - PreparedCard preparedCard = game.prepareCard(principal.getName(), action.getMove()); + Player player = playerRepository.find(principal.getName()); + Game game = player.getGame(); + CardBack preparedCardBack = game.prepareCard(player.getIndex(), action.getMove()); + PreparedCard preparedCard = new PreparedCard(player, preparedCardBack); logger.info("Game '{}': player {} prepared move {}", gameId, principal.getName(), action.getMove()); if (game.areAllPlayersReady()) { game.playTurn(); - sendTurnInfo(game); + sendTurnInfo(player.getLobby(), game); } else { sendPreparedCard(preparedCard, game); } @@ -48,10 +53,10 @@ public class GameController { template.convertAndSend("/topic/game/" + game.getId() + "/prepared", preparedCard); } - private void sendTurnInfo(Game game) { + private void sendTurnInfo(Lobby lobby, Game game) { for (PlayerTurnInfo turnInfo : game.getCurrentTurnInfo()) { - String username = turnInfo.getPlayer().getUsername(); - template.convertAndSendToUser(username, "/queue/game/" + game.getId() + "/turn", turnInfo); + Player player = lobby.getPlayers().get(turnInfo.getPlayerIndex()); + template.convertAndSendToUser(player.getUsername(), "/queue/game/turn", turnInfo); } } } diff --git a/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java index cbc69602..b9381cf8 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java +++ b/backend/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java @@ -11,9 +11,8 @@ import org.luxons.sevenwonders.actions.ReorderPlayersAction; import org.luxons.sevenwonders.actions.UpdateSettingsAction; import org.luxons.sevenwonders.errors.ApiMisuseException; import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Lobby; -import org.luxons.sevenwonders.game.Player; -import org.luxons.sevenwonders.repositories.GameRepository; +import org.luxons.sevenwonders.lobby.Lobby; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.repositories.LobbyRepository; import org.luxons.sevenwonders.repositories.PlayerRepository; import org.slf4j.Logger; @@ -33,17 +32,14 @@ public class LobbyController { private final LobbyRepository lobbyRepository; - private final GameRepository gameRepository; - private final PlayerRepository playerRepository; private final SimpMessagingTemplate template; @Autowired - public LobbyController(LobbyRepository lobbyRepository, GameRepository gameRepository, - PlayerRepository playerRepository, SimpMessagingTemplate template) { + public LobbyController(LobbyRepository lobbyRepository, PlayerRepository playerRepository, + SimpMessagingTemplate template) { this.lobbyRepository = lobbyRepository; - this.gameRepository = gameRepository; this.playerRepository = playerRepository; this.template = template; } @@ -131,10 +127,9 @@ public class LobbyController { public void startGame(Principal principal) { Lobby lobby = getOwnedLobby(principal); Game game = lobby.startGame(); - gameRepository.add(game); logger.info("Game {} successfully started", game.getId()); - template.convertAndSend("/topic/lobby/" + lobby.getId() + "/started", (Object)null); + template.convertAndSend("/topic/lobby/" + lobby.getId() + "/started", (Object) null); } private Lobby getOwnedLobby(Principal principal) { diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/Game.java b/backend/src/main/java/org/luxons/sevenwonders/game/Game.java index 206b4697..d90a2381 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/game/Game.java +++ b/backend/src/main/java/org/luxons/sevenwonders/game/Game.java @@ -5,17 +5,15 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import org.luxons.sevenwonders.game.api.Action; import org.luxons.sevenwonders.game.api.HandCard; import org.luxons.sevenwonders.game.api.PlayerMove; import org.luxons.sevenwonders.game.api.PlayerTurnInfo; -import org.luxons.sevenwonders.game.api.PreparedCard; import org.luxons.sevenwonders.game.api.Table; import org.luxons.sevenwonders.game.boards.Board; import org.luxons.sevenwonders.game.cards.Card; +import org.luxons.sevenwonders.game.cards.CardBack; import org.luxons.sevenwonders.game.cards.Decks; import org.luxons.sevenwonders.game.cards.Hands; import org.luxons.sevenwonders.game.effects.SpecialAbility; @@ -30,7 +28,7 @@ public class Game { private final Settings settings; - private final List players; + private final int nbPlayers; private final Table table; @@ -44,10 +42,10 @@ public class Game { private Hands hands; - public Game(long id, Settings settings, List players, List boards, Decks decks) { + public Game(long id, Settings settings, int nbPlayers, List boards, Decks decks) { this.id = id; this.settings = settings; - this.players = players; + this.nbPlayers = nbPlayers; this.table = new Table(boards); this.decks = decks; this.discardedCards = new ArrayList<>(); @@ -60,14 +58,6 @@ public class Game { return id; } - public boolean containsUser(String username) { - return players.stream().anyMatch(p -> p.getUsername().equals(username)); - } - - public List getPlayers() { - return players; - } - private void startNewAge() { table.increaseCurrentAge(); hands = decks.deal(table.getCurrentAge(), table.getNbPlayers()); @@ -75,17 +65,17 @@ public class Game { } private void startNewTurn() { - Function extractPlayerIndex = pti -> pti.getPlayer().getIndex(); - currentTurnInfo = players.stream() - .map(this::createPlayerTurnInfo) - .collect(Collectors.toMap(extractPlayerIndex, pti -> pti)); + currentTurnInfo.clear(); + for (int i = 0; i < nbPlayers; i++) { + currentTurnInfo.put(i, createPlayerTurnInfo(i)); + } } - private PlayerTurnInfo createPlayerTurnInfo(Player player) { - PlayerTurnInfo pti = new PlayerTurnInfo(player, table); - List hand = hands.createHand(table, player.getIndex()); + private PlayerTurnInfo createPlayerTurnInfo(int playerIndex) { + PlayerTurnInfo pti = new PlayerTurnInfo(playerIndex, table); + List hand = hands.createHand(table, playerIndex); pti.setHand(hand); - Action action = determineAction(hand, table.getBoard(player.getIndex())); + Action action = determineAction(hand, table.getBoard(playerIndex)); pti.setAction(action); pti.setMessage(action.getMessage()); return pti; @@ -109,20 +99,12 @@ public class Game { } } - public PreparedCard prepareCard(String username, PlayerMove playerMove) throws InvalidMoveException { - Player player = getPlayer(username); + public CardBack prepareCard(int playerIndex, PlayerMove playerMove) throws InvalidMoveException { Card card = decks.getCard(playerMove.getCardName()); - Move move = playerMove.getType().resolve(player.getIndex(), card, playerMove); + Move move = playerMove.getType().resolve(playerIndex, card, playerMove); validate(move); - preparedMoves.put(player.getIndex(), move); - return new PreparedCard(player, card.getBack()); - } - - private Player getPlayer(String username) { - return players.stream() - .filter(p -> p.getUsername().equals(username)) - .findAny() - .orElseThrow(() -> new UnknownPlayerException(username)); + preparedMoves.put(playerIndex, move); + return card.getBack(); } private void validate(Move move) throws InvalidMoveException { @@ -196,10 +178,10 @@ public class Game { } private void discardLastCardsOfHands() { - for (Player p : players) { - Board board = table.getBoard(p.getIndex()); + for (int i = 0; i < nbPlayers; i++) { + Board board = table.getBoard(i); if (!board.hasSpecial(SpecialAbility.PLAY_LAST_CARD)) { - discardHand(p.getIndex()); + discardHand(i); } } } @@ -242,12 +224,6 @@ public class Game { } } - private static class UnknownPlayerException extends IllegalArgumentException { - UnknownPlayerException(String username) { - super(username); - } - } - private static class InvalidMoveException extends IllegalArgumentException { InvalidMoveException(String message) { super(message); diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/backend/src/main/java/org/luxons/sevenwonders/game/Lobby.java deleted file mode 100644 index b90283a8..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/game/Lobby.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.luxons.sevenwonders.game; - -import java.util.ArrayList; -import java.util.List; - -import org.luxons.sevenwonders.game.api.CustomizableSettings; -import org.luxons.sevenwonders.game.data.GameDefinition; - -public class Lobby { - - private final long id; - - private final String name; - - private final Player owner; - - private final GameDefinition gameDefinition; - - private final List players; - - private CustomizableSettings settings; - - private State state = State.LOBBY; - - public Lobby(long id, String name, Player owner, GameDefinition gameDefinition) { - this.id = id; - this.name = name; - this.owner = owner; - this.gameDefinition = gameDefinition; - this.players = new ArrayList<>(gameDefinition.getMinPlayers()); - this.settings = new CustomizableSettings(); - players.add(owner); - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public List getPlayers() { - return players; - } - - public CustomizableSettings getSettings() { - return settings; - } - - public void setSettings(CustomizableSettings settings) { - this.settings = settings; - } - - public State getState() { - return state; - } - - public synchronized void addPlayer(Player player) throws GameAlreadyStartedException, PlayerOverflowException { - if (hasStarted()) { - throw new GameAlreadyStartedException(); - } - if (maxPlayersReached()) { - throw new PlayerOverflowException(); - } - if (playerNameAlreadyUsed(player.getDisplayName())) { - throw new PlayerNameAlreadyUsedException(player.getDisplayName()); - } - player.setIndex(players.size()); - players.add(player); - } - - private boolean hasStarted() { - return state != State.LOBBY; - } - - private boolean maxPlayersReached() { - return players.size() >= gameDefinition.getMaxPlayers(); - } - - private boolean playerNameAlreadyUsed(String name) { - return players.stream().anyMatch(p -> p.getDisplayName().equals(name)); - } - - public synchronized Game startGame() throws PlayerUnderflowException { - if (!hasEnoughPlayers()) { - throw new PlayerUnderflowException(); - } - state = State.PLAYING; - return gameDefinition.initGame(id, settings, players); - } - - private boolean hasEnoughPlayers() { - return players.size() >= gameDefinition.getMinPlayers(); - } - - public void reorderPlayers(List orderedUsernames) { - List formerList = new ArrayList<>(players); - players.clear(); - for (int i = 0; i < orderedUsernames.size(); i++) { - Player player = getPlayer(formerList, orderedUsernames.get(i)); - players.add(player); - player.setIndex(i); - } - } - - private static Player getPlayer(List players, String username) { - return players.stream() - .filter(p -> p.getUsername().equals(username)) - .findAny() - .orElseThrow(() -> new UnknownPlayerException(username)); - } - - public boolean isOwner(String username) { - return owner.getUsername().equals(username); - } - - public boolean containsUser(String username) { - return players.stream().anyMatch(p -> p.getUsername().equals(username)); - } - - static class GameAlreadyStartedException extends IllegalStateException { - } - - static class PlayerOverflowException extends IllegalStateException { - } - - static class PlayerUnderflowException extends IllegalStateException { - } - - static class PlayerNameAlreadyUsedException extends RuntimeException { - PlayerNameAlreadyUsedException(String name) { - super(name); - } - } - - static class UnknownPlayerException extends IllegalArgumentException { - UnknownPlayerException(String username) { - super(username); - } - } -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/Player.java b/backend/src/main/java/org/luxons/sevenwonders/game/Player.java deleted file mode 100644 index f1095049..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/game/Player.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.luxons.sevenwonders.game; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class Player { - - private final String username; - - private String displayName; - - private int index; - - private transient Lobby lobby; - - private transient Game game; - - public Player(String username, String displayName) { - this.username = username; - this.displayName = displayName; - } - - public String getUsername() { - return username; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @JsonIgnore - public Lobby getLobby() { - return lobby; - } - - public void setLobby(Lobby lobby) { - this.lobby = lobby; - } - - @JsonIgnore - public Game getGame() { - return game; - } - - public void setGame(Game game) { - this.game = game; - } -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/State.java b/backend/src/main/java/org/luxons/sevenwonders/game/State.java deleted file mode 100644 index 0bd71d3a..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/game/State.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.luxons.sevenwonders.game; - -public enum State { - LOBBY, - PLAYING -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java b/backend/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java index 14d4a9e8..c4cea17f 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java +++ b/backend/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java @@ -2,11 +2,9 @@ package org.luxons.sevenwonders.game.api; import java.util.List; -import org.luxons.sevenwonders.game.Player; - public class PlayerTurnInfo { - private final Player player; + private final int playerIndex; private final Table table; @@ -18,13 +16,13 @@ public class PlayerTurnInfo { private String message; - public PlayerTurnInfo(Player player, Table table) { - this.player = player; + public PlayerTurnInfo(int playerIndex, Table table) { + this.playerIndex = playerIndex; this.table = table; } - public Player getPlayer() { - return player; + public int getPlayerIndex() { + return playerIndex; } public Table getTable() { diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/api/PreparedCard.java b/backend/src/main/java/org/luxons/sevenwonders/game/api/PreparedCard.java deleted file mode 100644 index 85cac1de..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/game/api/PreparedCard.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.luxons.sevenwonders.game.api; - -import org.luxons.sevenwonders.game.Player; -import org.luxons.sevenwonders.game.cards.CardBack; - -public class PreparedCard { - - private final Player player; - - private final CardBack cardBack; - - public PreparedCard(Player player, CardBack cardBack) { - this.player = player; - this.cardBack = cardBack; - } - - public Player getPlayer() { - return player; - } - - public CardBack getCardBack() { - return cardBack; - } -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/boards/Board.java b/backend/src/main/java/org/luxons/sevenwonders/game/boards/Board.java index 0d85ac51..16f5cf5a 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/game/boards/Board.java +++ b/backend/src/main/java/org/luxons/sevenwonders/game/boards/Board.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.luxons.sevenwonders.game.Player; import org.luxons.sevenwonders.game.Settings; import org.luxons.sevenwonders.game.api.Table; import org.luxons.sevenwonders.game.cards.Card; @@ -23,7 +22,7 @@ public class Board { private final Wonder wonder; - private final Player player; + private final int playerIndex; private final List playedCards = new ArrayList<>(); @@ -47,9 +46,9 @@ public class Board { private int pointsPer3Gold; - public Board(Wonder wonder, Player player, Settings settings) { + public Board(Wonder wonder, int playerIndex, Settings settings) { this.wonder = wonder; - this.player = player; + this.playerIndex = playerIndex; this.gold = settings.getInitialGold(); this.tradingRules = new TradingRules(settings.getDefaultTradingCost()); this.military = new Military(settings.getLostPointsPerDefeat(), settings.getWonPointsPerVictoryPerAge()); @@ -62,10 +61,6 @@ public class Board { return wonder; } - public Player getPlayer() { - return player; - } - public List getPlayedCards() { return playedCards; } @@ -149,13 +144,13 @@ public class Board { } public PlayerScore computePoints(Table table) { - PlayerScore score = new PlayerScore(player, gold); + PlayerScore score = new PlayerScore(gold); score.put(ScoreCategory.CIVIL, computePointsForCards(table, Color.BLUE)); score.put(ScoreCategory.MILITARY, military.getTotalPoints()); score.put(ScoreCategory.SCIENCE, science.computePoints()); score.put(ScoreCategory.TRADE, computePointsForCards(table, Color.YELLOW)); score.put(ScoreCategory.GUILD, computePointsForCards(table, Color.PURPLE)); - score.put(ScoreCategory.WONDER, wonder.computePoints(table, player.getIndex())); + score.put(ScoreCategory.WONDER, wonder.computePoints(table, playerIndex)); score.put(ScoreCategory.GOLD, computeGoldPoints()); return score; } @@ -164,7 +159,7 @@ public class Board { return playedCards.stream() .filter(c -> c.getColor() == color) .flatMap(c -> c.getEffects().stream()) - .mapToInt(e -> e.computePoints(table, player.getIndex())) + .mapToInt(e -> e.computePoints(table, playerIndex)) .sum(); } diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java b/backend/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java index 4c63718b..7604ca6a 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java +++ b/backend/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java @@ -6,7 +6,6 @@ import java.util.Collections; import java.util.List; import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Player; import org.luxons.sevenwonders.game.Settings; import org.luxons.sevenwonders.game.api.CustomizableSettings; import org.luxons.sevenwonders.game.boards.Board; @@ -44,23 +43,22 @@ public class GameDefinition { return MAX_PLAYERS; } - public Game initGame(long id, CustomizableSettings customSettings, List orderedPlayers) { - Settings settings = new Settings(orderedPlayers.size(), customSettings); - List boards = assignBoards(settings, orderedPlayers); + public Game initGame(long id, CustomizableSettings customSettings, int nbPlayers) { + Settings settings = new Settings(nbPlayers, customSettings); + List boards = assignBoards(settings, nbPlayers); Decks decks = decksDefinition.create(settings); - return new Game(id, settings, orderedPlayers, boards, decks); + return new Game(id, settings, nbPlayers, boards, decks); } - private List assignBoards(Settings settings, List orderedPlayers) { + private List assignBoards(Settings settings, int nbPlayers) { List randomizedWonders = Arrays.asList(wonders); Collections.shuffle(randomizedWonders, settings.getRandom()); - List boards = new ArrayList<>(orderedPlayers.size()); - for (int i = 0; i < orderedPlayers.size(); i++) { - Player player = orderedPlayers.get(i); + List boards = new ArrayList<>(nbPlayers); + for (int i = 0; i < nbPlayers; i++) { WonderDefinition def = randomizedWonders.get(i); Wonder w = def.create(settings); - Board b = new Board(w, player, settings); + Board b = new Board(w, i, settings); boards.add(b); } return boards; diff --git a/backend/src/main/java/org/luxons/sevenwonders/game/scoring/PlayerScore.java b/backend/src/main/java/org/luxons/sevenwonders/game/scoring/PlayerScore.java index 42acec54..f67924e1 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/game/scoring/PlayerScore.java +++ b/backend/src/main/java/org/luxons/sevenwonders/game/scoring/PlayerScore.java @@ -2,18 +2,13 @@ package org.luxons.sevenwonders.game.scoring; import java.util.HashMap; -import org.luxons.sevenwonders.game.Player; - public class PlayerScore extends HashMap { - private final Player player; - private final int boardGold; private int totalPoints = 0; - public PlayerScore(Player player, int boardGold) { - this.player = player; + public PlayerScore(int boardGold) { this.boardGold = boardGold; } diff --git a/backend/src/main/java/org/luxons/sevenwonders/lobby/Lobby.java b/backend/src/main/java/org/luxons/sevenwonders/lobby/Lobby.java new file mode 100644 index 00000000..60637099 --- /dev/null +++ b/backend/src/main/java/org/luxons/sevenwonders/lobby/Lobby.java @@ -0,0 +1,143 @@ +package org.luxons.sevenwonders.lobby; + +import java.util.ArrayList; +import java.util.List; + +import org.luxons.sevenwonders.game.Game; +import org.luxons.sevenwonders.game.api.CustomizableSettings; +import org.luxons.sevenwonders.game.data.GameDefinition; + +public class Lobby { + + private final long id; + + private final String name; + + private final Player owner; + + private final GameDefinition gameDefinition; + + private final List players; + + private CustomizableSettings settings; + + private State state = State.LOBBY; + + public Lobby(long id, String name, Player owner, GameDefinition gameDefinition) { + this.id = id; + this.name = name; + this.owner = owner; + this.gameDefinition = gameDefinition; + this.players = new ArrayList<>(gameDefinition.getMinPlayers()); + this.settings = new CustomizableSettings(); + players.add(owner); + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getPlayers() { + return players; + } + + public CustomizableSettings getSettings() { + return settings; + } + + public void setSettings(CustomizableSettings settings) { + this.settings = settings; + } + + public State getState() { + return state; + } + + public synchronized void addPlayer(Player player) throws GameAlreadyStartedException, PlayerOverflowException { + if (hasStarted()) { + throw new GameAlreadyStartedException(); + } + if (maxPlayersReached()) { + throw new PlayerOverflowException(); + } + if (playerNameAlreadyUsed(player.getDisplayName())) { + throw new PlayerNameAlreadyUsedException(player.getDisplayName()); + } + player.setIndex(players.size()); + players.add(player); + } + + private boolean hasStarted() { + return state != State.LOBBY; + } + + private boolean maxPlayersReached() { + return players.size() >= gameDefinition.getMaxPlayers(); + } + + private boolean playerNameAlreadyUsed(String name) { + return players.stream().anyMatch(p -> p.getDisplayName().equals(name)); + } + + public synchronized Game startGame() throws PlayerUnderflowException { + if (!hasEnoughPlayers()) { + throw new PlayerUnderflowException(); + } + state = State.PLAYING; + return gameDefinition.initGame(id, settings, players.size()); + } + + private boolean hasEnoughPlayers() { + return players.size() >= gameDefinition.getMinPlayers(); + } + + public void reorderPlayers(List orderedUsernames) { + List formerList = new ArrayList<>(players); + players.clear(); + for (int i = 0; i < orderedUsernames.size(); i++) { + Player player = getPlayer(formerList, orderedUsernames.get(i)); + players.add(player); + player.setIndex(i); + } + } + + private static Player getPlayer(List players, String username) { + return players.stream() + .filter(p -> p.getUsername().equals(username)) + .findAny() + .orElseThrow(() -> new UnknownPlayerException(username)); + } + + public boolean isOwner(String username) { + return owner.getUsername().equals(username); + } + + public boolean containsUser(String username) { + return players.stream().anyMatch(p -> p.getUsername().equals(username)); + } + + static class GameAlreadyStartedException extends IllegalStateException { + } + + static class PlayerOverflowException extends IllegalStateException { + } + + static class PlayerUnderflowException extends IllegalStateException { + } + + static class PlayerNameAlreadyUsedException extends RuntimeException { + PlayerNameAlreadyUsedException(String name) { + super(name); + } + } + + static class UnknownPlayerException extends IllegalArgumentException { + UnknownPlayerException(String username) { + super(username); + } + } +} diff --git a/backend/src/main/java/org/luxons/sevenwonders/lobby/Player.java b/backend/src/main/java/org/luxons/sevenwonders/lobby/Player.java new file mode 100644 index 00000000..6698c476 --- /dev/null +++ b/backend/src/main/java/org/luxons/sevenwonders/lobby/Player.java @@ -0,0 +1,60 @@ +package org.luxons.sevenwonders.lobby; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.luxons.sevenwonders.game.Game; + +public class Player { + + private final String username; + + private String displayName; + + private int index; + + private transient Lobby lobby; + + private transient Game game; + + public Player(String username, String displayName) { + this.username = username; + this.displayName = displayName; + } + + public String getUsername() { + return username; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + @JsonIgnore + public Lobby getLobby() { + return lobby; + } + + public void setLobby(Lobby lobby) { + this.lobby = lobby; + } + + @JsonIgnore + public Game getGame() { + return game; + } + + public void setGame(Game game) { + this.game = game; + } +} diff --git a/backend/src/main/java/org/luxons/sevenwonders/lobby/State.java b/backend/src/main/java/org/luxons/sevenwonders/lobby/State.java new file mode 100644 index 00000000..17f3b101 --- /dev/null +++ b/backend/src/main/java/org/luxons/sevenwonders/lobby/State.java @@ -0,0 +1,6 @@ +package org.luxons.sevenwonders.lobby; + +public enum State { + LOBBY, + PLAYING +} diff --git a/backend/src/main/java/org/luxons/sevenwonders/output/PreparedCard.java b/backend/src/main/java/org/luxons/sevenwonders/output/PreparedCard.java new file mode 100644 index 00000000..ac696890 --- /dev/null +++ b/backend/src/main/java/org/luxons/sevenwonders/output/PreparedCard.java @@ -0,0 +1,24 @@ +package org.luxons.sevenwonders.output; + +import org.luxons.sevenwonders.lobby.Player; +import org.luxons.sevenwonders.game.cards.CardBack; + +public class PreparedCard { + + private final Player player; + + private final CardBack cardBack; + + public PreparedCard(Player player, CardBack cardBack) { + this.player = player; + this.cardBack = cardBack; + } + + public Player getPlayer() { + return player; + } + + public CardBack getCardBack() { + return cardBack; + } +} diff --git a/backend/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java b/backend/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java deleted file mode 100644 index efe39b85..00000000 --- a/backend/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.luxons.sevenwonders.repositories; - -import java.util.HashMap; -import java.util.Map; - -import org.luxons.sevenwonders.errors.ApiMisuseException; -import org.luxons.sevenwonders.game.Game; -import org.springframework.stereotype.Repository; - -@Repository -public class GameRepository { - - private Map games = new HashMap<>(); - - public void add(Game game) throws GameAlreadyExistsException { - if (games.containsKey(game.getId())) { - throw new GameAlreadyExistsException(game.getId()); - } - games.put(game.getId(), game); - } - - public Game find(long gameId) throws GameNotFoundException { - Game game = games.get(gameId); - if (game == null) { - throw new GameNotFoundException(gameId); - } - return game; - } - - public Game remove(long gameId) throws GameNotFoundException { - Game game = games.remove(gameId); - if (game == null) { - throw new GameNotFoundException(gameId); - } - return game; - } - - public static class GameNotFoundException extends ApiMisuseException { - GameNotFoundException(long id) { - super("Game " + id + " doesn't exist"); - } - } - - static class GameAlreadyExistsException extends ApiMisuseException { - GameAlreadyExistsException(long id) { - super("Game " + id + " already exists"); - } - } -} diff --git a/backend/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java b/backend/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java index 8f305791..0a7b9238 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java +++ b/backend/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java @@ -4,8 +4,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; -import org.luxons.sevenwonders.game.Lobby; -import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.lobby.Lobby; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.game.data.GameDefinitionLoader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; diff --git a/backend/src/main/java/org/luxons/sevenwonders/repositories/PlayerRepository.java b/backend/src/main/java/org/luxons/sevenwonders/repositories/PlayerRepository.java index 049c5ef9..541393e1 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/repositories/PlayerRepository.java +++ b/backend/src/main/java/org/luxons/sevenwonders/repositories/PlayerRepository.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; import org.luxons.sevenwonders.errors.ApiMisuseException; -import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.lobby.Player; import org.springframework.stereotype.Repository; @Repository diff --git a/backend/src/main/java/org/luxons/sevenwonders/validation/DestinationAccessValidator.java b/backend/src/main/java/org/luxons/sevenwonders/validation/DestinationAccessValidator.java index 65b3623c..cd17b0a5 100644 --- a/backend/src/main/java/org/luxons/sevenwonders/validation/DestinationAccessValidator.java +++ b/backend/src/main/java/org/luxons/sevenwonders/validation/DestinationAccessValidator.java @@ -3,9 +3,7 @@ package org.luxons.sevenwonders.validation; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Lobby; -import org.luxons.sevenwonders.repositories.GameRepository; +import org.luxons.sevenwonders.lobby.Lobby; import org.luxons.sevenwonders.repositories.LobbyRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -19,12 +17,9 @@ public class DestinationAccessValidator { private final LobbyRepository lobbyRepository; - private final GameRepository gameRepository; - @Autowired - public DestinationAccessValidator(LobbyRepository lobbyRepository, GameRepository gameRepository) { + public DestinationAccessValidator(LobbyRepository lobbyRepository) { this.lobbyRepository = lobbyRepository; - this.gameRepository = gameRepository; } public boolean hasAccess(String username, String destination) { @@ -47,7 +42,7 @@ public class DestinationAccessValidator { return false; // no game reference is always OK } int gameId = extractId(gameMatcher); - return !isUserInGame(username, gameId); + return !isUserInLobby(username, gameId); } private boolean hasForbiddenLobbyReference(String username, String destination) { @@ -59,11 +54,6 @@ public class DestinationAccessValidator { return !isUserInLobby(username, lobbyId); } - private boolean isUserInGame(String username, int gameId) { - Game game = gameRepository.find(gameId); - return game.containsUser(username); - } - private boolean isUserInLobby(String username, int lobbyId) { Lobby lobby = lobbyRepository.find(lobbyId); return lobby.containsUser(username); diff --git a/backend/src/test/java/org/luxons/sevenwonders/game/LobbyTest.java b/backend/src/test/java/org/luxons/sevenwonders/game/LobbyTest.java deleted file mode 100644 index b959ed96..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/game/LobbyTest.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.luxons.sevenwonders.game; - -import java.util.Arrays; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.luxons.sevenwonders.game.Lobby.GameAlreadyStartedException; -import org.luxons.sevenwonders.game.Lobby.PlayerNameAlreadyUsedException; -import org.luxons.sevenwonders.game.Lobby.PlayerOverflowException; -import org.luxons.sevenwonders.game.Lobby.PlayerUnderflowException; -import org.luxons.sevenwonders.game.Lobby.UnknownPlayerException; -import org.luxons.sevenwonders.game.data.GameDefinition; -import org.luxons.sevenwonders.game.data.GameDefinitionLoader; - -import static org.junit.Assert.*; -import static org.junit.Assume.*; - -@RunWith(Theories.class) -public class LobbyTest { - - @DataPoints - public static int[] nbPlayers() { - return new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private static GameDefinition gameDefinition; - - private Player gameOwner; - - private Lobby lobby; - - @BeforeClass - public static void loadDefinition() { - gameDefinition = new GameDefinitionLoader().getGameDefinition(); - } - - @Before - public void setUp() { - gameOwner = new Player("gameowner", "Game owner"); - lobby = new Lobby(0, "Test Game", gameOwner, gameDefinition); - } - - @Test - public void testId() { - Lobby l = new Lobby(5, "Test Game", gameOwner, gameDefinition); - assertEquals(5, l.getId()); - } - - @Test - public void testName() { - Lobby l = new Lobby(5, "Test Game", gameOwner, gameDefinition); - assertEquals("Test Game", l.getName()); - } - - @Test - public void isOwner_falseWhenNull() { - assertFalse(lobby.isOwner(null)); - } - - @Test - public void isOwner_falseWhenEmptyString() { - assertFalse(lobby.isOwner("")); - } - - @Test - public void isOwner_falseWhenGarbageString() { - assertFalse(lobby.isOwner("this is garbage")); - } - - @Test - public void isOwner_trueWhenOwnerUsername() { - assertTrue(lobby.isOwner(gameOwner.getUsername())); - } - - @Test - public void isOwner_falseWhenOtherPlayerName() { - Player player = new Player("testuser", "Test User"); - lobby.addPlayer(player); - assertFalse(lobby.isOwner(player.getUsername())); - } - - @Test - public void addPlayer_success() { - Player player = new Player("testuser", "Test User"); - lobby.addPlayer(player); - assertTrue(lobby.containsUser("testuser")); - } - - @Test(expected = PlayerNameAlreadyUsedException.class) - public void addPlayer_failsOnSameName() { - Player player = new Player("testuser", "Test User"); - Player player2 = new Player("testuser2", "Test User"); - lobby.addPlayer(player); - lobby.addPlayer(player2); - } - - @Test(expected = PlayerOverflowException.class) - public void addPlayer_playerOverflowWhenTooMany() { - // the owner + the max number gives an overflow - addPlayers(gameDefinition.getMaxPlayers()); - } - - @Test(expected = GameAlreadyStartedException.class) - public void addPlayer_failWhenGameStarted() { - // total with owner is the minimum - addPlayers(gameDefinition.getMinPlayers() - 1); - lobby.startGame(); - lobby.addPlayer(new Player("soonerNextTime", "The Late Guy")); - } - - private void addPlayers(int nbPlayers) { - for (int i = 0; i < nbPlayers; i++) { - Player player = new Player("testuser" + i, "Test User " + i); - lobby.addPlayer(player); - } - } - - @Test - public void reorderPlayers_failsOnSameName() { - Player player1 = new Player("testuser1", "Test User 1"); - Player player2 = new Player("testuser2", "Test User 2"); - Player player3 = new Player("testuser3", "Test User 3"); - lobby.addPlayer(player1); - lobby.addPlayer(player2); - lobby.addPlayer(player3); - lobby.reorderPlayers(Arrays.asList("testuser3", "testuser1", "testuser2")); - assertEquals("testuser3", lobby.getPlayers().get(0).getUsername()); - assertEquals("testuser1", lobby.getPlayers().get(1).getUsername()); - assertEquals("testuser2", lobby.getPlayers().get(2).getUsername()); - } - - @Test(expected = UnknownPlayerException.class) - public void reorderPlayers_failsOnUnknownPlayer() { - Player player1 = new Player("testuser1", "Test User 1"); - Player player2 = new Player("testuser2", "Test User 2"); - Player player3 = new Player("testuser3", "Test User 3"); - lobby.addPlayer(player1); - lobby.addPlayer(player2); - lobby.addPlayer(player3); - lobby.reorderPlayers(Arrays.asList("testuser4", "testuser1", "testuser2")); - } - - @Theory - public void startGame_failsBelowMinPlayers(int nbPlayers) { - assumeTrue(nbPlayers < gameDefinition.getMinPlayers()); - thrown.expect(PlayerUnderflowException.class); - // there is already the owner - addPlayers(nbPlayers - 1); - lobby.startGame(); - } - - @Theory - public void startGame_succeedsAboveMinPlayers(int nbPlayers) { - assumeTrue(nbPlayers >= gameDefinition.getMinPlayers()); - assumeTrue(nbPlayers < gameDefinition.getMaxPlayers()); - // there is already the owner - addPlayers(nbPlayers - 1); - lobby.startGame(); - } - - @Test - public void startGame_switchesState() { - assertTrue(lobby.getState() == State.LOBBY); - // there is already the owner - addPlayers(gameDefinition.getMinPlayers() - 1); - lobby.startGame(); - assertTrue(lobby.getState() == State.PLAYING); - } -} \ No newline at end of file diff --git a/backend/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java b/backend/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java index 858a6e2c..1dbe7dc7 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java @@ -53,13 +53,13 @@ public class BoardTest { CustomizableSettings customSettings = TestUtils.createCustomizableSettings(); customSettings.setInitialGold(goldAmountInSettings); Settings settings = new Settings(5, customSettings); - Board board = new Board(TestUtils.createWonder(), null, settings); + Board board = new Board(TestUtils.createWonder(), 0, settings); assertEquals(goldAmountInSettings, board.getGold()); } @Theory public void initialProduction_containsInitialResource(ResourceType type) { - Board board = new Board(TestUtils.createWonder(type), null, new Settings(5)); + Board board = new Board(TestUtils.createWonder(type), 0, new Settings(5)); Resources resources = TestUtils.createResources(type); assertTrue(board.getProduction().contains(resources)); assertTrue(board.getPublicProduction().contains(resources)); @@ -70,7 +70,7 @@ public class BoardTest { @FromDataPoints("gold") int goldRemoved) { assumeTrue(goldRemoved >= 0); assumeTrue(initialGold >= goldRemoved); - Board board = new Board(TestUtils.createWonder(), null, new Settings(5)); + Board board = new Board(TestUtils.createWonder(), 0, new Settings(5)); board.setGold(initialGold); board.removeGold(goldRemoved); assertEquals(initialGold - goldRemoved, board.getGold()); @@ -82,7 +82,7 @@ public class BoardTest { assumeTrue(goldRemoved >= 0); assumeTrue(initialGold < goldRemoved); thrown.expect(InsufficientFundsException.class); - Board board = new Board(TestUtils.createWonder(), null, new Settings(5)); + Board board = new Board(TestUtils.createWonder(), 0, new Settings(5)); board.setGold(initialGold); board.removeGold(goldRemoved); } @@ -90,7 +90,7 @@ public class BoardTest { @Theory public void getNbCardsOfColor_properCount_singleColor(ResourceType type, @FromDataPoints("nbCards") int nbCards, @FromDataPoints("nbCards") int nbOtherCards, Color color) { - Board board = new Board(TestUtils.createWonder(type), null, new Settings(5)); + Board board = new Board(TestUtils.createWonder(type), 0, new Settings(5)); TestUtils.addCards(board, nbCards, nbOtherCards, color); assertEquals(nbCards, board.getNbCardsOfColor(Collections.singletonList(color))); } @@ -99,7 +99,7 @@ public class BoardTest { public void getNbCardsOfColor_properCount_multiColors(ResourceType type, @FromDataPoints("nbCards") int nbCards1, @FromDataPoints("nbCards") int nbCards2, @FromDataPoints("nbCards") int nbOtherCards, Color color1, Color color2) { - Board board = new Board(TestUtils.createWonder(type), null, new Settings(5)); + Board board = new Board(TestUtils.createWonder(type), 0, new Settings(5)); TestUtils.addCards(board, nbCards1, color1); TestUtils.addCards(board, nbCards2, color2); TestUtils.addCards(board, nbOtherCards, TestUtils.getDifferentColorFrom(color1, color2)); diff --git a/backend/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java b/backend/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java index 4a481442..0d40bc9a 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java @@ -25,12 +25,12 @@ public class CardTest { @Before public void initBoard() { - Settings settings = new Settings(5); + Settings settings = new Settings(3); List boards = new ArrayList<>(3); - boards.add(new Board(new Wonder("TestWonder", ResourceType.WOOD), null, settings)); - boards.add(new Board(new Wonder("TestWonder", ResourceType.STONE), null, settings)); - boards.add(new Board(new Wonder("TestWonder", ResourceType.PAPYRUS), null, settings)); + boards.add(new Board(new Wonder("TestWonder", ResourceType.WOOD), 0, settings)); + boards.add(new Board(new Wonder("TestWonder", ResourceType.STONE), 1, settings)); + boards.add(new Board(new Wonder("TestWonder", ResourceType.PAPYRUS), 2, settings)); table = new Table(boards); Requirements treeFarmRequirements = new Requirements(); diff --git a/backend/src/test/java/org/luxons/sevenwonders/game/data/GameDefinitionTest.java b/backend/src/test/java/org/luxons/sevenwonders/game/data/GameDefinitionTest.java index 5acc09df..a5b37edd 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/game/data/GameDefinitionTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/game/data/GameDefinitionTest.java @@ -1,15 +1,10 @@ package org.luxons.sevenwonders.game.data; -import java.util.List; - import org.junit.Test; import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Player; -import org.luxons.sevenwonders.game.Settings; import org.luxons.sevenwonders.game.api.CustomizableSettings; -import org.luxons.sevenwonders.game.test.TestUtils; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; public class GameDefinitionTest { @@ -18,8 +13,7 @@ public class GameDefinitionTest { GameDefinition gameDefinition = new GameDefinitionLoader().getGameDefinition(); assertNotNull(gameDefinition); - List players = TestUtils.createPlayers(7); - Game game = gameDefinition.initGame(0, new CustomizableSettings(), players); + Game game = gameDefinition.initGame(0, new CustomizableSettings(), 7); assertNotNull(game); } } \ No newline at end of file diff --git a/backend/src/test/java/org/luxons/sevenwonders/game/test/TestUtils.java b/backend/src/test/java/org/luxons/sevenwonders/game/test/TestUtils.java index b8112779..a206cfb8 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/game/test/TestUtils.java +++ b/backend/src/test/java/org/luxons/sevenwonders/game/test/TestUtils.java @@ -3,12 +3,8 @@ package org.luxons.sevenwonders.game.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Player; import org.luxons.sevenwonders.game.Settings; import org.luxons.sevenwonders.game.api.CustomizableSettings; import org.luxons.sevenwonders.game.api.Table; @@ -17,7 +13,6 @@ import org.luxons.sevenwonders.game.boards.Science; import org.luxons.sevenwonders.game.boards.ScienceType; import org.luxons.sevenwonders.game.cards.Card; import org.luxons.sevenwonders.game.cards.Color; -import org.luxons.sevenwonders.game.cards.Decks; import org.luxons.sevenwonders.game.cards.Requirements; import org.luxons.sevenwonders.game.effects.Effect; import org.luxons.sevenwonders.game.effects.ScienceProgress; @@ -43,16 +38,6 @@ public class TestUtils { return new Settings(nbPlayers, createCustomizableSettings()); } - public static Game createGame(int id, int nbPlayers) { - Settings settings = createSettings(nbPlayers); - List players = TestUtils.createPlayers(nbPlayers); - List boards = TestUtils.createBoards(nbPlayers); - List cards = TestUtils.createSampleCards(0, nbPlayers * 7); - Map> cardsPerAge = new HashMap<>(); - cardsPerAge.put(1, cards); - return new Game(id, settings, players, boards, new Decks(cardsPerAge)); - } - public static Table createTable(int nbPlayers) { return new Table(createBoards(nbPlayers)); } @@ -66,26 +51,9 @@ public class TestUtils { return boards; } - public static List createPlayers(int count) { - List players = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - String username = "testUser" + i; - String displayName = "Test User " + i; - Player player = new Player(username, displayName); - player.setIndex(i); - players.add(player); - } - return players; - } - private static Board createBoard(Settings settings, ResourceType initialResource) { Wonder wonder = createWonder(initialResource); - - String username = "testUser" + initialResource.getSymbol(); - String displayName = "Test User " + initialResource.getSymbol(); - Player player = new Player(username, displayName); - - return new Board(wonder, player, settings); + return new Board(wonder, 0, settings); } public static Board createBoard(ResourceType initialResource) { diff --git a/backend/src/test/java/org/luxons/sevenwonders/lobby/LobbyTest.java b/backend/src/test/java/org/luxons/sevenwonders/lobby/LobbyTest.java new file mode 100644 index 00000000..adc37d3d --- /dev/null +++ b/backend/src/test/java/org/luxons/sevenwonders/lobby/LobbyTest.java @@ -0,0 +1,181 @@ +package org.luxons.sevenwonders.lobby; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.luxons.sevenwonders.game.data.GameDefinition; +import org.luxons.sevenwonders.game.data.GameDefinitionLoader; +import org.luxons.sevenwonders.lobby.Lobby.GameAlreadyStartedException; +import org.luxons.sevenwonders.lobby.Lobby.PlayerNameAlreadyUsedException; +import org.luxons.sevenwonders.lobby.Lobby.PlayerOverflowException; +import org.luxons.sevenwonders.lobby.Lobby.PlayerUnderflowException; +import org.luxons.sevenwonders.lobby.Lobby.UnknownPlayerException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +@RunWith(Theories.class) +public class LobbyTest { + + @DataPoints + public static int[] nbPlayers() { + return new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + } + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static GameDefinition gameDefinition; + + private Player gameOwner; + + private Lobby lobby; + + @BeforeClass + public static void loadDefinition() { + gameDefinition = new GameDefinitionLoader().getGameDefinition(); + } + + @Before + public void setUp() { + gameOwner = new Player("gameowner", "Game owner"); + lobby = new Lobby(0, "Test Game", gameOwner, gameDefinition); + } + + @Test + public void testId() { + Lobby l = new Lobby(5, "Test Game", gameOwner, gameDefinition); + assertEquals(5, l.getId()); + } + + @Test + public void testName() { + Lobby l = new Lobby(5, "Test Game", gameOwner, gameDefinition); + assertEquals("Test Game", l.getName()); + } + + @Test + public void isOwner_falseWhenNull() { + assertFalse(lobby.isOwner(null)); + } + + @Test + public void isOwner_falseWhenEmptyString() { + assertFalse(lobby.isOwner("")); + } + + @Test + public void isOwner_falseWhenGarbageString() { + assertFalse(lobby.isOwner("this is garbage")); + } + + @Test + public void isOwner_trueWhenOwnerUsername() { + assertTrue(lobby.isOwner(gameOwner.getUsername())); + } + + @Test + public void isOwner_falseWhenOtherPlayerName() { + Player player = new Player("testuser", "Test User"); + lobby.addPlayer(player); + assertFalse(lobby.isOwner(player.getUsername())); + } + + @Test + public void addPlayer_success() { + Player player = new Player("testuser", "Test User"); + lobby.addPlayer(player); + assertTrue(lobby.containsUser("testuser")); + } + + @Test(expected = PlayerNameAlreadyUsedException.class) + public void addPlayer_failsOnSameName() { + Player player = new Player("testuser", "Test User"); + Player player2 = new Player("testuser2", "Test User"); + lobby.addPlayer(player); + lobby.addPlayer(player2); + } + + @Test(expected = PlayerOverflowException.class) + public void addPlayer_playerOverflowWhenTooMany() { + // the owner + the max number gives an overflow + addPlayers(gameDefinition.getMaxPlayers()); + } + + @Test(expected = GameAlreadyStartedException.class) + public void addPlayer_failWhenGameStarted() { + // total with owner is the minimum + addPlayers(gameDefinition.getMinPlayers() - 1); + lobby.startGame(); + lobby.addPlayer(new Player("soonerNextTime", "The Late Guy")); + } + + private void addPlayers(int nbPlayers) { + for (int i = 0; i < nbPlayers; i++) { + Player player = new Player("testuser" + i, "Test User " + i); + lobby.addPlayer(player); + } + } + + @Test + public void reorderPlayers_failsOnSameName() { + Player player1 = new Player("testuser1", "Test User 1"); + Player player2 = new Player("testuser2", "Test User 2"); + Player player3 = new Player("testuser3", "Test User 3"); + lobby.addPlayer(player1); + lobby.addPlayer(player2); + lobby.addPlayer(player3); + lobby.reorderPlayers(Arrays.asList("testuser3", "testuser1", "testuser2")); + assertEquals("testuser3", lobby.getPlayers().get(0).getUsername()); + assertEquals("testuser1", lobby.getPlayers().get(1).getUsername()); + assertEquals("testuser2", lobby.getPlayers().get(2).getUsername()); + } + + @Test(expected = UnknownPlayerException.class) + public void reorderPlayers_failsOnUnknownPlayer() { + Player player1 = new Player("testuser1", "Test User 1"); + Player player2 = new Player("testuser2", "Test User 2"); + Player player3 = new Player("testuser3", "Test User 3"); + lobby.addPlayer(player1); + lobby.addPlayer(player2); + lobby.addPlayer(player3); + lobby.reorderPlayers(Arrays.asList("testuser4", "testuser1", "testuser2")); + } + + @Theory + public void startGame_failsBelowMinPlayers(int nbPlayers) { + assumeTrue(nbPlayers < gameDefinition.getMinPlayers()); + thrown.expect(PlayerUnderflowException.class); + // there is already the owner + addPlayers(nbPlayers - 1); + lobby.startGame(); + } + + @Theory + public void startGame_succeedsAboveMinPlayers(int nbPlayers) { + assumeTrue(nbPlayers >= gameDefinition.getMinPlayers()); + assumeTrue(nbPlayers < gameDefinition.getMaxPlayers()); + // there is already the owner + addPlayers(nbPlayers - 1); + lobby.startGame(); + } + + @Test + public void startGame_switchesState() { + assertTrue(lobby.getState() == State.LOBBY); + // there is already the owner + addPlayers(gameDefinition.getMinPlayers() - 1); + lobby.startGame(); + assertTrue(lobby.getState() == State.PLAYING); + } +} \ No newline at end of file diff --git a/backend/src/test/java/org/luxons/sevenwonders/repositories/GameRepositoryTest.java b/backend/src/test/java/org/luxons/sevenwonders/repositories/GameRepositoryTest.java deleted file mode 100644 index 5d7d558b..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/repositories/GameRepositoryTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.luxons.sevenwonders.repositories; - -import org.junit.Before; -import org.junit.Test; -import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.test.TestUtils; -import org.luxons.sevenwonders.repositories.GameRepository.GameAlreadyExistsException; -import org.luxons.sevenwonders.repositories.GameRepository.GameNotFoundException; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - -public class GameRepositoryTest { - - private GameRepository repository; - - @Before - public void setUp() { - repository = new GameRepository(); - } - - @Test(expected = GameAlreadyExistsException.class) - public void add_failsOnExistingId() { - Game game1 = TestUtils.createGame(0, 5); - repository.add(game1); - Game game2 = TestUtils.createGame(0, 7); - repository.add(game2); - } - - @Test(expected = GameNotFoundException.class) - public void find_failsOnUnknownId() { - repository.find(123); - } - - @Test - public void find_returnsTheSameObject() { - Game game = TestUtils.createGame(0, 5); - repository.add(game); - assertSame(game, repository.find(0)); - } - - @Test(expected = GameNotFoundException.class) - public void remove_failsOnUnknownId() { - repository.remove(123); - } - - @Test - public void remove_succeeds() { - Game game = TestUtils.createGame(0, 5); - repository.add(game); - assertNotNull(repository.find(0)); - repository.remove(0); - try { - repository.find(0); - fail(); // the call to find() should have failed - } catch (GameNotFoundException e) { - // the game has been properly removed - } - } -} \ No newline at end of file diff --git a/backend/src/test/java/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.java b/backend/src/test/java/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.java index f5a8d800..35618d49 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.java @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.repositories; import org.junit.Before; import org.junit.Test; -import org.luxons.sevenwonders.game.Lobby; -import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.lobby.Lobby; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.game.data.GameDefinitionLoader; import org.luxons.sevenwonders.repositories.LobbyRepository.LobbyNotFoundException; diff --git a/backend/src/test/java/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.java b/backend/src/test/java/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.java index d9e07b3f..8a6efe8c 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.java @@ -2,7 +2,7 @@ package org.luxons.sevenwonders.repositories; import org.junit.Before; import org.junit.Test; -import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.repositories.PlayerRepository.PlayerNotFoundException; import static org.junit.Assert.assertEquals; diff --git a/backend/src/test/java/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.java b/backend/src/test/java/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.java index 1a799ff3..8623ead8 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.java @@ -2,30 +2,25 @@ package org.luxons.sevenwonders.validation; import org.junit.Before; import org.junit.Test; -import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Lobby; -import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.lobby.Lobby; +import org.luxons.sevenwonders.lobby.Player; import org.luxons.sevenwonders.game.data.GameDefinitionLoader; -import org.luxons.sevenwonders.repositories.GameRepository; -import org.luxons.sevenwonders.repositories.GameRepository.GameNotFoundException; import org.luxons.sevenwonders.repositories.LobbyRepository; import org.luxons.sevenwonders.repositories.LobbyRepository.LobbyNotFoundException; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class DestinationAccessValidatorTest { private LobbyRepository lobbyRepository; - private GameRepository gameRepository; - private DestinationAccessValidator destinationAccessValidator; @Before public void setup() { - gameRepository = new GameRepository(); lobbyRepository = new LobbyRepository(new GameDefinitionLoader()); - destinationAccessValidator = new DestinationAccessValidator(lobbyRepository, gameRepository); + destinationAccessValidator = new DestinationAccessValidator(lobbyRepository); } private Lobby createLobby(String gameName, String ownerUsername, String... otherPlayers) { @@ -40,8 +35,7 @@ public class DestinationAccessValidatorTest { private void createGame(String gameName, String ownerUsername, String... otherPlayers) { Lobby lobby = createLobby(gameName, ownerUsername, otherPlayers); - Game game = lobby.startGame(); - gameRepository.add(game); + lobby.startGame(); } @Test @@ -81,7 +75,7 @@ public class DestinationAccessValidatorTest { destinationAccessValidator.hasAccess("", "/lobby/0"); } - @Test(expected = GameNotFoundException.class) + @Test(expected = LobbyNotFoundException.class) public void validate_failWhenNoGameExist() { destinationAccessValidator.hasAccess("", "/game/0"); } @@ -93,7 +87,7 @@ public class DestinationAccessValidatorTest { destinationAccessValidator.hasAccess("doesNotMatter", "/lobby/3"); } - @Test(expected = GameNotFoundException.class) + @Test(expected = LobbyNotFoundException.class) public void validate_failWhenReferencedGameDoesNotExist() { createGame("Test Game 1", "user1", "user2", "user3"); createGame("Test Game 2", "user4", "user5", "user6"); -- cgit