Coverage Summary for Class: CommonGoalCard (it.polimi.ingsw.Server.Model)

Class Class, % Method, % Line, %
CommonGoalCard 100% (1/1) 100% (11/11) 100% (236/236)


 package it.polimi.ingsw.Server.Model;
 
 import com.google.gson.annotations.Expose;
 import it.polimi.ingsw.Common.CommonGoalCardInterface;
 import it.polimi.ingsw.Common.ScoreCardInterface;
 
 import java.rmi.RemoteException;
 import java.rmi.server.UnicastRemoteObject;
 import java.util.Arrays;
 import java.util.Stack;
 
 /**
  * This class represents the Common Goal cards, thanks to which players may grant points,
  * achieving a specific pattern
  */
 public class CommonGoalCard extends UnicastRemoteObject implements CommonGoalCardInterface {
     /**
      * Limit of Common Goal Cards.
      */
     public static final int LIMIT = 12;
     /**
      * This attribute stands for the id of the Common Goal Card, which permits to
      * identify the different Common Goal Cards.
      */
     @Expose
     private final int type;
 
     /**
      * This attribute stands for a textual description of the pattern that the player has to achieve, in order
      * to gain points.
      */
     @Expose
     private String description;
 
     /**
      * This attribute stands for the deck of ScoreCards on each Common Goal Card, put there
      * from the lowest to the highest value. The size of the Stack varies according to the number of
      * players.
      */
     @Expose
     private Stack<ScoreCard> increments;
 
     /**
      * CommonGoalCard's constructor.
      * New ScoreCards with a value of 2,4,6 or 8 points are pushed into the Stack increments
      * according to the playerCount, from the lowest to the highest score value.
      *
      * @param type        it indicates the id of the Common Goal Card, in order to identify the pattern
      * @param playerCount (2nd parameter) it represents the number of players, according to which
      *                    a different number of ScoreCards are pushed into the Stack
      * @throws Exception if parameters are invalid
      */
     public CommonGoalCard(int type, int playerCount) throws Exception {
         this.type = type;
         if (type <= 0 || type > LIMIT)
             throw new Exception();
 
         increments = new Stack<>();
 
         if (playerCount < 2 || playerCount > 4)
             throw new Exception();
 
         if (playerCount == 4) {
             increments.push(new ScoreCard(2));
         }
         increments.push(new ScoreCard(4));
 
         if (playerCount >= 3) {
             increments.push(new ScoreCard(6));
         }
         increments.push(new ScoreCard(8));
 
         switch (type) {
             case 1 -> description = "Two groups each containing 4 cards of the same type in a 2x2 square. " +
                     "The cards of one square must be of the same type of those of the other square.";
             case 2 -> description = "Two columns each formed by 6 different types of cards.";
             case 3 -> description = "Four groups each containing 4 cards of the same type (in line or in column). " +
                     "The cards of a group can be different from those of another group.";
             case 4 -> description = "Six pairs of cards of the same type. " +
                     "The cards of a group can be different from those of another group.";
             case 5 -> description = "Three columns each formed by 6 cards of maximum three different types. " +
                     "One column can show a different combination of another column.";
             case 6 -> description = "Two lines each formed by 5 different types of cards. " +
                     "One line can show a different combination of the other line.";
             case 7 -> description = "Four lines each formed by five cards of maximum three different types. " +
                     "One line can show a different combination of the other line.";
             case 8 -> description = "Four cards of the same type in the four corners of the shelf.";
             case 9 -> description = "Eight cards of the same type. There's no restriction about the position of " +
                     "these cards.";
             case 10 -> description = "Five cards of the same type forming an X.";
             case 11 -> description = "Five cards of the same type forming a diagonal.";
             case 12 -> description = "Five columns of increasing or decreasing height. Starting from the first " +
                     "column on the left or on the right, each next column must be made of exactly one more " +
                     "card. Cards can be of any type.";
         }
     }
 
     /**
      * Related to Game's refresh strategy
      *
      * @throws RemoteException related to RMI
      */
     private CommonGoalCard(int type, String description, Stack<ScoreCard> increments) throws RemoteException {
         this.type = type;
         this.description = description;
         this.increments = new Stack<>();
         for (ScoreCard sc : increments) {
             this.increments.add(new ScoreCard(sc.getValue()));
         }
     }
 
     /**
      * This method returns the textual description of the pattern that the player has to achieve, in order
      * to gain points.
      *
      * @return String: textual description of the pattern
      */
     public String getDescription() {
         return description;
     }
 
     /**
      * @return Score Increments stack
      */
     public Stack<ScoreCardInterface> getIncrements() {
         Stack<ScoreCardInterface> ret = new Stack<>();
         ret.addAll(increments);
         return ret;
     }
 
 
     /**
      * This method calculates how many points the player has scored, by achieving the pattern which
      * is displayed in the Common Goal Card.
      *
      * @param shelf player's shelf
      * @return score granted by the player, if the pattern displayed by the card has been achieved
      * @throws Exception if coordinates are invalid
      */
     public ScoreCard attribute(Shelf shelf) throws Exception {
         boolean found = false;
         switch (type) {
             case 1 -> {
                 boolean[][] alrInAPattern = new boolean[Shelf.SHELF_DIM_X][Shelf.SHELF_DIM_Y];
                 //Pattern: two groups each containing 4 ObjectCards of the same type in a 2x2 square
                 for (ObjectCardType t : ObjectCardType.values()) {
                     int count = 0;
                     for (int i = 0; i < Shelf.SHELF_DIM_X - 1; i++) {
                         for (int j = 0; j < Shelf.SHELF_DIM_Y - 1; j++) {
                             if (shelf.getCard(i, j).isPresent() &&
                                     shelf.getCard(i, j).get().getType().equals(t) && !alrInAPattern[i][j]) {
                                 if (shelf.getCard(i + 1, j).isPresent() &&
                                         shelf.getCard(i + 1, j).get().getType().equals(t)
                                         && !alrInAPattern[i + 1][j]) {
                                     //check adjacency in the following line
                                     if (shelf.getCard(i, j + 1).isPresent() &&
                                             shelf.getCard(i, j + 1).get().getType().equals(t)
                                             && !alrInAPattern[i][j + 1]) {
                                         if (shelf.getCard(i + 1, j + 1).isPresent() &&
                                                 shelf.getCard(i + 1, j + 1).get().getType().equals(t)
                                                 && !alrInAPattern[i + 1][j + 1]) {
                                             alrInAPattern[i][j] = true;
                                             alrInAPattern[i][j + 1] = true;
                                             alrInAPattern[i + 1][j] = true;
                                             alrInAPattern[i + 1][j + 1] = true;
                                             count++;
                                         }
                                     }
                                 }
                             }
                         }
                     }
                     if (count >= 2) {
                         found = true;
                     }
                 }
             }
             case 2 -> {
                 //two columns each formed by 6 different types of ObjectCards
                 found = findTypesInColumns(6, 6, 2, shelf);
             }
             case 3 -> {
                 if (sameTypeGroupFirstCheck(4, 4, shelf)) {
                     found = true;
                 } else {
                     found = sameTypeGroupSecondCheck(4, 4, shelf);
                 }
 
             }
             case 4 -> {
                 //six pairs of cards of the same type (pairs may have different types)
                 if (sameTypeGroupFirstCheck(2, 6, shelf)) {
                     found = true;
                 } else {
                     found = sameTypeGroupSecondCheck(2, 6, shelf);
                 }
             }
             case 5 -> {
                 //3 columns of 6 cards (max 3 different ObjectCards)
                 found = findTypesInColumns(3, 1, 3, shelf);
             }
             case 6 -> { //two rows with five cards of five different types
                 found = findTypesInRows(5, 5, 2, shelf);
             }
             case 7 -> { //four rows with five cards of (from one to three) different types
                 found = findTypesInRows(3, 1, 4, shelf);
             }
             case 8 -> {
                 //four cards of the same type in the four corners of the shelf
                 if (shelf.getCard(0, 0).isPresent() &&
                         shelf.getCard(0, Shelf.SHELF_DIM_Y - 1).isPresent() &&
                         shelf.getCard(Shelf.SHELF_DIM_X - 1, Shelf.SHELF_DIM_Y - 1).isPresent() &&
                         shelf.getCard(Shelf.SHELF_DIM_X - 1, 0).isPresent()) {
                     if (shelf.getCard(0, 0).get().getType().equals(shelf.getCard(0, Shelf.SHELF_DIM_Y - 1).get().getType())
                             && shelf.getCard(0, 0).get().getType().equals(shelf.getCard(Shelf.SHELF_DIM_X - 1, 0).get().getType()) &&
                             shelf.getCard(0, 0).get().getType().equals(shelf.getCard(Shelf.SHELF_DIM_X - 1, Shelf.SHELF_DIM_Y - 1).get().getType())) {
                         found = true;
                     }
                 }
             }
             case 9 -> {
                 //eight cards of the same type
                 int[] typeCounter = new int[ObjectCardType.values().length];
                 Arrays.fill(typeCounter, 0);
                 for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
                     for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
                         if (shelf.getCard(i, j).isPresent()) {
                             typeCounter[shelf.getCard(i, j).get().getType().ordinal()]++;
                         }
                     }
                 }
                 for (int i = 0; i < ObjectCardType.values().length; i++) {
                     if (typeCounter[i] >= 8) {
                         found = true;
                         break;
                     }
                 }
             }
             case 10 -> {
                 for (int i = 1; i < Shelf.SHELF_DIM_X - 1; i++) {
                     for (int j = 1; j < Shelf.SHELF_DIM_Y - 1; j++) {
                         if (!found) {
                             //cards are present
                             if (shelf.getCard(i, j).isPresent() && shelf.getCard(i - 1, j + 1).isPresent()
                                     && shelf.getCard(i - 1, j - 1).isPresent() && shelf.getCard(i + 1, j - 1).isPresent() &&
                                     shelf.getCard(i + 1, j + 1).isPresent() && shelf.getCard(i, j - 1).isPresent() &&
                                     shelf.getCard(i + 1, j).isPresent() && shelf.getCard(i, j + 1).isPresent()) {
                                 //cards of the same type create an X
                                 if (shelf.getCard(i, j).get().getType().equals(shelf.getCard(i - 1, j + 1).get().getType())
                                         && shelf.getCard(i, j).get().getType().equals(shelf.getCard(i - 1, j - 1).get().getType()) &&
                                         shelf.getCard(i, j).get().getType().equals(shelf.getCard(i + 1, j - 1).get().getType()) &&
                                         shelf.getCard(i, j).get().getType().equals(shelf.getCard(i + 1, j + 1).get().getType()
                                         )) {
                                     //the other 4 cards are of a different type (they don't create a square)
                                     /*if (!shelf.getCard(i, j).get().getType().equals(shelf.getCard(i, j - 1).get().getType()) &&
                                             !shelf.getCard(i, j).get().getType().equals(shelf.getCard(i, j + 1).get().getType())
                                             && !shelf.getCard(i, j).get().getType().equals(shelf.getCard(i + 1, j).get().getType()) &&
                                             (shelf.getCard(i - 1, j).isEmpty() ||
                                                     !shelf.getCard(i, j).get().getType().equals(shelf.getCard(i - 1, j).get().getType()))) {*/
                                     found = true;
                                     // }
                                 }
                             }
                         }
                     }
                 }
             }
             case 11 -> {
                 boolean skipDiag1 = false;
                 boolean skipDiag2 = false;
                 boolean skipDiag3 = false;
                 boolean skipDiag4 = false;
                 for (int i = 0; i < Shelf.SHELF_DIM_X - 2; i++) {
                     for (int j = 0; j < Shelf.SHELF_DIM_Y - 1; j++) {
                         if (i == j) {
                             if (!(!skipDiag1 && shelf.getCard(i, j).isPresent() && shelf.getCard(i + 1, j + 1).isPresent() &&
                                     shelf.getCard(i, j).get().getType().equals(shelf.getCard(i + 1, j + 1).get().getType()))) {
                                 skipDiag1 = true;
                             }
                             if (!(!skipDiag2 && shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).isPresent() &&
                                     shelf.getCard(i + 1, Shelf.SHELF_DIM_Y - j - 2).isPresent() &&
                                     shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).get().getType().equals(shelf.getCard(i + 1, Shelf.SHELF_DIM_Y - j - 2).get().getType()))
                             ) {
                                 skipDiag2 = true;
                             }
                             if (!(!skipDiag3 && shelf.getCard(i + 1, j).isPresent() &&
                                     shelf.getCard(i + 2, j + 1).isPresent() &&
                                     shelf.getCard(i + 1, j).get().getType().equals(shelf.getCard(i + 2, j + 1).get().getType()))) {
                                 skipDiag3 = true;
                             }
                             if (!(!skipDiag4 && shelf.getCard(Shelf.SHELF_DIM_X - i - 1, j).isPresent() &&
                                     shelf.getCard(Shelf.SHELF_DIM_X - i - 2, j + 1).isPresent() &&
                                     shelf.getCard(Shelf.SHELF_DIM_X - i - 1, j).get().getType().equals(shelf.getCard(Shelf.SHELF_DIM_X - i - 2, j + 1).get().getType()))) {
                                 skipDiag4 = true;
                             }
                         }
                     }
                 }
                 if (!skipDiag1 || !skipDiag2 || !skipDiag3 || !skipDiag4) {
                     found = true;
                 }
             }
             case 12 -> {
                 boolean skipDiag1 = false;
                 boolean skipDiag2 = false;
                 boolean skipDiag3 = false;
                 boolean skipDiag4 = false;
                 for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
                     for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
                         if (!(!skipDiag1 && ((i >= j && shelf.getCard(i, j).isPresent()) || (j > i && shelf.getCard(i, j).isEmpty())))) {
                             skipDiag1 = true;
                         }
                         if (!(!skipDiag2 && ((i > j && shelf.getCard(i, j).isPresent()) || (j >= i && shelf.getCard(i, j).isEmpty())))) {
                             skipDiag2 = true;
                         }
                         if (!(!skipDiag3 && ((i >= j && shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).isPresent()) ||
                                 (j > i && shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).isEmpty())))) {
                             skipDiag3 = true;
                         }
                         if (!(!skipDiag4 && ((i > j && shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).isPresent()) ||
                                 (j >= i && shelf.getCard(i, Shelf.SHELF_DIM_Y - j - 1).isEmpty())))) {
                             skipDiag4 = true;
                         }
                     }
                 }
                 if (!skipDiag1 || !skipDiag2 || !skipDiag3 || !skipDiag4) {
                     found = true;
                 }
             }
         }
 
         if (found && !increments.isEmpty()) {
             return increments.pop();
         }
 
         return new ScoreCard(0);
     }
 
 
     /**
      * This method is a support method to attribute() for cards 2 and 5.
      *
      * @param diffTypesMax max number of different types in a column
      * @param diffTypesMin min number of different types in a column
      * @param numOfPattern num of pattern
      * @param shelf        player's shelf
      * @return true if the pattern has been found, false otherwise
      * @throws Exception invalid coordinates
      */
     private boolean findTypesInColumns(int diffTypesMax, int diffTypesMin, int numOfPattern, Shelf shelf) throws Exception {
         int patternCount = 0;
         ObjectCardType[] checkTypes = new ObjectCardType[Shelf.SHELF_DIM_X];
         Arrays.fill(checkTypes, null);
         for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
             if (shelf.getCard(0, j).isPresent()) { //checks the presence of 6 elements in the column
                 for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
                     if (shelf.getCard(i, j).isPresent()) {
                         checkTypes[i] = shelf.getCard(i, j).get().getType();
                     }
                 }
                 if ((Arrays.stream(checkTypes).distinct().count() <= diffTypesMax && Arrays.stream(checkTypes).distinct().count() >= diffTypesMin)) {
                     patternCount++;
                 }
                 Arrays.fill(checkTypes, null);
             }
         }
         return patternCount >= numOfPattern;
     }
 
     /**
      * This method is a support method to attribute() for cards 6 and 7.
      *
      * @param diffTypesMax max number of different types in a line
      * @param diffTypesMin min number of different types in a column
      * @param numOfPattern num of pattern
      * @param shelf        player's shelf
      * @return true if the pattern has been found, false otherwise
      * @throws Exception invalid coordinates
      */
     private boolean findTypesInRows(int diffTypesMax, int diffTypesMin, int numOfPattern, Shelf shelf) throws Exception {
         int patternCount = 0;
         ObjectCardType[] checkTypes = new ObjectCardType[Shelf.SHELF_DIM_Y];
         Arrays.fill(checkTypes, null);
         for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
             int cardCounter = 0;
             for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
                 if (shelf.getCard(i, j).isPresent()) {
                     checkTypes[j] = shelf.getCard(i, j).get().getType();
                     cardCounter++;
                 }
             }
             if (cardCounter == Shelf.SHELF_DIM_Y && Arrays.stream(checkTypes).distinct().count() >= diffTypesMin &&
                     Arrays.stream(checkTypes).distinct().count() <= diffTypesMax) {
 
                 patternCount++;
             }
             Arrays.fill(checkTypes, null);
         }
         return patternCount >= numOfPattern;
     }
 
     /**
      * This method is a support method to attribute() for cards 3 and 4. It checks the
      * presence of groups in lines and then in columns.
      *
      * @param dimOfGroup dimension of each group
      * @param numPattern number of pattern
      * @param shelf      player's shelf
      * @return true if the pattern has been found, false otherwise
      * @throws Exception invalid coordinates
      */
     private boolean sameTypeGroupFirstCheck(int dimOfGroup, int numPattern, Shelf shelf) throws Exception {
         boolean[][] alrInAPattern = new boolean[Shelf.SHELF_DIM_X][Shelf.SHELF_DIM_Y];
         ObjectCardType firstType;
         int foundPattern = 0; //counts how many patterns have been found
         for (int i = 0; i <= Shelf.SHELF_DIM_X - dimOfGroup; i++) {
             for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
                 int sameType = 0; //counts how many adjacent cards have the same type
                 if (shelf.getCard(i, j).isPresent() && !alrInAPattern[i][j]) { //checks adjacency in a column
                     firstType = shelf.getCard(i, j).get().getType();
                     for (int k = 1; k < dimOfGroup; k++) {
                         if (shelf.getCard(i + k, j).isPresent() && shelf.getCard(i + k, j).get().getType().equals(firstType)
                                 && !alrInAPattern[i + k][j]) {
                             sameType++;
                         }
                     }
                     if (sameType == dimOfGroup - 1) {
                         foundPattern++;
                         for (int k = 0; k < dimOfGroup; k++) {
                             alrInAPattern[i + k][j] = true;
                         }
                     }
                 }
             }
         }
         for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
             for (int j = 0; j <= Shelf.SHELF_DIM_Y - dimOfGroup; j++) {
                 int sameType = 0; //counts how many adjacent cards have the same type
                 if (shelf.getCard(i, j).isPresent() && !alrInAPattern[i][j]) {
                     firstType = shelf.getCard(i, j).get().getType();
                     for (int k = 1; k < dimOfGroup; k++) {
                         if (shelf.getCard(i, j + k).isPresent() && shelf.getCard(i, j + k).get().getType().equals(firstType)
                                 && !alrInAPattern[i][j + k]) {
                             sameType++;
                         }
                     }
                     if (sameType == dimOfGroup - 1) {
                         foundPattern++;
                         for (int k = 0; k < dimOfGroup; k++) {
                             alrInAPattern[i][j + k] = true;
                         }
                     }
                 }
             }
         }
         return foundPattern >= numPattern;
     }
 
     /**
      * This method is a support method to attribute() for cards 3 and 4. It checks the
      * presence of groups in columns and then in lines.
      *
      * @param dimOfGroup dimension of each group
      * @param numPattern number of patterns
      * @param shelf      player's shelf
      * @return true if the pattern has been found, false otherwise
      * @throws Exception invalid coordinates
      */
     private boolean sameTypeGroupSecondCheck(int dimOfGroup, int numPattern, Shelf shelf) throws Exception {
         boolean[][] alrInAPattern = new boolean[Shelf.SHELF_DIM_X][Shelf.SHELF_DIM_Y];
         ObjectCardType firstType;
         int foundPattern = 0; //counts how many patterns have been found
         for (int i = 0; i < Shelf.SHELF_DIM_X; i++) {
             for (int j = 0; j <= Shelf.SHELF_DIM_Y - dimOfGroup; j++) {
                 int sameType = 0; //counts how many adjacent cards have the same type
                 if (shelf.getCard(i, j).isPresent() && !alrInAPattern[i][j]) {
                     firstType = shelf.getCard(i, j).get().getType();
                     for (int k = 1; k < dimOfGroup; k++) {
                         if (shelf.getCard(i, j + k).isPresent() && shelf.getCard(i, j + k).get().getType().equals(firstType)
                                 && !alrInAPattern[i][j + k]) {
                             sameType++;
                         }
                     }
                     if (sameType == dimOfGroup - 1) {
                         foundPattern++;
                         for (int k = 0; k < dimOfGroup; k++) {
                             alrInAPattern[i][j + k] = true;
                         }
                     }
                 }
             }
         }
         for (int i = 0; i <= Shelf.SHELF_DIM_X - dimOfGroup; i++) {
             for (int j = 0; j < Shelf.SHELF_DIM_Y; j++) {
                 int sameType = 0; //counts how many adjacent cards have the same type
                 if (shelf.getCard(i, j).isPresent() && !alrInAPattern[i][j]) { //checks adjacency in a column
                     firstType = shelf.getCard(i, j).get().getType();
                     for (int k = 1; k < dimOfGroup; k++) {
                         if (shelf.getCard(i + k, j).isPresent() && shelf.getCard(i + k, j).get().getType().equals(firstType)
                                 && !alrInAPattern[i + k][j]) {
                             sameType++;
                         }
                     }
                     if (sameType == dimOfGroup - 1) {
                         foundPattern++;
                         for (int k = 0; k < dimOfGroup; k++) {
                             alrInAPattern[i + k][j] = true;
                         }
                     }
                 }
             }
         }
         return foundPattern >= numPattern;
     }
 
     /**
      * Refreshed copy, after server reload from file
      *
      * @return new copy of the object
      * @throws RemoteException related to RMI
      */
     public CommonGoalCard getCopy() throws RemoteException {
         return new CommonGoalCard(this.type, this.description, this.increments);
     }
 
     /**
      * Common Goal Card's type (ordinal)
      *
      * @return type
      * @throws RemoteException related to RMI
      */
     public int getType() throws RemoteException {
         return type;
     }
 }