package it.polimi.ingsw.gc14.Model; import it.polimi.ingsw.gc14.Model.Cards.BuildingCard; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.*; import it.polimi.ingsw.gc14.View.TUI.AsciiTable; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; import static it.polimi.ingsw.gc14.View.TUI.BorderStyle.*; /** * Default Player class; contains all identifiers and methods needed. */ public class Player implements Serializable { /** * The maximum length allowed for the username string. */ private static final int MAX_USERNAME_LENGTH = 32; /** * Identifier for the {@code Player} when displaying the game through the GUI. * @see Totems */ private Totems totem; // region Getters /** * Unique string identifier for players; must not be {@code null} and must not * exceed {@link #MAX_USERNAME_LENGTH} otherwise an {@link IllegalArgumentException} will be thrown * when the {@link #Player(String) constructor} is called. */ private final String userName; /** * Getter for the private attribute {@link #userName}. * @return {@code String} - The UserName */ public String getUserName() { return userName; } /** * Returns the totem assigned to this player. * * @return this player's totem. */ public Totems getTotem() { return totem; } /** * Counts the total {@link it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character Character Cards} * the player currently possesses. * @return {@code int} - Total Character Cards. */ public int getTotCharacters() { return Arrays.stream(CharacterType.values()) .mapToInt(this::getNType) .sum(); } /** * Counts the total number of cards of the specified {@link it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType Character Type}. * Character Type must not be {@code null} * @param type the Character Type to be Counted. * @return {@code int} - Total number of cards of given {@code type}. */ public int getNType(CharacterType type) { return switch (type) { case ARTIST -> artists.size(); case INVENTOR -> inventors.size(); case HUNTER -> hunters.size(); case BUILDER -> builders.size(); case SHAMAN -> shamans.size(); case GATHERER -> gatherers.size(); }; } private final ArrayList buildingCards; private final ArrayList artists; private final ArrayList builders; private final ArrayList inventors; private final ArrayList gatherers; private final ArrayList shamans; private final ArrayList hunters; /** @return this player's building cards. */ public ArrayList getBuildingCards() { return buildingCards; } /** @return this player's Artist character cards. */ public ArrayList getArtists() { return artists; } /** @return this player's Builder character cards. */ public ArrayList getBuilders() { return builders; } /** @return this player's Inventor character cards. */ public ArrayList getInventors() { return inventors; } /** @return this player's Gatherer character cards. */ public ArrayList getGatherers() { return gatherers; } /** @return this player's Shaman character cards. */ public ArrayList getShamans() { return shamans; } /** @return this player's Hunter character cards. */ public ArrayList getHunters() { return hunters; } /** * The current amount of {@code Food} the Player possesses. * Cannot be negative. */ private int foodValue; /** * Getter for the private attribute {@link #foodValue}. * @return {@code int} - The amount of Food the player possesses. */ public int getFoodValue() { return foodValue; } /** * The current amount of {@code Prestige} the Player possesses. */ private int prestigeValue; /** * Getter for the private attribute {@link #prestigeValue}. * @return {@code int} - The amount of Prestige the Player possesses. */ public int getPrestigeValue() { return prestigeValue; } // endregion getters // region Setters /** * Adds {@code value} amount of Food to the Player. * @param value The amount of Food to be added. Should be non-negative. * @see #foodValue */ public void addFood(int value){ this.foodValue += value; } /** * Sets the totem for this player. * * @param totem the totem to assign. */ public void setTotem(Totems totem) { this.totem = totem; } /** * Removes {@code value} amount of Food from the Player. * {@link #foodValue} cannot go negative: returns {@code false} if * {@code value} exceeds the current food and leaves the value unchanged. * * @param value The amount of Food to be removed. Should be non-negative. * @return {@code true} if the Food is successfully removed, {@code false} otherwise. * @see #foodValue */ public boolean removeFood(int value){ if(value > this.foodValue){ return false; } this.foodValue -= value; return true; } /** * Adds {@code value} amount of Prestige to the Player. * @param value The amount of Prestige to be added. Should be non-negative. * @see #prestigeValue */ public void addPrestige(int value){ this.prestigeValue += value; } /** * Removes {@code value} amount of Prestige from the Player. * @param value The amount of Prestige to be removed. Should be non-negative. * @see #prestigeValue */ public void removePrestige(int value){ this.prestigeValue -= value; } // endregion setters // region Constructors /** * Constructor for the class {@code Player}. Each Player is uniquely identified by the {@link #userName}. * * @param userName Unique String identifier for a Player. * @throws IllegalArgumentException when {@code userName} is empty or exceeds {@link #MAX_USERNAME_LENGTH}, * with message: *
{@code UserName is empty or exceeds maximum permitted length.}
* * @see #userName * @see #MAX_USERNAME_LENGTH */ public Player(String userName) throws IllegalArgumentException { if(userName.isEmpty() || userName.length() > MAX_USERNAME_LENGTH) { throw new IllegalArgumentException("UserName is empty or exceeds maximum permitted length."); } this.userName = userName; this.inventors = new ArrayList <>(); this.builders = new ArrayList <>(); this.gatherers = new ArrayList <>(); this.shamans = new ArrayList <>(); this.hunters = new ArrayList <>(); this.artists = new ArrayList<>(); this.buildingCards = new ArrayList<>(); this.foodValue = 0; this.prestigeValue = 0; this.totem = null; } // endregion constructors // region Functions /** * Checks equality between this {@code Player} and another object. * Two players are equal if and only if they share the same {@code userName}. * * @param obj the object to compare with. * @return {@code true} if {@code obj} is a {@code Player} with the same username; {@code false} otherwise. */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof Player)) return false; return userName.equals(((Player) obj).userName); } @Override public int hashCode() { return userName.hashCode(); } /** * Prints the {@code Player}'s attributes for the {@code Board}'s representation. * Uses the {@code UNICODE} border style. *

Includes: *

  • {@link #foodValue Food} *
  • {@link #prestigeValue Prestige} *
  • {@link #artists Artists} *
  • {@link #builders Builders} *
  • {@link #gatherers Gatherers} *
  • {@link #shamans Shamans} *
  • {@link #inventors Inventors} *
  • {@link #hunters Hunters} *
  • {@link #buildingCards Buildings} *

    * @return {@code String} - A string representation of the {@code Player}'s attributes. * @see it.polimi.ingsw.gc14.View.TUI.BorderStyle BorderStyle */ @Override public String toString() { int last; var table = new AsciiTable(ROUNDED, 1); String totemStr = (this.totem != null) ? " (" + this.totem + ")" : ""; table.addHeader(this.getUserName() + totemStr + " | \uD83C\uDF56:" + this.getFoodValue() + " | \uD83C\uDFC5:" + this.getPrestigeValue()); table.addSeparator(); if(!this.hunters.isEmpty()){ last = 6; } else if(!this.inventors.isEmpty()){ last = 5; } else if(!this.shamans.isEmpty()){ last = 4; } else if(!this.gatherers.isEmpty()){ last = 3; } else if(!this.builders.isEmpty()){ last = 2; } else if(!this.artists.isEmpty()){ last = 1; } else{ last = 0; } if(last == 0){ table.addSeparator(); } table.addRow("CHARACTERS"); if(!this.artists.isEmpty()){ table.addRow(this.artists.size() + " Artists: \uD83C\uDFA8:" + this.artists.size()); if(last == 1){ table.addSeparator(); } } if(!this.builders.isEmpty()){ table.addRow(this.builders.size() + " Builders: " + "\uD83D\uDD28:" + this.builders.stream().mapToInt(Builder::getReductionValue).sum() + " \uD83C\uDFC5:" + this.builders.stream().mapToInt(Builder::getPrestigeValue).sum()); if(last == 2){ table.addSeparator(); } } if(!this.gatherers.isEmpty()){ table.addRow(this.gatherers.size() + " Gatherers: \uD83C\uDF56:" + 3*this.gatherers.size()); if(last == 3){ table.addSeparator(); } } if(!this.shamans.isEmpty()){ table.addRow(this.shamans.size() + " Shamans: " + "\uD83C\uDF1F:" + this.shamans.stream().mapToInt(Shaman::getIcon).sum()); if(last == 4){ table.addSeparator(); } } if(!this.inventors.isEmpty()){ table.addRow(this.inventors.size() + " Inventors: " + this.inventors.stream() .collect(Collectors.groupingBy( Inventor::getIcon, Collectors.counting() )) .entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(e -> e.getKey() + ":" + e.getValue()) .collect(Collectors.joining(", "))); if(last == 5){ table.addSeparator(); } } if(!this.hunters.isEmpty()){ table.addRow(this.hunters.size() + " Hunters: \uD83C\uDF56" + this.hunters.stream().filter(Hunter::getIcon).count()); table.addSeparator(); } table.addSeparator(); table.addRow("BUILDING CARDS" + (this.buildingCards.stream().mapToInt(BuildingCard::getPrestigeValue).sum() != 0 ? " \uD83C\uDFC5:" + this.buildingCards.stream().mapToInt(BuildingCard::getPrestigeValue).sum() : "")); if(!this.buildingCards.isEmpty()){ table.addRow(this.buildingCards.size() + " Buildings: " + this.buildingCards.stream().map(BuildingCard::toStringPlayer).collect(Collectors.joining(", "))); } return table.build(); } // endregion functions }