Files
Progetto-ingegneria-del-sof…/src/main/java/it/polimi/ingsw/gc14/Model/Game.java
T

983 lines
36 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.CharacterType;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Builder;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Inventor;
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 java.util.stream.Stream;
/**
* 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 {
/**
* Returns the list of players participating in the game.
*
* @return a copy of the list of players currently participating in the game.
*/
public List<Player> getPlayers() {
return playersList;
}
//TODO
public List<Totems>getAvailableTotems() {
List<Totems> totems=new ArrayList<>(List.of(Totems.values()));
playersList.forEach(player -> {if(player.totem!=null)totems.remove(player.totem);});
return totems;
}
//TODO
private Queue<Player> totemChoiceQueue = new LinkedList<>();
//TODO
public boolean TotemChoice(Player player,Totems totem) {
if(!currentState.getGameStage().equals(GameStages.TOTEM_CHOICE))
return false;
if(!getCurrentState().getCurrentPlayer().equals(player))
return false;
if(!getAvailableTotems().contains(totem))
{
return false;
}
player.totem=totem;
Player nextPlayer= totemChoiceQueue.poll();
if(nextPlayer==null)
{
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
currentState.PlayerUpdate(orderLogicCard.pull(),null);
}
else
{
while(disconnetedPlayers.containsKey(nextPlayer)&& disconnetedPlayers.get(nextPlayer))
{
nextPlayer.totem=getAvailableTotems().get(new Random().nextInt(getAvailableTotems().size()-1));
nextPlayer=totemChoiceQueue.poll();
if(nextPlayer==null)
{
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
currentState.PlayerUpdate(orderLogicCard.pull(),null);
return true;
}
}
currentState.PlayerUpdate(nextPlayer,null);
}
return true;
}
//TODO
public Map<Player,Boolean> disconnetedPlayers = new HashMap<>();
//TODO
public boolean DisconnectedPlayer(Player player)
{
if(disconnetedPlayers.containsKey(player) && disconnetedPlayers.get(player))
{
return false;
}
disconnetedPlayers.put(player,true);
if(currentState.getCurrentPlayer().equals(player))
if(!currentState.getGameStage().equals(GameStages.TOTEM_CHOICE))
nextPlayerSetup();
else
{
if(totemChoiceQueue.isEmpty())
{
player.totem=getAvailableTotems().get(new Random().nextInt(getAvailableTotems().size()-1));
}
else {
totemChoiceQueue.add(player);
}
currentState.PlayerUpdate(totemChoiceQueue.poll(),null);
}
return true;
}
//TODO
public boolean ReconnectPlayer(Player player)
{
if(!disconnetedPlayers.containsKey(player))
{
return false;
}
disconnetedPlayers.put(player,false);
if(currentState.getGameStage().equals(GameStages.SLOT_CHOICE) )
{
disconnetedPlayers.remove(player);
if(!orderLogicCard.players.contains(player))
{
orderLogicCard.pushNoEffect(player);
}
}
return true;
}
//Totem
//TODO
public void ClearDisconnected()
{
disconnetedPlayers.clear();
}
/**
* Returns the current number of players participating in the game.
* @return 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;
/**
* Returns the map of slots assigned to players.
*
* @return the map that associates each slot with the corresponding player.
*/
public HashMap<Slot,Player> getSlotMap() {return 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.
*/
public OrderLogicCard orderLogicCard;
/**
* The board associated with this game.
*/
private Board board;
//TODO
public Board getBoard() {return 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.
* @throws IndexOutOfBoundsException if an index access error occurs.
*/
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);
totemChoiceQueue.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;
}
for(Player player : playersList)
{
switch(orderLogicCard.getPosition(player.getUserName()))
{
case 0: player.addFood(2); break;
case 1,2: player.addFood(3); break;
case 3,4: player.addFood(4); break;
}
}
currentState.PlayerUpdate(totemChoiceQueue.poll(),null);
currentState.GameStageUpdate(GameStages.TOTEM_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;
}
if(slotPlayerEntry.getKey().getSlotId()=='A')
{
player.addFood(3);
}
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.RES_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;
}
/**
* Skips the turn for the specified player when no drawable cards are available.
* The operation succeeds only if the current game stage is {@code RESOLVING_ACTIONS},
* the specified player is the current player,
* and the player can't draw tribe card (i.e. all remaining lower tribe cards are event cards).
* @param player the player skipping the turn .
* @return {@code true} if the skip succeeds, {@code false} otherwise.
*/
public boolean SkipNoDrawable(Player player) {
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
if(!player.equals(currentState.getCurrentPlayer()))
{
return false;
}
if(hasDrawableDown() && currentState.getNLower()>0 )
return false;
if(hasDrawableUp() && currentState.getNUpper()>0)
return false;
while(currentState.getNLower()>0)
currentState.LowerDrawn();
while(currentState.getNUpper()>0)
currentState.UpperDrawn();
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.RES_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.RES_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.RES_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.OPT_CARD_E){
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.OPT_CARD_E){
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.OPT_CARD_E){
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(disconnetedPlayers.containsKey(tempPlayer) && disconnetedPlayers.get(tempPlayer)) {
nextPlayerSetup();
return;
}
if (tempPlayer != null) {
currentState.PlayerUpdate(tempPlayer, null);
return;
}
// All players have chosen a slot → switch to RES_ACTIONS
currentState.GameStageUpdate(GameStages.RES_ACTIONS);
boolean anyAssigned = false;
for (Slot s : slotMap.keySet()) {
if (slotMap.get(s) != null) {
currentState.PlayerUpdate(slotMap.get(s), s);
boolean hasDrawableLower = currentState.getNLower() > 0
&& (hasDrawableDown() || !getLowerListBuilding().isEmpty());
boolean hasDrawableUpper = currentState.getNUpper() > 0
&& (hasDrawableUp() || !getUpperListBuilding().isEmpty());
if (!hasDrawableLower && !hasDrawableUpper) {
// This player has nothing drawable, skip them immediately
orderLogicCard.push(currentState.getCurrentPlayer());
slotMap.put(currentState.getSlot(), null);
} else {
anyAssigned = true;
break;
}
}
}
// If every player was skipped, jump straight to optional phase
if (!anyAssigned) {
transitionToOptionalOrNextRound();
}
return;
}
if (GameStages.RES_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(disconnetedPlayers.containsKey(currentState.getCurrentPlayer())&& disconnetedPlayers.get(currentState.getCurrentPlayer()))
{
slotMap.put(currentState.getSlot(), null);
continue;
}
boolean hasDrawableLower = currentState.getNLower() > 0
&& (hasDrawableDown() || !getLowerListBuilding().isEmpty());
boolean hasDrawableUpper = currentState.getNUpper() > 0
&& (hasDrawableUp() || !getUpperListBuilding().isEmpty());
if (!hasDrawableLower && !hasDrawableUpper) {
// This player also has nothing, skip and continue the loop
orderLogicCard.push(currentState.getCurrentPlayer());
slotMap.put(currentState.getSlot(), null);
} else {
// Found a player with something to do, stop here
return;
}
}
}
// All slots are now null → every player is done for this round
transitionToOptionalOrNextRound();
return;
}
if (GameStages.OPT_CARD_E == currentState.getGameStage()) {
Player optionalPlayer = OptionalCardQueue.poll();
if (optionalPlayer != null) {
currentState.PlayerUpdate(optionalPlayer, null);
if(disconnetedPlayers.containsKey(currentState.getCurrentPlayer())&& disconnetedPlayers.get(currentState.getCurrentPlayer())) {
nextPlayerSetup();
}
return;
}
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
}
}
//TODO
private void transitionToOptionalOrNextRound() {
currentState.GameStageUpdate(GameStages.OPT_CARD_E);
OptionalCardQueue = new LinkedList<>();
for (Player p : orderLogicCard.players) {
long count = p.buildingCards.stream().filter(x -> x.getEffectId() == 12).count();
if (count > 0) {
OptionalCardQueue.add(p);
}
}
Player optionalPlayer = OptionalCardQueue.poll();
if (optionalPlayer != null) {
currentState.PlayerUpdate(optionalPlayer, null);
return;
}
// Nobody has optional cards → go straight to event resolution
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
for(Map.Entry<Player,Boolean> entry: disconnetedPlayers.entrySet())
{
if(!entry.getValue())
{
orderLogicCard.pushNoEffect(entry.getKey());
disconnetedPlayers.remove(entry.getKey());
}
}
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
}
/**
* Checks whether there are any drawable upper tribe cards on the board,
* i.e. upper tribe cards that are not event cards.
*
* @return {@code true} if at least one non-event upper tribe card is available, {@code false} otherwise.
*/
private boolean hasDrawableUp()
{
return getUpperListTribeCards().stream().anyMatch(x -> !x.IsEventCard());
}
/**
* Checks whether there are any drawable lower tribe cards on the board,
* i.e. lower tribe cards that are not event cards.
*
* @return {@code true} if at least one non-event lower tribe card is available, {@code false} otherwise.
*/
private boolean hasDrawableDown()
{
return getLowerListTribeCards().stream().anyMatch(x -> !x.IsEventCard());
}
/**
* 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.RES_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() {
Queue<EventCard> events;
events=Stream.concat(board.lowerListTribe.stream().filter(TribeCard::IsEventCard),board.upperListTribe.stream().filter(TribeCard::IsEventCard)).map(x->((EventCard)x)).collect(Collectors.toCollection(LinkedList::new));
ArrayList<EventCard>sustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new));
events.removeAll(sustenance);
events.forEach(event->event.activateEvent(playersList));
sustenance.forEach(event->event.activateEvent(playersList));
playersList.forEach(p->{
int temp= p.builders.stream().mapToInt(Builder::getPrestigeValue).sum();
p.addPrestige(temp);
});
playersList.forEach(p->{
int temp=(int) p.inventors.stream().mapToInt(Inventor::Icon).distinct().count();
p.addPrestige(temp*p.getNType(CharacterType.INVENTOR));
});
playersList.forEach(p->{
p.addPrestige(10 * (p.getNType(CharacterType.ARTIST)/2));
});
playersList.forEach(p->{
int temp= p.buildingCards.stream().mapToInt(BuildingCard::getPrestigeValue).sum();
p.addPrestige(temp);
});
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;
}
}