892 lines
34 KiB
Java
892 lines
34 KiB
Java
package it.polimi.ingsw.gc14.Model;
|
|
|
|
import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType;
|
|
import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
|
|
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
|
|
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
|
|
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventCard;
|
|
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventType;
|
|
import it.polimi.ingsw.gc14.Model.GamePackage.Board;
|
|
import it.polimi.ingsw.gc14.Model.GamePackage.CurrentState;
|
|
import it.polimi.ingsw.gc14.Model.Orders.Order2;
|
|
import it.polimi.ingsw.gc14.Model.Orders.Order3;
|
|
import it.polimi.ingsw.gc14.Model.Orders.Order4;
|
|
import it.polimi.ingsw.gc14.Model.Orders.Order5;
|
|
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
import it.polimi.ingsw.gc14.Network.Observer;
|
|
import it.polimi.ingsw.gc14.View.TUI.AsciiTable;
|
|
import it.polimi.ingsw.gc14.View.TUI.BorderStyle;
|
|
|
|
/**
|
|
* Represents the main game model.
|
|
* A Game object stores the players, the current state of the match,
|
|
* the slot assignments, the board, and the logic required to manage the game flow.
|
|
*/
|
|
public class Game implements Serializable {
|
|
|
|
private transient List<Observer> observers = new ArrayList<>(); // transient! non serializzare
|
|
|
|
public void addObserver(Observer observer) {
|
|
observers.add(observer);
|
|
}
|
|
|
|
private void notifyObservers() {
|
|
for (Observer o : observers) {
|
|
o.update(this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the list of players participating in the game.
|
|
* @return
|
|
*/
|
|
public List<Player> getPlayers() {
|
|
return playersList;
|
|
}
|
|
|
|
/**
|
|
* The current number of players.
|
|
*/
|
|
public int getCurrentPlayerNumber() {
|
|
return playersList.size();
|
|
}
|
|
|
|
/**
|
|
* The list of players participating in the game.
|
|
*/
|
|
private ArrayList<Player> playersList;
|
|
|
|
/**
|
|
* The current state of the game.
|
|
*/
|
|
private CurrentState currentState;
|
|
|
|
/**
|
|
* The mapping between slots and the players assigned to them.
|
|
*/
|
|
private HashMap<Slot,Player> slotMap;
|
|
|
|
/**
|
|
* The configured number of players for this game.
|
|
*/
|
|
private int nPlayers;
|
|
|
|
/**
|
|
* The queue of players involved in optional card resolution.
|
|
*/
|
|
private Queue<Player> OptionalCardQueue;
|
|
|
|
/**
|
|
* The order logic card associated with this game.
|
|
*/
|
|
private OrderLogicCard orderLogicCard;
|
|
|
|
/**
|
|
* The board associated with this game.
|
|
*/
|
|
private Board board;
|
|
|
|
/**
|
|
* Returns clones of the upper tribe cards currently available on the board.
|
|
*
|
|
* @return a list containing clones of the upper tribe cards currently available on the board.
|
|
*/
|
|
public List<TribeCard>getUpperListTribeCards() {
|
|
List<TribeCard> cards = new ArrayList<>();
|
|
board.upperListTribe.forEach(x->cards.add(x.clone()));
|
|
return cards;
|
|
}
|
|
|
|
/**
|
|
* Returns clones of the lower tribe cards currently available on the board.
|
|
*
|
|
* @return a list containing clones of the lower tribe cards currently available on the board.
|
|
*/
|
|
public List<TribeCard>getLowerListTribeCards() {
|
|
List<TribeCard> cards = new ArrayList<>();
|
|
board.lowerListTribe.forEach(x->cards.add(x.clone()));
|
|
return cards;
|
|
}
|
|
|
|
/**
|
|
* Returns clones of the upper building cards currently available on the board.
|
|
*
|
|
* @return a list containing clones of the upper building cards currently available on the board.
|
|
*/
|
|
public List<BuildingCard>getUpperListBuilding() {
|
|
List<BuildingCard> cards = new ArrayList<>();
|
|
board.upperListBuilding.forEach(x->cards.add(x.clone()));
|
|
return cards;
|
|
}
|
|
|
|
/**
|
|
* Returns clones of the lower building cards currently available on the board.
|
|
*
|
|
* @return a list containing clones of the lower building cards currently available on the board.
|
|
*/
|
|
public List<BuildingCard>getLowerListBuilding() {
|
|
List<BuildingCard> cards = new ArrayList<>();
|
|
board.lowerListBuilding.forEach(x->cards.add(x.clone()));
|
|
return cards;
|
|
}
|
|
|
|
/**
|
|
* Returns the current state of the game.
|
|
*
|
|
* @return the current state of the game.
|
|
*/
|
|
public CurrentState getCurrentState() {
|
|
return currentState;
|
|
};
|
|
|
|
/**
|
|
* Returns the player with the specified username, if present.
|
|
*
|
|
* @param Username the username of the player to search for.
|
|
* @return the player with the specified username, or {@code null} if no such player exists.
|
|
*/
|
|
public Player getPlayerByUsername(String Username) throws IndexOutOfBoundsException {
|
|
return playersList.stream().filter(x->x.getUserName().equals(Username)).findFirst().orElse(null);
|
|
}
|
|
|
|
/**
|
|
* Returns the configured number of players for this game.
|
|
*
|
|
* @return the configured number of players for this game.
|
|
*/
|
|
public int getNPlayers() {
|
|
return nPlayers;
|
|
}
|
|
|
|
/**
|
|
* Creates a game with the specified number of players.
|
|
*
|
|
* @param nPlayers the configured number of players for the game.
|
|
* @throws IllegalArgumentException if {@code nPlayers < 0} or {@code nPlayers > 5}.
|
|
*/
|
|
public Game(int nPlayers) throws IllegalArgumentException{
|
|
if(nPlayers !=0 && (nPlayers < 2 || nPlayers > 5)) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
this.nPlayers = nPlayers;
|
|
board=new Board(nPlayers);
|
|
slotMap = new LinkedHashMap<>();
|
|
for(Slot s :board.getSlotList())
|
|
{
|
|
slotMap.put(s,null);
|
|
}
|
|
currentState= new CurrentState();
|
|
playersList = new ArrayList<>();
|
|
OptionalCardQueue = new LinkedList<>();
|
|
}
|
|
|
|
/**
|
|
* Creates a game with 0 configured players.
|
|
*/
|
|
public Game()
|
|
{
|
|
this(0);
|
|
}
|
|
|
|
/**
|
|
* Attempts to add the specified player to the game.
|
|
* The operation succeeds only if the configured number of players is not 0,
|
|
* the current game stage is {@code WAITING}, and the player is not already present.
|
|
* If the number of players reaches the configured maximum, the game is initialized.
|
|
*
|
|
* @param player the player to add to the game.
|
|
* @return {@code true} if the player is successfully added, {@code false} otherwise.
|
|
*/
|
|
public boolean addPlayer(Player player) {
|
|
if(this.nPlayers==0)
|
|
{
|
|
return false;
|
|
}
|
|
if(currentState.getGameStage()!= GameStages.WAITING)
|
|
return false;
|
|
if(getPlayerByUsername(player.getUserName())!=null)
|
|
return false;
|
|
playersList.add(player);
|
|
if(playersList.size()>=nPlayers)
|
|
{
|
|
init();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Initializes the game after all required players have been added.
|
|
* The method creates the appropriate order logic card according to the number of players,
|
|
* selects the first current player, and updates the game stage to {@code SLOT_CHOICE}.
|
|
*/
|
|
public void init() {
|
|
|
|
switch (nPlayers) {
|
|
case 2:
|
|
orderLogicCard=new Order2(playersList);
|
|
break;
|
|
case 3:
|
|
orderLogicCard=new Order3(playersList);
|
|
break;
|
|
case 4:
|
|
orderLogicCard=new Order4(playersList);
|
|
break;
|
|
case 5:
|
|
orderLogicCard=new Order5(playersList);
|
|
break;
|
|
}
|
|
currentState.PlayerUpdate(orderLogicCard.pull(),null);
|
|
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
|
|
}
|
|
|
|
//region Controller Methods
|
|
|
|
/**
|
|
* Attempts to assign the slot at the specified index to the specified player.
|
|
* The operation succeeds only if the index is valid, the current game stage is {@code SLOT_CHOICE},
|
|
* the specified player is the current player, and the selected slot is not already assigned.
|
|
* If the slot is successfully assigned, the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the slot choice.
|
|
* @param slotIndex the index of the selected slot.
|
|
* @return {@code true} if the slot choice succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean SlotChoiceByIndex(Player player, int slotIndex) {
|
|
if(slotIndex<0 || slotIndex>=slotMap.size())
|
|
return false;
|
|
if(currentState.getGameStage()!= GameStages.SLOT_CHOICE)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
Map.Entry<Slot, Player> slotPlayerEntry = new ArrayList<>(slotMap.entrySet()).get(slotIndex);
|
|
if(slotPlayerEntry.getValue()!=null)
|
|
{
|
|
return false;
|
|
}
|
|
slotMap.put(slotPlayerEntry.getKey(),player);
|
|
nextPlayerSetup();
|
|
return true;
|
|
|
|
}
|
|
|
|
//region Drawing Methods
|
|
|
|
/**
|
|
* Attempts to draw the upper tribe card at the specified index for the specified player.
|
|
* The operation succeeds only if the index is valid, the game stage is {@code RESOLVING_ACTIONS},
|
|
* the specified player is the current player, at least one upper card draw is still available,
|
|
* and the selected tribe card is not an event card.
|
|
* If successful, the card is inserted into the player's collection, removed from the board,
|
|
* and the number of remaining upper draws is decremented.
|
|
* If both upper and lower draws become zero, the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the draw.
|
|
* @param cardIndex the index of the upper tribe card to draw.
|
|
* @return {@code true} if the draw succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean DrawUpperTribeCardByIndex(Player player,int cardIndex) {
|
|
if( cardIndex<0 || cardIndex >=board.upperListTribe.size())
|
|
return false;
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
if(currentState.getNUpper() <1)
|
|
return false;
|
|
TribeCard tribeCard = board.upperListTribe.get(cardIndex);
|
|
if(tribeCard.IsEventCard())
|
|
return false;
|
|
|
|
Character tempCard = (Character) tribeCard;
|
|
tempCard.insert(player);
|
|
board.removeUpperTribeCard(tempCard);
|
|
currentState.UpperDrawn();
|
|
if((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0)))
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
|
|
public boolean SkipUpperDrawing(Player player) {
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
if(currentState.getNUpper() <1)
|
|
return false;
|
|
if(hasDrawableUp())
|
|
return false;
|
|
currentState.UpperDrawn();
|
|
if((currentState.getNLower() ==0 ||( !hasDrawableDown() && getLowerListBuilding().isEmpty())) && ((currentState.getNUpper() ==0)||(getUpperListBuilding().isEmpty())))
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
|
|
public boolean SkipLowerDrawing(Player player) {
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
if(currentState.getNUpper() <1)
|
|
return false;
|
|
if(hasDrawableDown())
|
|
return false;
|
|
currentState.LowerDrawn();
|
|
if((currentState.getNLower() ==0 ||( getLowerListBuilding().isEmpty())) && ((currentState.getNUpper() ==0)||(!hasDrawableUp()&&getUpperListBuilding().isEmpty())))
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Attempts to draw the lower tribe card at the specified index for the specified player.
|
|
* The operation succeeds only if the index is valid, the game stage is {@code RESOLVING_ACTIONS},
|
|
* the specified player is the current player, at least one lower card draw is still available,
|
|
* and the selected tribe card is not an event card.
|
|
* If successful, the card is inserted into the player's collection, removed from the board,
|
|
* and the number of remaining lower draws is decremented.
|
|
* If both lower and upper draws become zero, the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the draw.
|
|
* @param cardIndex the index of the lower tribe card to draw.
|
|
* @return {@code true} if the draw succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean DrawLowerTribeCardByIndex(Player player, int cardIndex) {
|
|
if( cardIndex<0 || cardIndex >=board.lowerListTribe.size())
|
|
return false;
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
if(currentState.getNLower() <1)
|
|
return false;
|
|
TribeCard tribeCard = board.lowerListTribe.get(cardIndex);
|
|
if(tribeCard.IsEventCard())
|
|
return false;
|
|
|
|
Character tempCard = (Character) tribeCard;
|
|
tempCard.insert(player);
|
|
board.removeLowerTribeCard(tempCard);
|
|
currentState.LowerDrawn();
|
|
if((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0)))
|
|
nextPlayerSetup();
|
|
return true;
|
|
|
|
}
|
|
|
|
/**
|
|
* Attempts to draw the upper building card at the specified index for the specified player.
|
|
* The operation succeeds only if the index is valid, the game stage is {@code RESOLVING_ACTIONS},
|
|
* the specified player is the current player, at least one upper card draw is still available,
|
|
* and the selected building card can be bought by the player.
|
|
* If successful, the building card is removed from the board and the number of remaining upper draws is decremented.
|
|
* If both upper and lower draws become zero, the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the draw.
|
|
* @param cardIndex the index of the upper building card to draw.
|
|
* @return {@code true} if the draw succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean DrawUpperBuildingCardByIndex(Player player,int cardIndex) {
|
|
if( cardIndex<0 || cardIndex >=board.upperListBuilding.size())
|
|
return false;
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
BuildingCard buildingCard = board.upperListBuilding.get(cardIndex);
|
|
if(currentState.getNUpper() <1)
|
|
return false;
|
|
if(buildingCard.buy(player))
|
|
{
|
|
currentState.UpperDrawn();
|
|
board.removeUpperBuildingCard(buildingCard);
|
|
}
|
|
else
|
|
return false;
|
|
if((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0)))
|
|
nextPlayerSetup();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Attempts to draw the lower building card at the specified index for the specified player.
|
|
* The operation succeeds only if the index is valid, the game stage is {@code RESOLVING_ACTIONS},
|
|
* the specified player is the current player, at least one lower card draw is still available,
|
|
* and the selected building card can be bought by the player.
|
|
* If successful, the building card is removed from the board and the number of remaining lower draws is decremented.
|
|
* If both lower and upper draws become zero, the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the draw.
|
|
* @param cardIndex the index of the lower building card to draw.
|
|
* @return {@code true} if the draw succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean DrawLowerBuildingCardByIndex(Player player,int cardIndex) {
|
|
if( cardIndex<0 || cardIndex >=board.lowerListBuilding.size())
|
|
return false;
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!player.equals(currentState.getCurrentPlayer()))
|
|
{
|
|
return false;
|
|
}
|
|
BuildingCard buildingCard = board.lowerListBuilding.get(cardIndex);
|
|
if(currentState.getNLower() <1)
|
|
return false;
|
|
if(buildingCard.buy(player))
|
|
{
|
|
currentState.LowerDrawn();
|
|
board.removeLowerBuildingCard(buildingCard);
|
|
}
|
|
else
|
|
return false;
|
|
if((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0)))
|
|
nextPlayerSetup();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//endregion
|
|
|
|
//region Optional Card Methods
|
|
|
|
|
|
/**
|
|
* Attempts to pick the upper optional tribe card at the specified index for the specified player.
|
|
* The operation succeeds only if the current game stage is {@code OPTIONAL_CARD_EFFECT},
|
|
* the specified player is the current player, the index is valid,
|
|
* and the selected tribe card is not an event card.
|
|
* If successful, the card is inserted into the player's collection,
|
|
* removed from the board, the player is removed from the optional card queue,
|
|
* and the next player setup is triggered.
|
|
*
|
|
* @param player the player performing the optional tribe card pick.
|
|
* @param cardIndex the index of the upper optional tribe card to pick.
|
|
* @return {@code true} if the operation succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean PickOptionalTribeCardByIndex(Player player,int cardIndex) {
|
|
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer())){
|
|
return false;
|
|
}
|
|
|
|
if( cardIndex<0 || cardIndex >=board.upperListTribe.size())
|
|
return false;
|
|
TribeCard tribeCard = board.upperListTribe.get(cardIndex);
|
|
|
|
if(tribeCard.IsEventCard())
|
|
return false;
|
|
|
|
Character tempCard = (Character) tribeCard;
|
|
tempCard.insert(player);
|
|
board.removeUpperTribeCard(tempCard);
|
|
OptionalCardQueue.removeIf(x->x.equals(player));
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Attempts to pick the upper optional building card at the specified index for the specified player.
|
|
* The operation succeeds only if the current game stage is {@code OPTIONAL_CARD_EFFECT},
|
|
* the specified player is the current player, the index is valid,
|
|
* and the selected building card can be bought by the player.
|
|
* If successful, the card is removed from the board, the next player setup is triggered,
|
|
* and the player is removed from the optional card queue.
|
|
*
|
|
* @param player the player performing the optional building card pick.
|
|
* @param cardIndex the index of the upper optional building card to pick.
|
|
* @return {@code true} if the operation succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean PickOptionalBuildingCard(Player player, int cardIndex) {
|
|
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer())){
|
|
return false;
|
|
}
|
|
if( cardIndex<0 || cardIndex >=board.upperListBuilding.size())
|
|
return false;
|
|
BuildingCard buildingCard = board.upperListBuilding.get(cardIndex);
|
|
if(buildingCard.buy(player)) {
|
|
board.removeUpperBuildingCard(buildingCard);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
OptionalCardQueue.removeIf(x->x.equals(player));
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Skips the optional card choice for the specified player.
|
|
* The operation succeeds only if the current game stage is {@code OPTIONAL_CARD_EFFECT}
|
|
* and the specified player is the current player.
|
|
* If successful, the player is removed from the optional card queue
|
|
* and the next player setup is triggered.
|
|
*
|
|
* @param player the player skipping the optional card choice.
|
|
* @return {@code true} if the operation succeeds, {@code false} otherwise.
|
|
*/
|
|
public boolean NoOptionalCard(Player player) {
|
|
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
|
|
return false;
|
|
}
|
|
if(!player.equals(currentState.getCurrentPlayer())){
|
|
return false;
|
|
}
|
|
OptionalCardQueue.removeIf(x->x.equals(player));
|
|
nextPlayerSetup();
|
|
return true;
|
|
}
|
|
//endregion
|
|
|
|
//endregion
|
|
|
|
/**
|
|
* Prepares the next player and updates the game state according to the current game stage.
|
|
* If the current stage is {@code SLOT_CHOICE}, the next player is taken from the order logic card.
|
|
* If no player is available, the game stage is updated to {@code RESOLVING_ACTIONS}
|
|
* and the first assigned slot is selected.
|
|
* If the current stage is {@code RESOLVING_ACTIONS}, the current player is pushed back
|
|
* into the order logic card, the current slot is freed, and the next assigned slot is selected.
|
|
* If no assigned slots remain, the game stage is updated to {@code OPTIONAL_CARD_EFFECT},
|
|
* the optional card queue is built from players owning building cards with effect id equal to 12,
|
|
* and the first player in that queue is selected.
|
|
* If no player is available for optional card resolution, the game stage is updated to
|
|
* {@code RESOLVING_EVENT}; then, if the round number is less than 10, the next round is prepared,
|
|
* otherwise event resolution is performed, the game stage is updated to {@code ENDING},
|
|
* and the game is ended.
|
|
* If the current stage is {@code OPTIONAL_CARD_EFFECT}, the next player is taken from the optional card queue.
|
|
* If no player is available, the game stage is updated to {@code RESOLVING_EVENT}.
|
|
*/
|
|
private void nextPlayerSetup() {
|
|
if(GameStages.SLOT_CHOICE==currentState.getGameStage()) {
|
|
Player tempPlayer = orderLogicCard.pull();
|
|
|
|
if(tempPlayer!=null) {
|
|
currentState.PlayerUpdate(tempPlayer, null);
|
|
return;
|
|
}
|
|
currentState.GameStageUpdate(GameStages.RESOLVING_ACTIONS);
|
|
for (Slot s : slotMap.keySet()) {
|
|
if (slotMap.get(s) != null) {
|
|
currentState.PlayerUpdate(slotMap.get(s), s);
|
|
if(!((currentState.getNLower() ==0 ||(!hasDrawableDown() && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||(!hasDrawableUp() && getUpperListBuilding().size()==0))))
|
|
break;
|
|
else
|
|
{
|
|
orderLogicCard.push(currentState.getCurrentPlayer());
|
|
slotMap.put(currentState.getSlot(), null);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
}
|
|
if(GameStages.RESOLVING_ACTIONS==currentState.getGameStage()) {
|
|
orderLogicCard.push(currentState.getCurrentPlayer());
|
|
slotMap.put(currentState.getSlot(), null);
|
|
for (Slot s : slotMap.keySet()) {
|
|
if (slotMap.get(s) != null) {
|
|
currentState.PlayerUpdate(slotMap.get(s), s);
|
|
if((currentState.getNLower() ==0 ||(!hasDrawableDown() && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( !hasDrawableUp() && getUpperListBuilding().size()==0))) {
|
|
orderLogicCard.push(currentState.getCurrentPlayer());
|
|
|
|
slotMap.put(currentState.getSlot(), null);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(slotMap.values().stream().allMatch(v -> v == null))
|
|
{
|
|
currentState.GameStageUpdate(GameStages.OPTIONAL_CARD_EFFECT);
|
|
HashMap<Player,Integer> optional=new LinkedHashMap<>();
|
|
for (Player p : playersList) {
|
|
int tempCount=(int)p.buildingCards.stream().filter(x->x.getEffectId()==12).count();
|
|
if(tempCount>0)
|
|
{
|
|
optional.put(p,tempCount);
|
|
}
|
|
}
|
|
OptionalCardQueue=new LinkedList<>();
|
|
for(Map.Entry<Player,Integer> e : optional.entrySet())
|
|
{
|
|
OptionalCardQueue.add(e.getKey());
|
|
}
|
|
Player optionalPlayer = OptionalCardQueue.poll();
|
|
|
|
if (optionalPlayer != null) {
|
|
currentState.PlayerUpdate(optionalPlayer, null);
|
|
return;
|
|
}
|
|
|
|
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
|
|
|
|
if (currentState.getRound() < 10) {
|
|
nextRound();
|
|
currentState.PlayerUpdate(orderLogicCard.pull(), null);
|
|
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
|
|
} else {
|
|
EventResolution();
|
|
currentState.GameStageUpdate(GameStages.ENDING);
|
|
endGame();
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (GameStages.OPTIONAL_CARD_EFFECT == currentState.getGameStage()) {
|
|
Player optionalPlayer = OptionalCardQueue.poll();
|
|
|
|
if (optionalPlayer != null) {
|
|
currentState.PlayerUpdate(optionalPlayer, null);
|
|
return;
|
|
}
|
|
|
|
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
|
|
|
|
if (currentState.getRound() < 10) {
|
|
nextRound();
|
|
currentState.PlayerUpdate(orderLogicCard.pull(), null);
|
|
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
|
|
} else {
|
|
EventResolution();
|
|
currentState.GameStageUpdate(GameStages.ENDING);
|
|
endGame();
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
}
|
|
private boolean hasDrawableUp()
|
|
{
|
|
return getUpperListTribeCards().stream().filter(x-> !x.IsEventCard()).count()!=0;
|
|
}
|
|
private boolean hasDrawableDown()
|
|
{
|
|
return getLowerListTribeCards().stream().filter(x-> !x.IsEventCard()).count()!=0;
|
|
}
|
|
/**
|
|
* Resolves all pending event cards if the current game stage is {@code RESOLVING_EVENT}.
|
|
* All pending events are activated on the player list.
|
|
* Event cards of type {@code SUSTENANCE} are resolved after all other pending events.
|
|
*/
|
|
private void EventResolution() {
|
|
|
|
if(currentState.getGameStage()!= GameStages.RESOLVING_EVENT)
|
|
{
|
|
return;
|
|
}
|
|
Queue<EventCard> events;
|
|
events=board.getPendingEvents();
|
|
ArrayList<EventCard>sustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new));
|
|
events.removeAll(sustenance);
|
|
for(EventCard event:events)
|
|
{
|
|
event.activateEvent(playersList);
|
|
}
|
|
|
|
for(EventCard e : sustenance)
|
|
{
|
|
e.activateEvent(playersList);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Advances the game to the next round.
|
|
* The method first resolves pending events.
|
|
* If the current round is 10, the game stage is updated to {@code ENDING} and the game is ended.
|
|
* Otherwise, the era is updated if the board changes era, and the round number is incremented.
|
|
*/
|
|
private void nextRound() {
|
|
|
|
EventResolution();
|
|
if(currentState.getRound()==10)
|
|
{
|
|
currentState.GameStageUpdate(GameStages.ENDING);
|
|
endGame();
|
|
return;
|
|
}
|
|
|
|
if(currentState.getEra()!= board.nextRound()) {
|
|
currentState.EraUpdate();
|
|
}
|
|
|
|
currentState.RoundUpdate();
|
|
|
|
}
|
|
|
|
/**
|
|
* Ends the game by applying all final building effects owned by each player
|
|
* and updating the game stage to {@code ENDED}.
|
|
*/
|
|
private void endGame() {
|
|
playersList.forEach(
|
|
p -> p.buildingCards.stream().filter(x -> x.getEffectType() == EffectType.FINAL).
|
|
forEach(x -> x.applyEffect(p))
|
|
);
|
|
currentState.GameStageUpdate(GameStages.ENDED);
|
|
}
|
|
|
|
/**
|
|
* Sets the configured number of players for this game.
|
|
* The operation succeeds only if the current configured number of players is 0.
|
|
*
|
|
* @param nPlayers the new configured number of players.
|
|
* @return {@code true} if the number of players is updated, {@code false} otherwise.
|
|
*/
|
|
public boolean setNPlayer(int nPlayers) {
|
|
if (this.nPlayers != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (nPlayers < 2 || nPlayers > 5) {
|
|
return false;
|
|
}
|
|
|
|
this.nPlayers = nPlayers;
|
|
|
|
board = new Board(nPlayers);
|
|
|
|
slotMap = new LinkedHashMap<>();
|
|
for (Slot s : board.getSlotList()) {
|
|
slotMap.put(s, null);
|
|
}
|
|
|
|
currentState = new CurrentState();
|
|
playersList = new ArrayList<>();
|
|
OptionalCardQueue = new LinkedList<>();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Prints a string representation of the {@code Game}. Used in the TUI implementation to draw:
|
|
* <li>{@link it.polimi.ingsw.gc14.Model.GamePackage.Board Board}
|
|
* <li>{@link it.polimi.ingsw.gc14.Model.Player Players}
|
|
* <li>{@link #getUpperListTribeCards() Upper TribeCard List} <li>{@link #getUpperListBuilding() Upper Building List}
|
|
* <li>{@link #getLowerListTribeCards() Lower TribeCard List} <li>{@link #getLowerListBuilding() Lower Building List}
|
|
* <li>{@link it.polimi.ingsw.gc14.Model.OrderLogicCard Offer Track}
|
|
*
|
|
* @return {@code String} - a string representation of the {@code Game}.
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
return PlayersStamp()+"\n"+BoardStamp()+"\n";
|
|
}
|
|
public String PlayersStamp()
|
|
{
|
|
StringBuilder stringBuilder=new StringBuilder();
|
|
for(int i=0;i<playersList.size()/2;i++)
|
|
{
|
|
stringBuilder.append(AsciiTable.sideBySide(List.of(playersList.get((i*2)).toString().split("\n")),List.of(playersList.get((i*2+1)).toString().split("\n")),2));
|
|
}
|
|
stringBuilder.append("\n");
|
|
if(playersList.size()%2!=0)
|
|
{
|
|
stringBuilder.append(playersList.get(playersList.size()-1).toString());
|
|
stringBuilder.append("\n");
|
|
}
|
|
return stringBuilder.toString();
|
|
}
|
|
public String BoardStamp()
|
|
{
|
|
var offerTrack = new AsciiTable(BorderStyle.UNICODE, slotMap.size());
|
|
List<String> stringUpOffer=new ArrayList<>();
|
|
List<String> stringDownOffer=new ArrayList<>();
|
|
|
|
int index=0;
|
|
for(Map.Entry<Slot,Player> entry:slotMap.entrySet())
|
|
{
|
|
stringDownOffer.add((index++)+"."+entry.getKey().toStringTUI());
|
|
if(entry.getValue()!=null)
|
|
stringUpOffer.add(entry.getValue().getUserName());
|
|
else
|
|
stringUpOffer.add(" ");
|
|
}
|
|
|
|
var TribeTableUpper = new AsciiTable(BorderStyle.UNICODE,1);
|
|
var TribeTableLower = new AsciiTable(BorderStyle.UNICODE,1);
|
|
|
|
List<String> stringUpperListTribe=new ArrayList<>();
|
|
List<String> stringLowerListTribe=new ArrayList<>();
|
|
stringUpperListTribe.add("Char/Events");
|
|
stringLowerListTribe.add("Char/Events");
|
|
for(int i=0;i<Math.max(getUpperListTribeCards().size(),getLowerListTribeCards().size());i++)
|
|
{
|
|
if(i<getUpperListTribeCards().size())
|
|
{
|
|
stringUpperListTribe.add(i+"-"+getUpperListTribeCards().get(i).toStringBoard());
|
|
}
|
|
if(i<getLowerListTribeCards().size())
|
|
{
|
|
stringLowerListTribe.add(i+"-"+getLowerListTribeCards().get(i).toStringBoard());
|
|
}
|
|
}
|
|
var BuildTableUpper = new AsciiTable(BorderStyle.UNICODE,1);
|
|
BuildTableUpper.addHeader("Building ");
|
|
var BuildTableLower = new AsciiTable(BorderStyle.UNICODE,1);
|
|
BuildTableLower.addHeader("Building ");
|
|
|
|
for(int i=0;i<Math.max(getUpperListBuilding().size(),getLowerListBuilding().size());i++)
|
|
{
|
|
if(i<getUpperListBuilding().size())
|
|
{
|
|
BuildTableUpper.addRow(i+"-"+getUpperListBuilding().get(i).toString());
|
|
}
|
|
if(i<getLowerListBuilding().size())
|
|
{
|
|
BuildTableLower.addRow(i+"-"+getLowerListBuilding().get(i).toString());
|
|
}
|
|
}
|
|
stringUpperListTribe.forEach(x->TribeTableUpper.addRow(x));
|
|
stringLowerListTribe.forEach(x->TribeTableLower.addRow(x));
|
|
offerTrack.addRow(stringUpOffer);
|
|
offerTrack.addRow(stringDownOffer);
|
|
return "CURRENT STATE\n"+getCurrentState()+"\n"+orderLogicCard.toString()+"\n"+ AsciiTable.sideBySide(Arrays.stream((TribeTableUpper.build().split("\n"))).toList(), Arrays.stream(BuildTableUpper.build().split("\n")).toList(),2)+"\n"+offerTrack.build()+"\n"+AsciiTable.sideBySide(List.of(TribeTableLower.build().split("\n")), Arrays.stream(BuildTableLower.build().split("\n")).toList(),2);
|
|
}
|
|
}
|