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

Class Class, % Method, % Line, %
Shelf 100% (1/1) 100% (14/14) 90,2% (119/132)


 package it.polimi.ingsw.Server.Model;
 
 import com.google.gson.annotations.Expose;
 import it.polimi.ingsw.Common.ShelfInterface;
 
 import java.rmi.RemoteException;
 import java.rmi.server.UnicastRemoteObject;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
  * Player's Shelf
  */
 public class Shelf extends UnicastRemoteObject implements ShelfInterface {
     /**
      * Maximum X dimension of the shelf
      */
     public static final int SHELF_DIM_X = 6;
     /**
      * Maximum Y dimension of the shelf
      */
     public static final int SHELF_DIM_Y = 5;
     /**
      * Shelf implementation of Object Cards
      */
     @Expose
     private Optional<ObjectCard>[][] cards;
 
     /**
      * Manages creation of the shelf (filling with empty values)
      *
      * @throws RemoteException related to RMI
      */
     public Shelf() throws RemoteException {
         cards = new Optional[SHELF_DIM_X][SHELF_DIM_Y];
         for (Optional<ObjectCard>[] r : cards)
             Arrays.fill(r, Optional.empty());
     }
 
     /**
      * Related to Game's refresh strategy
      */
     private Shelf(Optional<ObjectCard>[][] cards) throws RemoteException {
         this.cards = cards;
     }
 
     /**
      * Returns a list of effectively present cards on the board, based on a functional approach using Optionals.
      *
      * @return list of cards in the shelf
      */
     public List<ObjectCard> shelfCards() {
         return Stream.of(cards)
                 .flatMap(Stream::of)
                 .filter(Optional::isPresent)
                 .map(Optional::orElseThrow)
                 .collect(Collectors.toList());
     }
 
     /**
      * gets Object Card in position (x, y) if valid (else empty)
      *
      * @param x coordinate
      * @param y coordinate
      * @return requested ObjectCard
      * @throws Exception if coordinates are invalid
      */
     public Optional<ObjectCard> getCard(int x, int y) throws Exception {
         if (x >= 0 && x <= SHELF_DIM_X - 1 && y >= 0 && y <= SHELF_DIM_Y - 1)
             return cards[x][y];
         else throw new Exception();
     }
 
     /**
      * gets Object Card in position (x, y) if valid (else null)
      *
      * @param x coordinate
      * @param y coordinate
      * @return requested ObjectCard
      * @throws Exception if coordinates are invalid
      */
     public ObjectCard getPlainCard(int x, int y) throws Exception {
         if (x >= 0 && x <= SHELF_DIM_X - 1 && y >= 0 && y <= SHELF_DIM_Y - 1)
             return cards[x][y].orElse(null);
         else throw new Exception();
     }
 
 
     /**
      * Returns Object Card's type ordinal in position (x, y) if valid (else -1)
      *
      * @param x coordinate
      * @param y coordinate
      * @return requested Object Card's type ordinal
      * @throws Exception if coordinates are invalid
      */
     public int getCardOrdinal(int x, int y) throws Exception {
         if (x >= 0 && x <= SHELF_DIM_X - 1 && y >= 0 && y <= SHELF_DIM_Y - 1)
             if (cards[x][y].isPresent())
                 return cards[x][y].get().getType().ordinal();
             else return -1;
         else throw new Exception();
     }
 
     /**
      * Returns Object Card's image path in position (x, y) if valid (else null)
      *
      * @param x coordinate
      * @param y coordinate
      * @return the card's image path
      * @throws Exception if parameters are trying to go out of the board
      */
     public String getCardImage(int x, int y) throws Exception {
         if (x >= 0 && x <= SHELF_DIM_X - 1 && y >= 0 && y <= SHELF_DIM_Y - 1)
             if (cards[x][y].isPresent())
                 return cards[x][y].get().getType().name().concat("-").concat(String.valueOf(cards[x][y].get().getImage()));
             else return null;
         else throw new Exception();
     }
 
     /**
      * Looks for coordinates of a given card (x, y)
      *
      * @param oc the Object Card to be found
      * @param X  kind of coordinate: X = true means x coordinate, false y
      * @return coordinate of the given card
      * @throws Exception related to invalid coordinates in getCard method
      */
     public int getCoordinate(ObjectCard oc, boolean X) throws Exception {
         if (oc == null || !shelfCards().contains(oc))
             return -1;
         for (int i = 0; i < SHELF_DIM_X; i++) {
             for (int j = 0; j < SHELF_DIM_Y; j++) {
                 if (getCard(i, j).isPresent() && oc.equals(getCard(i, j).get())) {
                     if (X)
                         return i;
                     else return j;
                 }
             }
         }
         return -1;
     }
 
     /**
      * Inserts a card into the shelf at the selected column (y)
      *
      * @param oc ObjectCard to insert
      * @param y  number of column to use
      * @throws Exception newly defined exception to manage error related to Shelf Insertion
      */
     public void placeCard(ObjectCard oc, int y) throws Exception {
         if (y < 0 || y >= SHELF_DIM_Y)
             throw new Exception("Inexistent column");
         if (cards[0][y].isPresent())
             throw new Exception("Selected column is full");
         for (int i = 0; i < SHELF_DIM_X; i++) {
             if (cards[SHELF_DIM_X - i - 1][y].isEmpty()) {
                 cards[SHELF_DIM_X - i - 1][y] = Optional.of(oc);
                 return;
             }
         }
         throw new Exception("Unable to insert new card in selected column");
     }
 
     /**
      * Evaluates score for a PersonalGoalCard
      *
      * @param pgCard Personal Goal Card
      * @return corresponding score
      */
     public int evaluatePattern(PersonalGoalCard pgCard) {
         int counter = 0;
         Optional<ObjectCardType>[][] pattern = pgCard.getPattern();
         for (int i = 0; i < SHELF_DIM_X; i++) {
             for (int j = 0; j < SHELF_DIM_Y; j++) {
                 if (pattern[i][j].isPresent() && cards[i][j].isPresent() && pattern[i][j].get().equals(cards[i][j].get().getType())) {
                     counter++;
                 }
             }
         }
         if (counter == 1 || counter == 2)
             return counter;
         if (counter == 3)
             return 4;
         if (counter == 4)
             return 6;
         if (counter == 5)
             return 9;
         if (counter == 6)
             return 12;
         return 0;
     }
 
     /**
      * Implements final evaluation of groups of Object Cards used at the end of the game
      *
      * @return score obtained for current shelf
      * @throws Exception related to invalid coordinates in getCard method
      */
     public int finalEvaluation() throws Exception {
         int ret = 0;
         for (ObjectCardType t : ObjectCardType.values()) {
             List<Integer> groupsTotal = new ArrayList<>();
             Set<ObjectCard> nextToCheck = new HashSet<>();
             Set<ObjectCard> checked = new HashSet<>();
             int localCounter = 0;
 
             for (int i = 0; i < SHELF_DIM_X; i++) {
                 for (int j = 0; j < SHELF_DIM_Y; j++) {
                     if (this.getCard(i, j).isPresent() && (checked.contains(this.getCard(i, j).get()) || !this.getCard(i, j).get().getType().equals(t))) {
                         continue;
                     }
                     if (i >= 1) {
                         if (this.getCard(i - 1, j).isPresent() && this.getCard(i - 1, j).get().getType().equals(t) && !checked.contains(this.getCard(i - 1, j).get())) {
                             nextToCheck.add(this.getCard(i - 1, j).get());
                         }
                     }
                     if (i <= SHELF_DIM_X - 2) {
                         if (this.getCard(i + 1, j).isPresent() && this.getCard(i + 1, j).get().getType().equals(t) && !checked.contains(this.getCard(i + 1, j).get())) {
                             nextToCheck.add(this.getCard(i + 1, j).get());
                         }
                     }
                     if (j >= 1) {
                         if (this.getCard(i, j - 1).isPresent() && this.getCard(i, j - 1).get().getType().equals(t) && !checked.contains(this.getCard(i, j - 1).get())) {
                             nextToCheck.add(this.getCard(i, j - 1).get());
                         }
                     }
                     if (j <= SHELF_DIM_Y - 2) {
                         if (this.getCard(i, j + 1).isPresent() && this.getCard(i, j + 1).get().getType().equals(t) && !checked.contains(this.getCard(i, j + 1).get())) {
                             nextToCheck.add(this.getCard(i, j + 1).get());
                         }
                     }
                     if (this.getCard(i, j).isPresent()) {
                         checked.add(this.getCard(i, j).get());
                         localCounter++;
                     } else continue;
                     while (nextToCheck.size() >= 1) {
                         ArrayList<ObjectCard> support = new ArrayList<>(nextToCheck);
                         if (checked.contains(support.get(0))) {
                             nextToCheck.remove(support.get(0));
                             continue;
                         }
                         localCounter++;
                         int I = this.getCoordinate(support.get(0), true);
                         int J = this.getCoordinate(support.get(0), false);
                         if (I >= 1) {
                             if (this.getCard(I - 1, J).isPresent() && this.getCard(I - 1, J).get().getType().equals(t) && !checked.contains(this.getCard(I - 1, J).get())) {
                                 nextToCheck.add(this.getCard(I - 1, J).get());
                             }
                         }
                         if (I <= SHELF_DIM_X - 2) {
                             if (this.getCard(I + 1, J).isPresent() && this.getCard(I + 1, J).get().getType().equals(t) && !checked.contains(this.getCard(I + 1, J).get())) {
                                 nextToCheck.add(this.getCard(I + 1, J).get());
                             }
                         }
                         if (J >= 1) {
                             if (this.getCard(I, J - 1).isPresent() && this.getCard(I, J - 1).get().getType().equals(t) && !checked.contains(this.getCard(I, J - 1).get())) {
                                 nextToCheck.add(this.getCard(I, J - 1).get());
                             }
                         }
                         if (J <= SHELF_DIM_Y - 2) {
                             if (this.getCard(I, J + 1).isPresent() && this.getCard(I, J + 1).get().getType().equals(t) && !checked.contains(this.getCard(I, J + 1).get())) {
                                 nextToCheck.add(this.getCard(I, J + 1).get());
                             }
                         }
                         checked.add(support.get(0));
                         nextToCheck.remove(support.get(0));
                     }
                     groupsTotal.add(localCounter);
                     localCounter = 0;
                 }
             }
             for (Integer total : groupsTotal) {
                 if (total == 3)
                     ret += 2;
                 if (total == 4)
                     ret += 3;
                 if (total == 5)
                     ret += 5;
                 if (total >= 6)
                     ret += 8;
             }
         }
 
         return ret;
     }
 
     /**
      * @return true if the Shelf is full
      */
     public boolean isFull() {
         return Arrays.stream(cards)
                 .flatMap(Arrays::stream)
                 .noneMatch(Optional::isEmpty);
     }
 
     /**
      * Calculates the number of empty spaces in the selected column
      *
      * @param column in the Shelf
      * @return number of empty spaces in the column
      * @throws Exception if given column is invalid
      */
     public int emptySpacesInColumn(int column) throws Exception {
         if (column < 0 || column >= SHELF_DIM_Y)
             throw new Exception();
         return ((Long) (Arrays.stream(cards)
                 .map(r -> r[column])
                 .filter(Optional::isEmpty)
                 .count())).intValue();
     }
 
     /**
      * Refreshed copy, after server reload from file
      *
      * @return new copy of the object
      * @throws RemoteException related to RMI
      */
     public Shelf getCopy() throws RemoteException {
         return new Shelf(cards);
     }
 }