package ch.zhaw.catan; import ch.zhaw.catan.Config.Land; import ch.zhaw.hexboard.HexBoard; import ch.zhaw.hexboard.Label; import java.awt.Point; import java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Iterator; import java.util.Collections; //TODO Enhance JavaDoc /** * Subclass of HexBoard * Saves the fields which are set and handles Methods with specific Dice Numbers. */ public class SiedlerBoard extends HexBoard { /** * HashMap to save all Fields which are set yet. * Key: Point with coordinates of the field * //TODO Enhance JavaDoc * Value: Field Object */ HashMap fields = new HashMap<>(); Config.Faction longestRoadFaction = null; int longestRoadLenth = 0; /** * Method to create the predefined game field from Config. */ public void createFixGameField() { Map resourcePlacement = Config.getStandardLandPlacement(); Map dicePlacement = Config.getStandardDiceNumberPlacement(); for (Map.Entry resourceField : resourcePlacement.entrySet()) { addField(resourceField.getKey(), resourceField.getValue()); if (dicePlacement.get(resourceField.getKey()) != null) { String numberAsString = dicePlacement.get(resourceField.getKey()).toString(); char[] numbersInChar = numberAsString.toCharArray(); if (numberAsString.length() < 2) { fields.put(resourceField.getKey(), new Field(resourceField.getValue(), new Label('0', numbersInChar[0]))); } else { fields.put(resourceField.getKey(), new Field(resourceField.getValue(), new Label(numbersInChar[0], numbersInChar[1]))); } } } } /** * Method to get the DiceNumber of a specific field. * * @param field Point with coordinates of the specific field * @return the DiceNumber of the field. */ private int getDiceNumber(Point field) { Label label = fields.get(field).getLabel(); return Integer.parseInt(label.toString()); } /** * Method to create a SiedlerBoardTextView Object set the LowerFieldLabels with theirs dice number. * It is used to print the actual board in TextIO. * * @return String of actual board. */ public String getTextView() { SiedlerBoardTextView view = new SiedlerBoardTextView(this); for (Map.Entry field : fields.entrySet()) { view.setLowerFieldLabel(field.getKey(), field.getValue().getLabel()); } return view.toString(); } /** * Returns the fields associated with the specified dice value. * * @param dice the dice value * @return the fields associated with the dice value */ public List getFieldsForDiceValue(int dice) { ArrayList fields = new ArrayList<>(); for (Point field : this.fields.keySet()) { if (getDiceNumber(field) == dice) { fields.add(field); } } return fields; } /** * Method to get the Resources which are paid to a specific faction for a specific field. * * @param point The Point with the Coordinates of the field, which should pay resources. * @param faction The faction, which should get paid. * @return a ArrayList with all resources, which will be paid to the specified faction. */ public ArrayList getResourcesForFaction(Point point, Config.Faction faction) { List possibleSettlementField = super.getCornersOfField(point); ArrayList resourcesToPlayer = new ArrayList<>(); for (Settlement settlement : possibleSettlementField) { if (settlement.getFaction() == faction) { resourcesToPlayer.add(fields.get(point).getResource()); if (settlement instanceof City) { resourcesToPlayer.add(fields.get(point).getResource()); } } } return resourcesToPlayer; } /** * Returns the {@link Land}s adjacent to the specified corner. * * @param corner the corner * @return the list with the adjacent {@link Land}s */ public List getLandsForCorner(Point corner) { Point above = new Point(corner.x, corner.y + 2); Point below = new Point(corner.x, corner.y - 2); Land[] lands = new Land[3]; if (hasField(above)) { lands[0] = getField(above); lands[1] = getField(new Point(corner.x + 1, corner.y - 1)); lands[2] = getField(new Point(corner.x - 1, corner.y - 1)); } else if (hasField(below)) { lands[0] = getField(below); lands[1] = getField(new Point(corner.x + 1, corner.y + 1)); lands[2] = getField(new Point(corner.x - 1, corner.y + 1)); } else { return Collections.emptyList(); } return List.of(lands); } //TODO Java Doc no return /** * This method checks for the player with the longest road according to the siedler game rules. * * @return a HashMap where faction is the player with the longest road longer according to siedler game rules * and the Integer representing the length of the road */ public Config.Faction getLongestRoadFaction(List factionList) { List corners = getCorners(); HashMap players = new HashMap<>(); for (Config.Faction faction : factionList) { int count = 0; players.put(faction, count); for (Settlement settlement : corners) { if (settlement.getFaction() == faction) { HashSet roads = new HashSet<>(); roads = countRoad(faction, settlement.getPosition(), roads, true); count = roads.size(); int currentCount = players.get(faction); if (count > currentCount) { players.put(faction, count); } } } } if (longestRoadFaction == null) { Config.Faction currentFaction = null; int currentRoad = 4; for (Config.Faction factionA : players.keySet()) { if (players.get(factionA) > currentRoad) { currentFaction = factionA; currentRoad = players.get(factionA); } } if (currentFaction != null) { longestRoadFaction = currentFaction; longestRoadLenth = currentRoad; } } else { for (Config.Faction faction : players.keySet()) { if (players.get(faction) >= 5 && players.get(faction) > longestRoadLenth) { longestRoadFaction = faction; longestRoadLenth = players.get(faction); } } } return longestRoadFaction; } /** * This method is recursive and adds all roads which belongs to a specific players and stringing together to a HashSet. * The length of the HashSet represents the length of the longest Road the player has. * * @param faction the faction of the player to check on * @param position there has to be a starting point to start counting. In this case it's a corner where a settlement belonging to the player's faction is build on. * @param roads is the hashset with all roads belong to the player which are stringing together * @param add if true branches needs to be count together. (for example if it is the starting point(first time of counting)) otherwise the longest branch is being added to roads. * @return HashSet with all roads from a specific player which are string together. */ private HashSet countRoad(Config.Faction faction, Point position, HashSet roads, boolean add) { List roadsList = getAdjacentEdges(position); if (getCorner(position) != null && getCorner(position).getFaction() != faction) { return roads; } for (Road roadsRoad : roads) { Iterator it3 = roadsList.iterator(); while (it3.hasNext()) { Road roadsListRoad = it3.next(); if (roadsListRoad == roadsRoad || roadsListRoad.getFaction() != faction) { it3.remove(); } } } if (roadsList.size() == 1) { roads.add(roadsList.get(0)); position = getNextPoint(roadsList.get(0), position); roads = countRoad(faction, position, roads, false); } else if (roadsList.size() == 2) { HashSet listOne = (HashSet) roads.clone(); HashSet listTwo = (HashSet) roads.clone(); listOne.add(roadsList.get(0)); Point positionOne = getNextPoint(roadsList.get(0), position); listTwo.add(roadsList.get(1)); Point positionTwo = getNextPoint(roadsList.get(1), position); listOne = countRoad(faction, positionOne, listOne, false); listTwo = countRoad(faction, positionTwo, listTwo, false); if (add) { listTwo.addAll(listOne); roads = listTwo; } else { HashSet tallest; if (listOne.size() >= listTwo.size()) { tallest = listOne; } else { tallest = listTwo; } roads.addAll(tallest); } } else if (roadsList.size() == 3) { HashSet listOne = (HashSet) roads.clone(); HashSet listTwo = (HashSet) roads.clone(); HashSet listThree = (HashSet) roads.clone(); listOne.add(roadsList.get(0)); Point positionOne = getNextPoint(roadsList.get(0), position); listTwo.add(roadsList.get(1)); Point positionTwo = getNextPoint(roadsList.get(1), position); listThree.add(roadsList.get(2)); Point positionThree = getNextPoint(roadsList.get(2), position); listOne = countRoad(faction, positionOne, listOne, false); listTwo = countRoad(faction, positionTwo, listTwo, false); listThree = countRoad(faction, positionThree, listThree, false); HashSet tallest; HashSet secondTallest; if (listOne.size() >= listTwo.size()) { tallest = listOne; secondTallest = listTwo; } else { tallest = listTwo; secondTallest = listOne; } if (listThree.size() >= secondTallest.size()) { secondTallest = listThree; } tallest.addAll(secondTallest); roads = tallest; } return roads; } /** * This method is being used to evaluate the next starting position to get the adjacent Roads from it. * * @param road the next road to check on * @param position the current starting point * @return return the opposite point of the current point. */ private Point getNextPoint(Road road, Point position) { Point start = road.getStart(); Point end = road.getEnd(); if (position.equals(start)) { position = end; } else { position = start; } return position; } }