diff --git a/.classpath b/.classpath
index 653dfd75..d39d3b10 100644
--- a/.classpath
+++ b/.classpath
@@ -26,7 +26,7 @@
-
+
diff --git a/deliveries/UML/class_diagram.mmd b/deliveries/UML/class_diagram.mmd
index 4115ea89..b9edabc3 100644
--- a/deliveries/UML/class_diagram.mmd
+++ b/deliveries/UML/class_diagram.mmd
@@ -1,5 +1,5 @@
---
-title: Stati
+title: Model diagram
---
classDiagram
Match --> GameDeck
@@ -8,11 +8,11 @@ classDiagram
Match -- Player
MatchState <|-- WaitState
MatchState <|-- SetupState
- MatchState <|-- ChoosePlayerState
+ MatchState <|-- NextTurnState
MatchState <|-- ChooseSecretObjectiveState
- MatchState <|-- UpdatePlayerStatusState
- MatchState <|-- DrawPhaseState
- MatchState <|-- RankingsState
+ MatchState <|-- AfterMoveState
+ MatchState <|-- AfterDrawState
+ MatchState <|-- FinalState
Card <|-- InitialCard
Card <|-- PlayableCard
@@ -35,6 +35,7 @@ classDiagram
%%Side <-- Player
%%Side <-- Match
Side <-- PlacedCard
+ Corner <-- CardFace
%%Symbol <-- GoldCard
%% DrawSource <-- Player
@@ -54,24 +55,35 @@ classDiagram
CORNER_OBJ
}
+ class Corner {
+ <>
+ TOP_LEFT
+ TOP_RIGHT
+ BOTTOM_LEFT
+ BOTTOM_RIGHT
+ }
+
class CardFace {
+ <>
- topLeft: Symbol
- topRight: Symbol
- bottomLeft: Symbol
- bottomRight: Symbol
- center: Set~Symbol~
+ CardFace(Symbol topLeft, Symbol topRight, Symbol bottomLeft, Symbol bottomRight, Set~Symbol~ center)
+ + getCorner(Corner corner) Symbol
+ + getCenter() Set~Symbol~
}
class Card {
<>
- - front: CardFace
- - back: CardFace
+ # sides : Map~Side, CardFace~
+ + getSide(Side side) CardFace
}
class PlayableCard {
<>
- - points: int
+ # points: int
}
class InitialCard {
@@ -80,40 +92,46 @@ classDiagram
class ResourceCard {
+ ResourceCard(CardFace front, CardFace back, int points)
+ + getPoints() : int
}
class GoldCard {
- multiplier: Symbol
- req: QuantityRequirement
+ GoldCard(CardFace front, CardFace back, int points, Symbol multiplier, QuantityRequirement req)
- + totPoints(Board) int
+ + getMultiplier() Symbol
+ + getRequirement() QuantityRequirement
+ + totPoints(Board board) int
}
class Requirement {
<>
- + isSatisfied(Board bord) bool
+ + isSatisfied(Board board) bool
}
class QuantityRequirement {
- reqs : Map~Integer, Symbol~
+ QuantityRequirement(Symbol simbol, Integer quantity)
+ + isSatisfied(Board board) bool
}
class PositionRequirement {
- reqs: Map<Pair<Integer, Integer>, Color>
+ PositionRequirement(Map<Pair<Integer, Integer>, Color>)
+ + isSatisfied(Board board) bool
}
class Objective {
- points: int
- req: Requirement
+ Objective(int points, Requirement req)
+ + getPoints() int
+ + getRequirement() Requirement
}
class Player {
- nickname: String
- match: Match
- points: Int
- board: Board
- - resources: Map
- color: Color
- objective: Objective
@@ -122,6 +140,11 @@ classDiagram
+ drawCard(DrawSource draw) void
+ chooseObjective(Objective objective) void
+ getBoard() Board
+ + getPoints() int
+ + getSecretObjective() Objective
+ + getColor() Color
+ + getNickname() String
+ # setColor() void
}
class Color{
<>
@@ -138,18 +161,26 @@ classDiagram
class Board {
- currentHand: List~PlayableCard~
- placed: Map<Pair<Integer,Integer>, PlacedCard>
+ - availableResources: Map~Symbol, Integer~
+ Board()
+ getCurrentHand() List~PlayableCard~
- + addCardHand(PlayableCard card) void
- + removeCardHand(PlayableCard card) void
- + checkRequirement(Requirement req) bool
- + placeCard(Pair, Card card, Side side) Map~Symbols, Integer~
+ + getAvailableResources() Map~Symbol, Integer~
+ # getPlacedMap() Map<Pair<Integer,Integer>, PlacedCard>
+ # addHandCard(PlayableCard card) void
+ # removeHandCard(PlayableCard card) void
+ # setInitialSide(Side side) void
+ # placeCard(Pair~Integer, Integer~, PlayableCard card, Side side) int
+ # setInitialCard(InitialCard card) void
+ + verifyCardPlacement(Pair~Integer, Integer~ coords, Card card, Side side) bool
}
class PlacedCard {
+ <>
- card: Card
- turn: int
+ PlacedCard(Card card, int turn)
+ + getCard() Card
+ + getTurn() int
}
class Match {
@@ -157,25 +188,39 @@ classDiagram
- maxPlayers: int
- currState: MatchState
- currentPlayer: Player
+ - initialsDeck: GameDeck~InitialCard~
- resourcesDeck: GameDeck~ResourceCard~
- goldsDeck: GameDeck~GoldCard~
- objectivesDeck: GameDeck~Objective~
- - visibleGolds: Pair
- - visibleResources: Pair
- - visibleObjectives: Pair
+ - visibleGolds: Pair~GoldCard, GoldCard~
+ - visibleResources: Pair~ResourceCard, ResourceCard~
+ - visibleObjectives: Pair~Objective, Objective~
+ - currentProposedObjectives: Pair~Objective, Objective~
+ - started: bool
+ - lastTurn: bool
+ - finished: bool
- + Match(int maxPlayers) void
- + setState() void
+ + Match(int maxPlayers, resourceDeck ) void
+ isFull() bool
+ + isStarted() bool
+ isFinished() bool
+ addPlayer(Player player) void
+ removePlayer(Player player) void
+ getCurrentPlayer() Player
- + chooseSecretObjective(Objective obj) void
- + getSecretObjectives() Pair~Objective, Objective~
- + makeMove(Player player, Pair~Integer, Integer~ coords, PlayableCard card, Side side) void
- + drawCard(Player player, DrawSource draw) PlayableCard
- - setupMatch() void
+ + getPlayers() List~Player~
+ # getPoints() int
+ # addPoints() void
+ # chooseSecretObjective(Objective obj) void
+ # proposeSecretObjectives() Pair~Objective, Objective~
+ # makeMove(Pair~Integer, Integer~ coords, PlayableCard card, Side side) void
+ # drawCard(DrawSource draw) PlayableCard
+ # doStart() void
+ # doFinish() void
+ # setState() void
+ # setupDecks() void
+ # setupPlayers() void
+ # setupBoards() void
+ # nextPlayer() void
}
class DrawSource {
@@ -191,44 +236,54 @@ classDiagram
class MatchState {
<>
+ match: Match
+ + MatchState(Match match)
+ transition() void
- + join() void
- + quit() void
+ + addPlayer() void
+ + removePlayer() void
+ + proposeSecretObjectives() void
+ + chooseSecretObjective() void
+ + makeMove() void
+ + drawCard() void
+
}
class WaitState{
- + WaitState() void
+ + WaitState(Match match) void
+ transition() void
- + join() void
- + quit() void
+ + addPlayer() void
+ + removePlayer() void
}
class SetupState{
- + SetupState() void
+ + SetupState(Match match) void
+ transition() void
}
- class ChoosePlayerState {
- + ChoosePlayerState() void
+ class NextTurnState {
+ + NextTurnState(Match match) void
+ + proposeSecretObjectives() void
+ + makeMove() void
+ transition() void
}
class ChooseSecretObjectiveState {
+ ChooseSecretObjectiveState() void
+ + chooseSecretObjective() void
+ transition() void
}
- class UpdatePlayerStatusState {
- + UpdatePlayerStatusState() void
+ class AfterMoveState {
+ + AfterMoveState() void
+ + drawCard() void
+ transition() void
}
- class DrawPhaseState {
- + DrawPhaseState() void
+ class AfterDrawState {
+ + AfterDrawState() void
+ transition() void
}
- class RankingsState{
- + RankingsState() void
+ class FinalState{
+ + FinalState() void
+ transition() void
}
@@ -236,7 +291,7 @@ classDiagram
class GameDeck {
<>
- int size
- - cardList: List~U~
+ - cardsList: List~U~
+ GameDeck(int size)
+ add(U card) void
+ pop() U
diff --git a/deliveries/UML/model.pdf b/deliveries/UML/model.pdf
index 9afe0d48..a9db4c7d 100644
Binary files a/deliveries/UML/model.pdf and b/deliveries/UML/model.pdf differ
diff --git a/pom.xml b/pom.xml
index 9eecf715..56be2d75 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,8 @@
maven-javadoc-plugin3.6.3
+
+ 16
Plugin to execute project -->
@@ -87,5 +89,15 @@
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 16
+
+
+
diff --git a/src/main/java/it/polimi/ingsw/App.java b/src/main/java/it/polimi/ingsw/App.java
deleted file mode 100644
index e15eafa3..00000000
--- a/src/main/java/it/polimi/ingsw/App.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package it.polimi.ingsw;
-
-/**
- * Main Loop
- *
- */
-public class App
-{
- public static void main( String[] args )
- {
- String test = new String("Hello world!");
- System.out.println(test);
- }
-}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/AfterDrawState.java b/src/main/java/it/polimi/ingsw/gamemodel/AfterDrawState.java
new file mode 100644
index 00000000..d8289e45
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/AfterDrawState.java
@@ -0,0 +1,20 @@
+package it.polimi.ingsw.gamemodel;
+
+public class AfterDrawState extends MatchState {
+
+ public AfterDrawState(Match match) {
+ super(match);
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState;
+
+ if(match.isFinished())
+ nextState = new FinalState(match);
+ else
+ nextState = new NextTurnState(match);
+
+ match.setState(nextState);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/AfterMoveState.java b/src/main/java/it/polimi/ingsw/gamemodel/AfterMoveState.java
new file mode 100644
index 00000000..245790d6
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/AfterMoveState.java
@@ -0,0 +1,19 @@
+package it.polimi.ingsw.gamemodel;
+
+public class AfterMoveState extends MatchState {
+
+ public AfterMoveState(Match match) {
+ super(match);
+ }
+
+ @Override
+ public void drawCard() throws WrongStateException {
+ this.transition();
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState = new AfterDrawState(match);
+ match.setState(nextState);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Board.java b/src/main/java/it/polimi/ingsw/gamemodel/Board.java
new file mode 100644
index 00000000..667e102f
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Board.java
@@ -0,0 +1,81 @@
+package it.polimi.ingsw.gamemodel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import it.polimi.ingsw.utils.Pair;
+
+/**
+ * Board is the class that contains all the informations relative to a {@link Player}'s status
+ */
+public class Board {
+ private List currentHand;
+ private Map, PlacedCard> placed;
+ private Map availableResources;
+
+ /**
+ * Class constructor. No inputs taken as the board starts empty
+ */
+ public Board() {
+ currentHand = new ArrayList<>();
+ placed = new HashMap<>();
+ availableResources = new HashMap<>();
+ }
+
+ /**
+ * Getter for the hand of the player (which must be composed of three {@link PlayableCard}), which is visible
+ * to every player
+ */
+ public List getCurrentHand() {
+ return this.currentHand;
+ }
+
+ /**
+ * Adds a card to the player's hand (which is visible to every player)
+ * @param card the card to put in the hand
+ */
+ protected void addHandCard(PlayableCard card) {
+ currentHand.addLast(card);
+ }
+
+ /**
+ * The initial card will be added by {@link Match} at the start of the game, and it will be set on the front side by default.
+ * During the first turn of the player, he will be asked if he wants to switch side with this method
+ * @param side the desired side for the initial card
+ */
+ public void setInitialSide(Side side) {
+
+ }
+
+ /**
+ * Removes a card from the hand of the player
+ * @param card the card that must be removed from the player's hand
+ */
+ protected void removeHandCard(PlayableCard card) {
+ currentHand.remove(card);
+ }
+
+ /**
+ * This method will add to the board the given card (if requirements are met and the position is valid), and update the player's resources
+ * @param coord the x and y coordinates in which the card must be placed
+ * @param card the card to be placed
+ * @param side the side of the card to be placed
+ * @return the points gained from playing card
+ */
+ protected int placeCard(Pair coord, Card card, Side side) {
+ return 0;
+ }
+
+ /**
+ * Checks whether the given position is valid (ie there are no adjacent cards with an empty angle and there is at least one adjacent card),
+ * if the card is in the player's hand and if the card requirement is met
+ * @param coord the x and y coordinates to check
+ * @return whether the given coordinates are valid or not
+ */
+ public boolean verifyCardPlacement(Pair coord, Card card, Side side) {
+ return true;
+ }
+
+}
+
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Card.java b/src/main/java/it/polimi/ingsw/gamemodel/Card.java
new file mode 100644
index 00000000..c7968527
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Card.java
@@ -0,0 +1,27 @@
+package it.polimi.ingsw.gamemodel;
+
+/*
+* Highest abstraction of the card object, with common aspects for every card in the game (except objectives).
+*/
+public abstract class Card {
+ protected CardFace front;
+ protected CardFace back;
+
+ /**
+ * @param side the desired side
+ * @return the structure of the specified side
+ * @see CardFace
+ */
+ public CardFace getSide(Side side) {
+ switch (side) {
+ case FRONT:
+ return this.front;
+
+ case BACK:
+ return this.back;
+
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/CardFace.java b/src/main/java/it/polimi/ingsw/gamemodel/CardFace.java
new file mode 100644
index 00000000..92b0ad5c
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/CardFace.java
@@ -0,0 +1,38 @@
+package it.polimi.ingsw.gamemodel;
+
+import java.util.Set;
+
+/*
+* Topological definition of a card's side
+*/
+public class CardFace {
+ private Symbol topLeft;
+ private Symbol topRight;
+ private Symbol bottomLeft;
+ private Symbol bottomRight;
+ private Set center;
+
+ public CardFace(Symbol topLeft, Symbol topRight, Symbol bottomLeft, Symbol bottomRight, Set center) {
+ this.topLeft = topLeft;
+ this.topRight = topRight;
+ this.bottomLeft = bottomLeft;
+ this.bottomRight = bottomRight;
+ this.center = center;
+ }
+
+ /**
+ * Used to get the symbol present in one of the four corners of a card
+ * @param corner which of the four corners we want
+ * @return the symbol the specified corner contains
+ */
+ public Symbol getCorner(Corner corner) {
+ return topLeft;
+ }
+
+ /**
+ * @return the set containing all symbols the center of the card contains
+ */
+ public Set getCenter() {
+ return center;
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/ChooseInitialSideState.java b/src/main/java/it/polimi/ingsw/gamemodel/ChooseInitialSideState.java
new file mode 100644
index 00000000..2c453cb9
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/ChooseInitialSideState.java
@@ -0,0 +1,5 @@
+package it.polimi.ingsw.gamemodel;
+
+public class ChooseInitialSideState {
+
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/ChooseSecretObjectiveState.java b/src/main/java/it/polimi/ingsw/gamemodel/ChooseSecretObjectiveState.java
new file mode 100644
index 00000000..0699042d
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/ChooseSecretObjectiveState.java
@@ -0,0 +1,24 @@
+package it.polimi.ingsw.gamemodel;
+
+public class ChooseSecretObjectiveState extends MatchState {
+
+ public ChooseSecretObjectiveState(Match match) {
+ super(match);
+ }
+
+ @Override
+ public void chooseSecretObjectives() {
+ Player lastPlayer = match.getPlayers().getLast();
+
+ if (match.getCurrentPlayer().equals(lastPlayer))
+ match.doStart();
+
+ this.transition();
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState = new NextTurnState(match);
+ match.setState(nextState);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Color.java b/src/main/java/it/polimi/ingsw/gamemodel/Color.java
new file mode 100644
index 00000000..471a1123
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Color.java
@@ -0,0 +1,9 @@
+package it.polimi.ingsw.gamemodel;
+
+
+public enum Color {
+ RED,
+ BLUE,
+ GREEN,
+ YELLOW
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Corner.java b/src/main/java/it/polimi/ingsw/gamemodel/Corner.java
new file mode 100644
index 00000000..48cc4437
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Corner.java
@@ -0,0 +1,11 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* All the corners of a card, which can contain a {@link Symbol}
+*/
+public enum Corner {
+ TOP_LEFT,
+ TOP_RIGHT,
+ BOTTOM_LEFT,
+ BOTTOM_RIGHT
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/DrawSource.java b/src/main/java/it/polimi/ingsw/gamemodel/DrawSource.java
new file mode 100644
index 00000000..37859df2
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/DrawSource.java
@@ -0,0 +1,13 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* All the sources a player can draw from: the decks and the four visible cards
+*/
+public enum DrawSource {
+ GOLDS_DECK,
+ RESOURCES_DECK,
+ FIRST_VISIBLE_GOLDS,
+ SECOND_VISIBLE_GOLDS,
+ FIRST_VISIBLE_RESOURCES,
+ SECOND_VISIBLE_RESOURCES
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/FinalState.java b/src/main/java/it/polimi/ingsw/gamemodel/FinalState.java
new file mode 100644
index 00000000..1eb8bc1b
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/FinalState.java
@@ -0,0 +1,13 @@
+package it.polimi.ingsw.gamemodel;
+
+public class FinalState extends MatchState {
+
+ public FinalState(Match match) {
+ super(match);
+ }
+
+ @Override
+ public void transition() {
+ System.err.println("ERROR: State transition tried in the final state!");
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/GameDeck.java b/src/main/java/it/polimi/ingsw/gamemodel/GameDeck.java
new file mode 100644
index 00000000..7b22a295
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/GameDeck.java
@@ -0,0 +1,37 @@
+package it.polimi.ingsw.gamemodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+* Generic used to create the decks for all the types of cards
+*/
+public class GameDeck {
+ private int size;
+ private List cardsList;
+
+ /**
+ * Constructor of the class, which will initialize the deck empty
+ * @param size initial size of the deck
+ */
+ public GameDeck(int size) {
+ this.size = size;
+ cardsList = new ArrayList<>();
+ }
+
+ public void add(T card) {
+
+ }
+
+ public T pop() {
+ return null;
+ }
+
+ public void shuffle() {
+
+ }
+
+ public void isEmpty() {
+
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/GoldCard.java b/src/main/java/it/polimi/ingsw/gamemodel/GoldCard.java
new file mode 100644
index 00000000..cdf89e71
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/GoldCard.java
@@ -0,0 +1,35 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* The front side of these cards always gives points, but needs a certain requirement to be met in order to be played
+* @see CardFace
+*/
+public class GoldCard extends PlayableCard{
+ private Symbol multiplier;
+ private QuantityRequirement req;
+
+ /**
+ * The front side always gives points based on the quantity of a certain resource, while the back always gives a
+ * resource of the card's faction
+ * @param front the front side of the card
+ * @param back the back side of the card
+ * @param multiplier the symbol whose number of resources multiplies the points parameter
+ * @param points the number every resource of the given type is worth
+ * @param req the requirement that must be met in order to be able to play the card
+ */
+ public GoldCard(CardFace front, CardFace back, Symbol multiplier, int points, QuantityRequirement req) {
+ this.front = front;
+ this.back = back;
+ this.points = points;
+ this.multiplier = multiplier;
+ this.req = req;
+ }
+
+ /**
+ * Will compute the total points this card gives based on the board it's played on
+ * @param board The board on which we want to compute the points this card will give
+ */
+ public int totPoints(Board board) {
+ return this.points; // will need to compute tot resources of board and get the tot resource
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/InitialCard.java b/src/main/java/it/polimi/ingsw/gamemodel/InitialCard.java
new file mode 100644
index 00000000..8efaee8a
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/InitialCard.java
@@ -0,0 +1,15 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* Every player has an initial card (which will automatically be placed in the center of the board)
+*/
+public class InitialCard extends Card{
+ /**
+ * The initial card only gives corners and resources, never points, so we only need to know its topologic description
+ * @param front the front side of the card
+ * @param back the back side of the card
+ */
+ public InitialCard(CardFace front, CardFace back) {
+ this.front = front; this.back = back;
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Match.java b/src/main/java/it/polimi/ingsw/gamemodel/Match.java
new file mode 100644
index 00000000..fdd0cc5d
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Match.java
@@ -0,0 +1,279 @@
+package it.polimi.ingsw.gamemodel;
+
+import it.polimi.ingsw.utils.Pair;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Match {
+ private final List players;
+ private final int maxPlayers;
+ private Player currentPlayer;
+
+ private MatchState currentState;
+
+ // All cards decks
+ private final GameDeck initialsDeck;
+ private final GameDeck resourcesDeck;
+ private final GameDeck goldsDeck;
+ private final GameDeck objectivesDeck;
+
+ // All the visible cards on the common table
+ private Pair visibleResources;
+ private Pair visibleGolds;
+ private Pair visibleObjectives;
+
+ private Pair currentProposedObjectives;
+
+ // Denotes if the match has been started or has finished
+ private boolean started = false;
+ private boolean lastTurn = false;
+ private boolean finished = false;
+
+
+ /**
+ * Constructor to be used to initialize main Match attributes and allocate the attribute players List.
+ * @param maxPlayers maximum number of players to be added to the match, chosen by the first player to join
+ * @param initialsDeck deck of initial cards
+ * @param resourcesDeck deck of resource cards
+ * @param goldsDeck deck of gold cards
+ * @param objectivesDeck deck of objectives
+ */
+ public Match(int maxPlayers, GameDeck initialsDeck, GameDeck resourcesDeck, GameDeck goldsDeck, GameDeck objectivesDeck) {
+ this.maxPlayers = maxPlayers;
+ this.initialsDeck = initialsDeck;
+ this.resourcesDeck = resourcesDeck;
+ this.goldsDeck = goldsDeck;
+ this.objectivesDeck = objectivesDeck;
+
+ this.players = new ArrayList();
+ }
+
+ // Called by the controller
+ /**
+ * Method that adds a new player to the match; if the player is already in, throws an exception.
+ * @param player player to be added to the match
+ * @throws IllegalArgumentException thrown if player already in the match
+ */
+ public void addPlayer(Player player) throws IllegalArgumentException, WrongStateException {
+ if(!players.contains(player)) {
+ currentState.addPlayer();
+ players.add(player);
+ } else {
+ throw new IllegalArgumentException("Duplicated Player in a Match");
+ }
+ }
+
+ // Called by the controller
+ /**
+ *
+ * @param player
+ */
+ public void removePlayer(Player player) {
+ players.remove(player);
+ }
+
+ // Called by the controller
+ /**
+ *
+ * @return
+ */
+ public boolean isFull() {
+ return players.size() == maxPlayers;
+ }
+
+ /**
+ * Method that changes the currentPlayer based on the next turn
+ * If it is the first turn, currentPlayer gets initialized as the
+ * first one in the players List.The turn order follows the list order.
+ * Called by ChoosePlayerState every time a new turn starts
+ */
+ protected void nextPlayer() {
+ // If player has never been initialized OR the current player is the last one
+ if (currentPlayer == null || currentPlayer.equals(players.getLast())) {
+ // Set currentPlayer as the first one
+ currentPlayer = players.getFirst();
+ } else {
+ // Get the index of the current player and choose the next one
+ int currentPlayerIndex = players.indexOf(currentPlayer);
+ currentPlayer = players.get(currentPlayerIndex + 1);
+ }
+ }
+ // Called by the state
+ /**
+ *
+ */
+ protected void doFinish() {
+ finished = true;
+ }
+
+ // Called by the controller
+ /**
+ *
+ * @return
+ */
+ public boolean isFinished() {
+ return finished;
+ }
+
+ protected void doStart() {
+ started = true;
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ // Called by the controller
+ /**
+ *
+ * @return
+ */
+ public Player getCurrentPlayer() {
+ return currentPlayer;
+ }
+
+ public List getPlayers() {
+ return players;
+ }
+ // Called by the state
+
+ /**
+ *
+ * @param state
+ */
+ protected void setState(MatchState state) {
+ this.currentState = state;
+ }
+
+ /**
+ *
+ * @return
+ */
+ protected Pair proposeSecretObjectives() {
+ Objective obj1 = objectivesDeck.pop();
+ Objective obj2 = objectivesDeck.pop();
+ currentProposedObjectives = new Pair<>(obj1, obj2);
+ return currentProposedObjectives;
+ }
+
+ // Called by the controller
+ /**
+ *
+ * @param objective
+ */
+ protected void chooseSecretObjective(Objective objective) {
+ // Put back the player's refused secret objective
+ objectivesDeck.add(objective);
+ }
+
+ /**
+ *
+ */
+ protected void setupPlayers() {
+ // Shuffle players List
+ Collections.shuffle(players);
+
+ // Set players' colors
+ for (int i = 0; i < maxPlayers; i++) {
+ players.get(i).setColor(Color.values()[i]);
+ }
+ }
+
+ /**
+ *
+ */
+ protected void setupDecks() {
+ // Shuffle each deck
+ initialsDeck.shuffle();
+ resourcesDeck.shuffle();
+ goldsDeck.shuffle();
+ objectivesDeck.shuffle();
+
+ // Pop two resources to be placed on the common table
+ ResourceCard resourceCard1 = resourcesDeck.pop();
+ ResourceCard resourceCard2 = resourcesDeck.pop();
+
+ // Pop two golds to be placed on the common table
+ GoldCard goldCard1 = goldsDeck.pop();
+ GoldCard goldCard2 = goldsDeck.pop();
+
+ // Pop two golds to be placed on the common table
+ Objective objective1 = objectivesDeck.pop();
+ Objective objective2 = objectivesDeck.pop();
+
+ // Set popped cards in Match attributes
+ visibleGolds = new Pair<>(goldCard1, goldCard2);
+ visibleResources = new Pair<>(resourceCard1, resourceCard2);
+ visibleObjectives = new Pair<>(objective1, objective2);
+ }
+
+ /**
+ *
+ */
+ protected void setupBoards() {
+ // Give starting cards to players
+ for (Player player : players) {
+ // Pop a card from the resources deck and one from the golds deck
+ GoldCard goldCard = goldsDeck.pop();
+ ResourceCard resourceCard1 = resourcesDeck.pop();
+ ResourceCard resourceCard2 = resourcesDeck.pop();
+
+ // Add each card to the player's hand
+ player.getBoard().addHandCard(goldCard);
+ player.getBoard().addHandCard(resourceCard1);
+ player.getBoard().addHandCard(resourceCard2);
+
+ // Place the initial card to the player's board
+ // By default, the initial card is placed on front side
+ Pair initialCoords = new Pair<>(0,0);
+ InitialCard initial = initialsDeck.pop();
+ player.getBoard().placeCard(initialCoords, initial, Side.FRONT);
+
+ }
+ }
+
+ /**
+ *
+ * @param coords
+ * @param card
+ * @param side
+ * @throws WrongStateException
+ * @throws WrongCardPlacementException
+ */
+ protected void makeMove(Pair coords, PlayableCard card, Side side) throws WrongStateException, WrongCardPlacementException {
+ Board currentPlayerBoard = currentPlayer.getBoard();
+
+ // If placing the card in the current player's board is allowed by rules
+ if (currentPlayerBoard.verifyCardPlacement(coords, card, side)) {
+
+ // Trigger current state behavior
+ currentState.makeMove();
+
+ // Place the card in the current player's board
+ // and save the points possibly gained because of the move
+ int gainedPoints = currentPlayerBoard.placeCard(coords, card, side);
+
+ // Remove the card from the player's hand
+ // since it has been placed on the board
+ currentPlayerBoard.removeHandCard(card);
+
+ // Update the current player's points
+ currentPlayer.addPoints(gainedPoints);
+
+ // If the current player reaches 20 points or more
+ // the last turn of the match starts
+ if (currentPlayer.getPoints() >= 20)
+ lastTurn = true;
+
+ // If the current player is the last one in the match turns rotation
+ // i.e. the last one in the players List
+ // AND the current turn is the last one
+ // the match is now finished
+ if (currentPlayer.equals(players.getLast()) && lastTurn)
+ finished = true;
+ } else {
+ throw new WrongCardPlacementException("Card placement not valid!");
+ }
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/MatchState.java b/src/main/java/it/polimi/ingsw/gamemodel/MatchState.java
new file mode 100644
index 00000000..e26251f3
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/MatchState.java
@@ -0,0 +1,35 @@
+package it.polimi.ingsw.gamemodel;
+
+public abstract class MatchState {
+ Match match;
+
+ public MatchState (Match match) {
+ this.match = match;
+ }
+
+ public abstract void transition();
+
+ public void addPlayer() throws WrongStateException{
+ throw new WrongStateException("addPlayer not allowed from the current match state!");
+ }
+
+ public void removePlayer() throws WrongStateException{
+ throw new WrongStateException("removePlayer not allowed from the current match state!");
+ }
+
+ public void makeMove() throws WrongStateException{
+ throw new WrongStateException("makeMove not allowed from the current match state!");
+ }
+
+ public void drawCard() throws WrongStateException{
+ throw new WrongStateException("drawCard not allowed from the current match state!");
+ }
+
+ public void proposeSecretObjectives() throws WrongStateException{
+ throw new WrongStateException("proposeSecretObjective not allowed from the current match state!");
+ }
+
+ public void chooseSecretObjectives() throws WrongStateException {
+ throw new WrongStateException("chooseSecretObjective not allowed from the current match state!");
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/NextTurnState.java b/src/main/java/it/polimi/ingsw/gamemodel/NextTurnState.java
new file mode 100644
index 00000000..878c4175
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/NextTurnState.java
@@ -0,0 +1,38 @@
+package it.polimi.ingsw.gamemodel;
+
+public class NextTurnState extends MatchState {
+
+ public NextTurnState(Match match) {
+ super(match);
+
+ match.nextPlayer();
+ }
+
+ @Override
+ public void proposeSecretObjectives() throws WrongStateException {
+ if (match.isStarted())
+ throw new WrongStateException("proposeSecretObjectives called after the match was started");
+ else
+ this.transition();
+ }
+
+ @Override
+ public void makeMove() throws WrongStateException {
+ if (match.isStarted())
+ this.transition();
+ else
+ throw new WrongStateException("makeMove called when match was not started yet");
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState;
+
+ if (match.isStarted())
+ nextState = new AfterMoveState(match);
+ else
+ nextState = new ChooseSecretObjectiveState(match);
+
+ match.setState(nextState);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Objective.java b/src/main/java/it/polimi/ingsw/gamemodel/Objective.java
new file mode 100644
index 00000000..ec04d950
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Objective.java
@@ -0,0 +1,20 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* Every player has a secret objective, and at the start of the game two objectives common to every
+* player get randomly chosen. The objective asks for a certain requirement to be satisfied and gives points only when
+* the game ends, and does not stack on itself (e.g. if an objective requires three feathers and a player has 6, he will receive the points only once)
+*/
+public class Objective {
+ private int points;
+ private Requirement req;
+
+ /**
+ * @param points the number of points the objective will give (which is always an absolute number, it never depends on any resource)
+ * @param req the requirement to satisfy in order to receive the points
+ */
+ public Objective(int points, Requirement req) {
+ this.points = points; this.req = req;
+ }
+}
+
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/PlacedCard.java b/src/main/java/it/polimi/ingsw/gamemodel/PlacedCard.java
new file mode 100644
index 00000000..248d485d
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/PlacedCard.java
@@ -0,0 +1,19 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* This class handles the card already placed on the board, since we need to remember which card covers which
+*/
+public class PlacedCard {
+ private Card card;
+ private int turn;
+
+
+ /**
+ * @param card the {@link Card} played
+ * @param turn the turn said card is played. Needed to know which card covers which, since a card played in a certain turn will
+ * always cover one played before
+ */
+ public PlacedCard(Card card, int turn) {
+ this.card = card; this.turn = turn;
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/PlayableCard.java b/src/main/java/it/polimi/ingsw/gamemodel/PlayableCard.java
new file mode 100644
index 00000000..ff6b1c31
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/PlayableCard.java
@@ -0,0 +1,12 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* Class that represents every kind of card that can be played during the game.
+* All these cards have at least a side (the back) that does not require any resouce to be played.
+* @see CardFace
+*/
+
+public abstract class PlayableCard extends Card{
+ protected int points;
+}
+
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Player.java b/src/main/java/it/polimi/ingsw/gamemodel/Player.java
new file mode 100644
index 00000000..695b13ed
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Player.java
@@ -0,0 +1,100 @@
+package it.polimi.ingsw.gamemodel;
+import it.polimi.ingsw.utils.Pair;
+
+/**
+* Player represents each in-game user. The class also manages the board's logic
+*/
+public class Player {
+ private String nickname;
+ private Match match;
+ private int points;
+ private Board board;
+ private Color pawnColor;
+ private Objective secretObjective;
+
+ public Player(String nickname, Match match) {
+ this.nickname = nickname;
+ this.match = match;
+
+ //Initialize values
+ board = new Board();
+ points = 0;
+
+ }
+
+ /**
+ * Places on the board the desired card (on the specified side) in the given position, if it is a valid one
+ * @param coord x and y position in which the card is played (where 0, 0 is the initial card)
+ * @param card the card to be placed
+ * @param side whether the card should be placed on the front or on the back
+ */
+ public void playCard(Pair coord, PlayableCard card, Side side) {
+ //TODO
+ }
+
+ /**
+ * Adds a card to the player's hand, popping it from the required source
+ * @param source represents the source of the draw, which can be either one of the two decks or one of the four cards on the table
+ */
+ public void drawcard(DrawSource source) {
+ // TODO
+ }
+
+ /**
+ * Sets the player private objective (only at the start of the game)
+ * @param objective the chosen objective between the two proposed
+ */
+ public void chooseSecretObjective(Objective objective) {
+ // TODO
+ }
+
+ /**
+ * Getter for the player's board
+ */
+ public Board getBoard() {
+ return board;
+ }
+
+ /**
+ * Getter for the player's points
+ */
+ public int getPoints() {
+ return points;
+ }
+ /**
+ * Getter for the player's pawn color
+ */
+ public Color getPawnColor() {
+ return pawnColor;
+ }
+
+ /**
+ * Setter for the player's color
+ */
+ protected void setColor(Color color) {
+ this.pawnColor = color;
+ }
+
+ /**
+ * Getter for the player's objective
+ * @see #chooseSecretObjective(Objective)
+ */
+ protected Objective getSecretObjective() {
+ return secretObjective;
+ }
+
+ /**
+ * Adds points to the player
+ * @param points number of points to add to the player
+ */
+ protected void addPoints(int points) {
+ this.points += points;
+ }
+
+ /**
+ * Getter for the player's nickname
+ */
+ public String getNickname() {
+ return nickname;
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/PositionRequirement.java b/src/main/java/it/polimi/ingsw/gamemodel/PositionRequirement.java
new file mode 100644
index 00000000..08abf3f0
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/PositionRequirement.java
@@ -0,0 +1,32 @@
+package it.polimi.ingsw.gamemodel;
+
+import java.util.Map;
+
+import it.polimi.ingsw.utils.Pair;
+
+/**
+* This class handles requirements involving relative positioning of cards, e.g. three red cards placed in the top right corner of each other
+*/
+public class PositionRequirement extends Requirement{
+ private Map, Symbol> reqs;
+
+ /**
+ * @param reqs The relative positioning of the cards (of which we only care about the faction).
+ * Note that, since this requirement only cares about relative positioning, there must always be
+ * an element whose key is (0, 0)
+ */
+ public PositionRequirement(Map, Symbol> reqs) {
+ this.reqs = reqs;
+ }
+
+ /**
+ * The requirement will be satisfied if the board has cards of the specified faction in the correct relative positions
+ * @param board the {@link Board} on which the requirement must be checked
+ * @return wheter the board actually meets the requirement or not
+ */
+ @Override
+ public boolean isSatisfied(Board board) {
+ return true;
+ }
+
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/QuantityRequirement.java b/src/main/java/it/polimi/ingsw/gamemodel/QuantityRequirement.java
new file mode 100644
index 00000000..f1436fe6
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/QuantityRequirement.java
@@ -0,0 +1,29 @@
+package it.polimi.ingsw.gamemodel;
+
+import java.util.Map;
+
+import it.polimi.ingsw.utils.Pair;
+
+/**
+* This class handles requirements involving relative positioning of cards, e.g. three red cards placed in the top right corner of each other
+*/
+public class QuantityRequirement extends Requirement{
+ private Map reqs;
+
+ /**
+ * @param reqs how many resources of a certain type are needed to fulfill the requirement
+ */
+ public QuantityRequirement(Map reqs) {
+ this.reqs = reqs;
+ }
+
+ /**
+ * The requirement will be satisfied if the board has enough resources of the specified type
+ * @param board the board on which we check the requirement
+ * @return whether the requirement is satisfied
+ */
+ @Override
+ public boolean isSatisfied(Board board) {
+ return true;
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/RankingState.java b/src/main/java/it/polimi/ingsw/gamemodel/RankingState.java
new file mode 100644
index 00000000..1684ce6b
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/RankingState.java
@@ -0,0 +1,4 @@
+package it.polimi.ingsw.gamemodel;
+
+public class RankingState {
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Requirement.java b/src/main/java/it/polimi/ingsw/gamemodel/Requirement.java
new file mode 100644
index 00000000..df254369
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Requirement.java
@@ -0,0 +1,15 @@
+package it.polimi.ingsw.gamemodel;
+
+/*
+* A condition must be met in order to play a golden card and to get points from the objectives. Those requirements are both represented by this class
+*/
+public abstract class Requirement {
+
+ /**
+ * Will be implemented on the concrete classes, as they have different kind of conditions
+ * @param board the board that will be used to check if the requirement is met
+ * @return whether the requirement is met or not
+ */
+ public abstract boolean isSatisfied(Board board);
+
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/ResourceCard.java b/src/main/java/it/polimi/ingsw/gamemodel/ResourceCard.java
new file mode 100644
index 00000000..1b1533ab
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/ResourceCard.java
@@ -0,0 +1,16 @@
+package it.polimi.ingsw.gamemodel;
+
+/*
+* Card that does not require any conditions to be played
+*/
+public class ResourceCard extends PlayableCard{
+ /**
+ * @param front the front side of the card
+ * @param back the back side of the card
+ * @param points the number of points the card gives (must be an absolute value)
+ */
+ public ResourceCard(CardFace front, CardFace back, int points) {
+ this.front = front; this.back = back; this.points = points;
+ }
+
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/SetupState.java b/src/main/java/it/polimi/ingsw/gamemodel/SetupState.java
new file mode 100644
index 00000000..a54ad47c
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/SetupState.java
@@ -0,0 +1,20 @@
+package it.polimi.ingsw.gamemodel;
+
+public class SetupState extends MatchState {
+
+ SetupState(Match match) {
+ super(match);
+
+ match.setupDecks();
+ match.setupPlayers();
+ match.setupBoards();
+
+ this.transition();
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState = new NextTurnState(match);
+ match.setState(nextState);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Side.java b/src/main/java/it/polimi/ingsw/gamemodel/Side.java
new file mode 100644
index 00000000..4237e949
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Side.java
@@ -0,0 +1,9 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* Used to know which of the two faces of a card we want to use
+*/
+public enum Side {
+ FRONT,
+ BACK
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/Symbol.java b/src/main/java/it/polimi/ingsw/gamemodel/Symbol.java
new file mode 100644
index 00000000..35dbd68a
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/Symbol.java
@@ -0,0 +1,20 @@
+package it.polimi.ingsw.gamemodel;
+
+/**
+* Contains all the possible symbols a corner can store or a multiplier can have.
+* Besides the basic 4 factions and 3 symbols, there is also EMPTY_CORNER, which represents a corner withtout the
+* possibility of placing another card on top of it (missing slot), FULL_CORNER which represents a valid corner without any symbol and
+* CORNER_OBJ which represents a {@link QuantityRequirement} in which the multiplier is how many corners the card covered
+*/
+public enum Symbol {
+ ANIMAL,
+ PLANT,
+ INSECT,
+ FUNGUS,
+ FEATHER,
+ INKWELL,
+ PARCHMENT,
+ EMPTY_CORNER,
+ FULL_CORNER,
+ CORNER_OBJ
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/WaitState.java b/src/main/java/it/polimi/ingsw/gamemodel/WaitState.java
new file mode 100644
index 00000000..517851d1
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/WaitState.java
@@ -0,0 +1,25 @@
+package it.polimi.ingsw.gamemodel;
+
+public class WaitState extends MatchState{
+
+ public WaitState(Match match) {
+ super(match);
+ }
+
+ @Override
+ public void transition() {
+ MatchState nextState = new SetupState(match);
+ match.setState(nextState);
+ }
+
+ @Override
+ public void removePlayer() {
+ //TBD
+ }
+
+ @Override
+ public void addPlayer() {
+ if (match.isFull())
+ transition();
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/WrongCardPlacementException.java b/src/main/java/it/polimi/ingsw/gamemodel/WrongCardPlacementException.java
new file mode 100644
index 00000000..f8829974
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/WrongCardPlacementException.java
@@ -0,0 +1,7 @@
+package it.polimi.ingsw.gamemodel;
+
+public class WrongCardPlacementException extends Exception {
+ public WrongCardPlacementException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/gamemodel/WrongStateException.java b/src/main/java/it/polimi/ingsw/gamemodel/WrongStateException.java
new file mode 100644
index 00000000..a7f6ff6e
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/gamemodel/WrongStateException.java
@@ -0,0 +1,7 @@
+package it.polimi.ingsw.gamemodel;
+
+public class WrongStateException extends Exception{
+ public WrongStateException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/it/polimi/ingsw/utils/Pair.java b/src/main/java/it/polimi/ingsw/utils/Pair.java
new file mode 100644
index 00000000..edff9c9c
--- /dev/null
+++ b/src/main/java/it/polimi/ingsw/utils/Pair.java
@@ -0,0 +1,3 @@
+package it.polimi.ingsw.utils;
+
+public record Pair (T first, U second) {}