// TODO: Refactor method private void removeLines( Map<Position, Piece> pieceMap, PieceColor pieceColor, Map<PieceColor, Set<Line.Segment>> linesTakenBy, Map<PieceColor, Set<Position>> piecesBackTo) { Set<Line.Segment> intersectingSegments; Set<Line.Segment> segmentsNotRemoved = new HashSet<>(); do { intersectingSegments = new HashSet<>(); Set<Line.Segment> removableSegmentsThisPlayer = getRemovableLineSegments(pieceMap, pieceColor); for (Line.Segment segment : removableSegmentsThisPlayer) { // Remove the line segments that are not intersecting with other line segments of the set boolean intersectionFound = false; for (Line.Segment otherSegment : removableSegmentsThisPlayer) { if (!segment.equals(otherSegment) && !segmentsNotRemoved.contains(otherSegment)) { if (segment.intersectsWith(otherSegment)) { if (!segmentsNotRemoved.contains(segment)) { intersectingSegments.add(segment); intersectionFound = true; } } } } if (!intersectionFound) { if (!segmentsNotRemoved.contains(segment)) { linesTakenBy.get(pieceColor).add(segment); } } } if (intersectingSegments.size() > 0) { Line.Segment segment = intersectingSegments.iterator().next(); currentRemoveSelection = segment.getOccupiedPositions(pieceMap); int dialogResult = GipfBoardComponent.showConfirmDialog( gipfBoardState.players.current().pieceColor + ", do you want to remove " + segment .getOccupiedPositions(pieceMap) .stream() .map(Position::getName) .sorted() .collect(toList()) + "?", "Remove line segment"); if (dialogResult == JOptionPane.YES_OPTION) { // Remove the line linesTakenBy.get(pieceColor).add(segment); } else if (dialogResult == JOptionPane.NO_OPTION) { // Don't remove the line segmentsNotRemoved.add(segment); } currentRemoveSelection = new HashSet<>(); } for (Line.Segment segment : linesTakenBy.get(pieceColor)) { Predicate<Map.Entry<Position, Piece>> isNormalPiece = entry -> entry.getValue().getPieceType() == NORMAL; Predicate<Map.Entry<Position, Piece>> isCurrentPlayersColor = entry -> entry.getValue().getPieceColor() == pieceColor; Predicate<Map.Entry<Position, Piece>> doesPlayerWantToRemoveGipf = entry -> { currentRemoveSelection.add(entry.getKey()); int dialogResult = GipfBoardComponent.showConfirmDialog( gipfBoardState.players.current().pieceColor + ", do you want to remove the Gipf at " + entry.getKey().getName() + "?", "Remove Gipf"); currentRemoveSelection = new HashSet<>(); return dialogResult == JOptionPane.YES_OPTION; }; Map<Position, Piece> piecesRemovedMap = segment.getOccupiedPositions(pieceMap).stream().collect(toMap(p -> p, pieceMap::get)); piecesBackTo .get(pieceColor) .addAll( piecesRemovedMap .entrySet() .stream() .filter(isCurrentPlayersColor.and(isNormalPiece.or(doesPlayerWantToRemoveGipf))) .map(Map.Entry::getKey) .collect(toSet())); piecesBackTo .get(null) .addAll( piecesRemovedMap .entrySet() .stream() .filter( isCurrentPlayersColor .negate() .and(isNormalPiece.or(doesPlayerWantToRemoveGipf))) .map(Map.Entry::getKey) .collect(toSet())); } piecesBackTo.values().forEach(positionSet -> removePiecesFromPieceMap(pieceMap, positionSet)); } while (intersectingSegments.size() > 0); return; }
public Set<Move> getAllowedMoves() { // If there is already a winn if (gipfBoardState.players.winner() != null) { return Collections.emptySet(); } // Create a set of incomplete moves containing the starting positions and directions for the // current piece Set<Move> potentialMoves = getPotentialStartMoves(getCurrentPiece()); // If the current piece is a GIPF piece, the player is also allowed to place normal pieces. if (getCurrentPiece().getPieceType() == GIPF) potentialMoves.addAll( getPotentialStartMoves(Piece.of(NORMAL, getCurrentPiece().getPieceColor()))); // These moves are marked as complete so a temporary game won't ask for user input. potentialMoves.stream().forEach(m -> m.isCompleteMove = true); Set<Move> potentialMovesIncludingLineSegmentRemoval = new HashSet<>(); for (Move potentialMove : potentialMoves) { try { Map<Position, Piece> temporaryPieceMap = new HashMap<>(getGipfBoardState().getPieceMap()); temporaryPieceMap.put(potentialMove.startPos, potentialMove.addedPiece); movePiecesTowards( temporaryPieceMap, potentialMove.getStartingPosition(), potentialMove.getDirection()); Set<List<Pair<PieceColor, Line.Segment>>> RLineOrderingsSet = getRemovableLineOrderingsSetFromGipfBoard( temporaryPieceMap, getCurrentPiece().getPieceColor()); if (RLineOrderingsSet.size() > 0) { for (List<Pair<PieceColor, Line.Segment>> RLineOrdering : RLineOrderingsSet) { Set<Position> piecesToWhite = new HashSet<>(); Set<Position> piecesToBlack = new HashSet<>(); Set<Position> piecesRemoved = new HashSet<>(); for (Pair<PieceColor, Line.Segment> RLine : RLineOrdering) { Line.Segment removedSegment = RLine.getValue(); // The color of the player who removed the line PieceColor colorRemoved = RLine.getKey(); // Determine per segment to whom the pieces are given. Pieces can only be given to the // player // who removed the line, or deleted from the game. Set<Position> occupiedPositions = removedSegment.getOccupiedPositions(temporaryPieceMap); Set<Position> piecesFromSegmentBackToReserve = occupiedPositions .stream() .filter( position -> temporaryPieceMap.get(position).getPieceColor() == colorRemoved) .collect(toSet()); Set<Position> piecesFromSegmentRemoved = occupiedPositions .stream() .filter(position -> !piecesFromSegmentBackToReserve.contains(position)) .collect(toSet()); if (colorRemoved == WHITE) piecesToWhite.addAll(piecesFromSegmentBackToReserve); if (colorRemoved == BLACK) piecesToBlack.addAll(piecesFromSegmentBackToReserve); piecesRemoved.addAll(piecesFromSegmentRemoved); } // And finally add the move // the constructor will define this as a complete move, because all the parameters have // a value. potentialMovesIncludingLineSegmentRemoval.add( new Move( potentialMove.addedPiece, potentialMove.startPos, potentialMove.direction, piecesToWhite, piecesToBlack, piecesRemoved)); } } else { // If no line segments can be removed, just add the original move potentialMovesIncludingLineSegmentRemoval.add(potentialMove); } } catch (InvalidMoveException e) { // We don't consider this move if it is invalid } } return potentialMovesIncludingLineSegmentRemoval; }