diff options
author | Joffrey BION <joffrey.bion@gmail.com> | 2016-12-15 01:28:53 +0100 |
---|---|---|
committer | Joffrey BION <joffrey.bion@gmail.com> | 2016-12-15 01:28:53 +0100 |
commit | 326baa18f341e40fbff2e8131b6a249c08c3a3c0 (patch) | |
tree | bfc03e44addae8f97d18304ef8c31711dd6715ea | |
parent | Improve card requirements management (diff) | |
download | seven-wonders-326baa18f341e40fbff2e8131b6a249c08c3a3c0.tar.gz seven-wonders-326baa18f341e40fbff2e8131b6a249c08c3a3c0.tar.bz2 seven-wonders-326baa18f341e40fbff2e8131b6a249c08c3a3c0.zip |
Add skeleton for game turns and card playing
In this commit, I also created a couple classes like HandCard, PlayerTurnInfo, and Table that are UI-oriented, and contain information relative to what one player should see or do.
10 files changed, 366 insertions, 30 deletions
diff --git a/src/main/java/org/luxons/sevenwonders/game/Decks.java b/src/main/java/org/luxons/sevenwonders/game/Decks.java index be811b6f..12fda17f 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Decks.java +++ b/src/main/java/org/luxons/sevenwonders/game/Decks.java @@ -17,6 +17,15 @@ public class Decks { this.cardsPerAge = cardsPerAge; } + Card getCard(String cardName) throws CardNotFoundException { + return cardsPerAge.values() + .stream() + .flatMap(List::stream) + .filter(c -> c.getName().equals(cardName)) + .findAny() + .orElseThrow(CardNotFoundException::new); + } + Map<Integer, List<Card>> deal(int age, int nbPlayers) { List<Card> deck = getDeck(age); validateNbCards(deck, nbPlayers); @@ -45,4 +54,7 @@ public class Decks { } return hands; } + + public class CardNotFoundException extends RuntimeException { + } } diff --git a/src/main/java/org/luxons/sevenwonders/game/Game.java b/src/main/java/org/luxons/sevenwonders/game/Game.java index d07bac93..f4dac7ef 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Game.java +++ b/src/main/java/org/luxons/sevenwonders/game/Game.java @@ -1,29 +1,113 @@ package org.luxons.sevenwonders.game; -import org.luxons.sevenwonders.game.boards.Board; - +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.luxons.sevenwonders.game.api.PlayerTurnInfo; +import org.luxons.sevenwonders.game.api.Table; +import org.luxons.sevenwonders.game.boards.Board; +import org.luxons.sevenwonders.game.cards.Card; public class Game { + private final long id; + private final Settings settings; - private final List<Board> boards; + private final Table table; private final Decks decks; - public Game(Settings settings, List<Board> boards, Decks decks) { + private final List<Card> discardedCards; + + private final Map<Integer, Move> preparedMoves; + + private Map<Integer, List<Card>> hands; + + private int currentAge = 0; + + public Game(long id, Settings settings, List<Player> players, List<Board> boards, Decks decks) { + this.id = id; this.settings = settings; - this.boards = boards; + this.table = new Table(players, boards); this.decks = decks; + this.discardedCards = new ArrayList<>(); + this.hands = new HashMap<>(); + this.preparedMoves = new HashMap<>(); + } + + public long getId() { + return id; + } + + public int startNewAge() { + currentAge++; + hands = decks.deal(currentAge, table.getNbPlayers()); + return currentAge; } - public List<Board> getBoards() { - return boards; + public List<PlayerTurnInfo> startTurn() { + return hands.entrySet() + .stream() + .map(e -> table.createPlayerTurnInfo(e.getKey(), e.getValue())) + .collect(Collectors.toList()); } - public Decks getDecks() { - return decks; + public void prepareCard(int playerIndex, Move move) throws InvalidMoveException { + validateMove(playerIndex, move); + preparedMoves.put(playerIndex, move); } + private void validateMove(int playerIndex, Move move) throws InvalidMoveException { + // TODO throw if invalid + } + + public boolean areAllPlayersReady() { + return preparedMoves.size() == table.getPlayers().size(); + } + + public void playTurn() { + // cards need to be all placed first as some effects depend on just-played cards + placePreparedCards(); + playPreparedCards(); + } + + private void placePreparedCards() { + preparedMoves.forEach((playerIndex, move) -> { + switch (move.getType()) { + case PLAY: + table.placeCard(playerIndex, decks.getCard(move.getCardName())); + break; + case UPGRADE_WONDER: + // TODO pre-upgrade the level of wonder without effect + break; + case DISCARD: + break; + } + }); + + } + + private void playPreparedCards() { + preparedMoves.forEach((playerIndex, move) -> { + switch (move.getType()) { + case PLAY: + table.playCard(playerIndex, decks.getCard(move.getCardName())); + break; + case UPGRADE_WONDER: + table.upgradeWonder(playerIndex); + break; + case DISCARD: + table.discard(playerIndex, settings.getDiscardedCardGold()); + break; + } + }); + + } + + public class InvalidMoveException extends RuntimeException { + } } diff --git a/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/src/main/java/org/luxons/sevenwonders/game/Lobby.java index a7c42665..24055c75 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Lobby.java +++ b/src/main/java/org/luxons/sevenwonders/game/Lobby.java @@ -1,10 +1,10 @@ package org.luxons.sevenwonders.game; -import org.luxons.sevenwonders.game.data.GameDefinition; - import java.util.ArrayList; import java.util.List; +import org.luxons.sevenwonders.game.data.GameDefinition; + public class Lobby { private final long id; @@ -15,9 +15,9 @@ public class Lobby { private State state = State.LOBBY; - public Lobby(long id, GameDefinition gameDefintion) { + public Lobby(long id, GameDefinition gameDefinition) { this.id = id; - this.gameDefinition = gameDefintion; + this.gameDefinition = gameDefinition; this.players = new ArrayList<>(3); } @@ -25,7 +25,7 @@ public class Lobby { return id; } - public synchronized int addPlayer(Player player) { + public synchronized int addPlayer(Player player) throws GameAlreadyStartedException, PlayerOverflowException { if (hasStarted()) { throw new GameAlreadyStartedException(); } @@ -41,17 +41,17 @@ public class Lobby { return state != State.LOBBY; } - public synchronized Game startGame(Settings settings) { + private boolean maxPlayersReached() { + return players.size() >= gameDefinition.getMaxPlayers(); + } + + public synchronized Game startGame(Settings settings) throws PlayerUnderflowException { if (!hasEnoughPlayers()) { throw new PlayerUnderflowException(); } state = State.PLAYING; settings.setNbPlayers(players.size()); - return gameDefinition.initGame(settings); - } - - private boolean maxPlayersReached() { - return players.size() >= gameDefinition.getMaxPlayers(); + return gameDefinition.initGame(id, settings, players); } private boolean hasEnoughPlayers() { diff --git a/src/main/java/org/luxons/sevenwonders/game/Move.java b/src/main/java/org/luxons/sevenwonders/game/Move.java new file mode 100644 index 00000000..6bb857f6 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/Move.java @@ -0,0 +1,39 @@ +package org.luxons.sevenwonders.game; + +import java.util.HashMap; +import java.util.Map; + +import org.luxons.sevenwonders.game.resources.Resources; + +public class Move { + + private String cardName; + + private MoveType moveType; + + private Map<Integer, Resources> boughtResources = new HashMap<>(); + + public String getCardName() { + return cardName; + } + + public void setCardName(String cardName) { + this.cardName = cardName; + } + + public MoveType getType() { + return moveType; + } + + public void setMoveType(MoveType moveType) { + this.moveType = moveType; + } + + public Map<Integer, Resources> getBoughtResources() { + return boughtResources; + } + + public void setBoughtResources(Map<Integer, Resources> boughtResources) { + this.boughtResources = boughtResources; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/MoveType.java b/src/main/java/org/luxons/sevenwonders/game/MoveType.java new file mode 100644 index 00000000..b24d673c --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/MoveType.java @@ -0,0 +1,5 @@ +package org.luxons.sevenwonders.game; + +public enum MoveType { + PLAY, UPGRADE_WONDER, DISCARD +} diff --git a/src/main/java/org/luxons/sevenwonders/game/Settings.java b/src/main/java/org/luxons/sevenwonders/game/Settings.java index b70caa71..e733b460 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Settings.java +++ b/src/main/java/org/luxons/sevenwonders/game/Settings.java @@ -10,6 +10,8 @@ public class Settings { private int initialGold = 3; + private int discardedCardGold = 3; + private int defaultTradingCost = 2; private WonderSide wonderSide = WonderSide.A; @@ -38,6 +40,14 @@ public class Settings { this.initialGold = initialGold; } + public int getDiscardedCardGold() { + return discardedCardGold; + } + + public void setDiscardedCardGold(int discardedCardGold) { + this.discardedCardGold = discardedCardGold; + } + public int getDefaultTradingCost() { return defaultTradingCost; } diff --git a/src/main/java/org/luxons/sevenwonders/game/api/HandCard.java b/src/main/java/org/luxons/sevenwonders/game/api/HandCard.java new file mode 100644 index 00000000..743a48db --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/api/HandCard.java @@ -0,0 +1,46 @@ +package org.luxons.sevenwonders.game.api; + +import org.luxons.sevenwonders.game.cards.Card; + +public class HandCard { + + private final Card data; + + private boolean chainable; + + private boolean free; + + private boolean playable; + + public HandCard(Card card) { + this.data = card; + } + + public Card getData() { + return data; + } + + public boolean isChainable() { + return chainable; + } + + public void setChainable(boolean chainable) { + this.chainable = chainable; + } + + public boolean isFree() { + return free; + } + + public void setFree(boolean free) { + this.free = free; + } + + public boolean isPlayable() { + return playable; + } + + public void setPlayable(boolean playable) { + this.playable = playable; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java new file mode 100644 index 00000000..ad9e6da9 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java @@ -0,0 +1,43 @@ +package org.luxons.sevenwonders.game.api; + +import java.util.List; + +public class PlayerTurnInfo { + + private final int playerIndex; + + private final Table table; + + private List<HandCard> hand; + + private String message; + + public PlayerTurnInfo(int playerIndex, Table table) { + this.playerIndex = playerIndex; + this.table = table; + } + + public int getPlayerIndex() { + return playerIndex; + } + + public Table getTable() { + return table; + } + + public List<HandCard> getHand() { + return hand; + } + + public void setHand(List<HandCard> hand) { + this.hand = hand; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/api/Table.java b/src/main/java/org/luxons/sevenwonders/game/api/Table.java new file mode 100644 index 00000000..7a2e20dc --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/api/Table.java @@ -0,0 +1,93 @@ +package org.luxons.sevenwonders.game.api; + +import java.util.List; +import java.util.stream.Collectors; + +import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.game.boards.Board; +import org.luxons.sevenwonders.game.cards.Card; + +/** + * The table contains what is visible by all the players in the game: the boards and their played cards, and the + * players' information. + */ +public class Table { + + private final int nbPlayers; + + private final List<Player> players; + + private final List<Board> boards; + + public Table(List<Player> players, List<Board> boards) { + this.nbPlayers = players.size(); + this.players = players; + this.boards = boards; + if (players.size() != boards.size()) { + throw new IllegalArgumentException( + String.format("There are %d boards for %d players, it doesn't make sense", boards.size(), + players.size())); + } + } + + public List<Player> getPlayers() { + return players; + } + + public List<Board> getBoards() { + return boards; + } + + public int getNbPlayers() { + return nbPlayers; + } + + public void placeCard(int playerIndex, Card card) { + Board board = boards.get(playerIndex); + board.addCard(card); + } + + public void upgradeWonder(int playerIndex) { + Board board = boards.get(playerIndex); + Board left = boards.get(wrapIndex(playerIndex - 1)); + Board right = boards.get(wrapIndex(playerIndex + 1)); + board.upgradeWonderLevel(left, right); + } + + public void playCard(int playerIndex, Card card) { + Board board = boards.get(playerIndex); + Board left = boards.get(wrapIndex(playerIndex - 1)); + Board right = boards.get(wrapIndex(playerIndex + 1)); + card.applyTo(board, left, right); + } + + public void discard(int playerIndex, int goldBonus) { + Board board = boards.get(playerIndex); + board.setGold(board.getGold() + goldBonus); + } + + private int wrapIndex(int index) { + return Math.floorMod(index, nbPlayers); + } + + public PlayerTurnInfo createPlayerTurnInfo(int playerIndex, List<Card> cards) { + PlayerTurnInfo pti = new PlayerTurnInfo(playerIndex, this); + pti.setHand(createHand(playerIndex, cards)); + return pti; + } + + private List<HandCard> createHand(int playerIndex, List<Card> cards) { + return cards.stream().map(c -> createHandCard(playerIndex, c)).collect(Collectors.toList()); + } + + private HandCard createHandCard(int playerIndex, Card card) { + Board board = boards.get(playerIndex); + Board left = boards.get(wrapIndex(playerIndex - 1)); + Board right = boards.get(wrapIndex(playerIndex + 1)); + HandCard handCard = new HandCard(card); + handCard.setChainable(card.isChainableOn(board)); + handCard.setFree(card.isAffordedBy(board) && card.getRequirements().getGold() == 0); + handCard.setPlayable(card.isPlayable(board, left, right)); + return handCard; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java b/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java index d2932cdf..801b7559 100644 --- a/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java +++ b/src/main/java/org/luxons/sevenwonders/game/data/GameDefinition.java @@ -1,18 +1,18 @@ package org.luxons.sevenwonders.game.data; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + import org.luxons.sevenwonders.game.Decks; import org.luxons.sevenwonders.game.Game; +import org.luxons.sevenwonders.game.Player; import org.luxons.sevenwonders.game.Settings; import org.luxons.sevenwonders.game.boards.Board; import org.luxons.sevenwonders.game.data.definitions.DecksDefinition; -import org.luxons.sevenwonders.game.data.definitions.Definition; import org.luxons.sevenwonders.game.data.definitions.WonderDefinition; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - public class GameDefinition { /** @@ -29,7 +29,7 @@ public class GameDefinition { private DecksDefinition decksDefinition; - public GameDefinition(WonderDefinition[] wonders, DecksDefinition decksDefinition) { + GameDefinition(WonderDefinition[] wonders, DecksDefinition decksDefinition) { this.wonders = wonders; this.decksDefinition = decksDefinition; } @@ -42,15 +42,19 @@ public class GameDefinition { return MAX_PLAYERS; } - public Game initGame(Settings settings) { + public Game initGame(long id, Settings settings, List<Player> players) { List<Board> boards = pickRandomBoards(settings); Decks decks = decksDefinition.create(settings); - return new Game(settings, boards, decks); + return new Game(id, settings, players, boards, decks); } private List<Board> pickRandomBoards(Settings settings) { List<WonderDefinition> randomizedWonders = Arrays.asList(wonders); Collections.shuffle(randomizedWonders, settings.getRandom()); - return Arrays.stream(wonders).map(def -> def.create(settings)).map(w -> new Board(w, settings)).collect(Collectors.toList()); + return Arrays.stream(wonders) + .map(def -> def.create(settings)) + .map(w -> new Board(w, settings)) + .limit(settings.getNbPlayers()) + .collect(Collectors.toList()); } } |