예제 #1
1
 private Move solveMove(Move move) throws NoFreeCellException, AgainstTheRulesException {
   MoveMacro newMove = new MoveMacro();
   Iterator stackIterator = stacks[move.getFrom()].createIterator();
   FreeCellAllocator allocator = new FreeCellAllocator();
   {
     // Find out if any move would be possible before we go to the trouble of creating a movemacro.
     boolean found = false;
     while (stackIterator.hasNext()) {
       Card theCard = (Card) stackIterator.next();
       if (stacks[move.getTo()].canPush(theCard)) {
         found = true;
         break;
       }
       /*
        * TODO: A side effect of this is if the fromstack includes any
        * card that could be moved, the move will allocate free cells
        * until it runs out, even if the card is buried deep?
        * //int freeCells = allocator.getNumFreeCells();
        * //for (int i=0; i < freeCells; i++) {
        */
     }
     if (!found) {
       throw new AgainstTheRulesException("There are no valid moves possible.");
     }
   }
   // Go back to the beginning.
   stackIterator.reset();
   while (stackIterator.hasNext()) {
     Card theCard = (Card) stackIterator.next();
     // if this card can be moved, then create the move and end
     if (stacks[move.getTo()].canPush(theCard)) {
       newMove.addMove(move);
       break;
     } else {
       // if it can't be moved directly, then get a free cell and create a move to the free cell.
       int cell = allocator.getFreeCell();
       newMove.addMove(new Move(move.getFrom(), cell, this));
     } // If we get a NoFreeCellException here, it's passed back and newMove gets gc'ed.
   }
   // Now, go back through the moves and move everything to the destination stack in reverse order.
   Iterator moveIterator = newMove.createIterator();
   moveIterator.previous(); // Skip the very last move, we don't need to repeat that.
   while (moveIterator.hasPrevious()) {
     Move theMove = (Move) moveIterator.previous();
     newMove.addMove(new Move(theMove.getTo(), move.getTo(), this));
   }
   return newMove;
 }
예제 #2
0
파일: Board.java 프로젝트: hodgesbe/Othello
  // alpha-beta search
  public Move alphaBeta(
      Board currentBoard, int ply, Player player, double alpha, double beta, int maxDepth) {
    /*
        Algorithm provided by: Dr. Cameron
        Implemented by: Brett Hodges
    */
    if (ply >= maxDepth) {
      Move returnMove = new Move();
      returnMove.value = currentBoard.evaluateBoard(player);
      return returnMove;
    } else {
      ArrayList<Move> moves = currentBoard.generateMoves(player);
      Move bestMove = moves.get(0);
      for (Move move : moves) {
        Board newBoard = new Board(currentBoard);
        newBoard.applyMove(player, move.move);

        // Recursively Call alpha-beta
        Move tempMove =
            alphaBeta(newBoard, ply + 1, player.getOpponant(), beta * -1, alpha * -1, maxDepth);
        move.value = -tempMove.value;
        if (move.value > alpha) {
          bestMove = move;
          alpha = move.value;
          if (alpha > beta) return bestMove;
        }
      }
      return bestMove;
    }
  }
예제 #3
0
  public void revertMove() {
    // pops a move from the stack and reverses it
    try {
      Move move = this.popMoveFromHistory(); // pop a move off the stack
      if (move.getPosition() == -1) {
        // move is pass
      } else {
        this.positions[move.getPosition()] = 0; // set move position to empty

        int stackSize = move.getFlipStackSize(); // how many flips are there?
        for (int i = 0; i < stackSize; i++) { // loop through the stack
          int flipPosition = move.popFlip();
          // System.out.println(flipPosition);
          this.setPosition(flipPosition); // pop a flip and un-flip it
        }
      }

      // Debugging stuff
      popCount++;
      // System.out.println("pop");
      // this.printBoard();

    } catch (NullPointerException e) {
      System.out.println("(C you tried to pop an empty move stack )");
    }
  }
예제 #4
0
파일: Board.java 프로젝트: hodgesbe/Othello
  // generates all possible moves for player passed, gives them a rating, and sorts them
  public ArrayList<Move> generateMoves(Player player) {
    int playerNumber = player.getPlayerNumber();
    ArrayList<Move> moveList = new ArrayList<>();

    for (int i = 0; i < board.length; i++) {
      if (isValidMove(playerNumber, i)) {
        Move move = new Move(i);
        if (CORNERS.contains(move.getMove())) {
          move.setValue(500);
        } else if (AMOVES.contains(move.getMove())) {
          move.setValue(250);
        } else if (BMOVES.contains(move.getMove())) {
          move.setValue(100);
        } else if (CMOVES.contains(move.getMove())) {
          move.setValue(50);
        } else move.setValue(-5);

        moveList.add(move);
      }
    }

    // in case of no moves, add pass move
    if (moveList.size() > 0) {
      Collections.sort(moveList, new MoveComparator());
      Collections.reverse(moveList);
    } else {
      String pass = "" + player.getPlayerColor();
      Move move = new Move(pass);
      moveList.add(move);
    }

    player.assignPossibleMoves(moveList);
    return moveList;
  }
예제 #5
0
 public void unmove(Move move) {
   try {
     Card theCard = stacks[move.getTo()].getTopCard();
     stacks[move.getFrom()].deal(theCard);
     stacks[move.getTo()].pop();
   } catch (Exception e) {
     controller.alert("Sorry, I guess you're outta luck.");
   }
   this.repaint();
 }
예제 #6
0
 /**
  * Apply the given Move to this Board (i.e., mark the Move's location on this Board with the
  * Move's Player).
  */
 public void apply(Move move) throws TTTRuntimeException {
   int x = move.getX();
   int y = move.getY();
   int z = move.getZ();
   if (x < 0 || x >= size || y < 0 || y >= size || z < 0 || z >= size) {
     throw new IllegalLocationException();
   } else if (!isEmpty(x, y, z)) {
     throw new LocationOccupiedException();
   } else {
     grid[x][y][z] = move.getPlayer();
   }
 }
예제 #7
0
  public void applyMove(int color, Move move) {
    // applies move based on fields of supplied move and pushes it to the stack
    if (move.getPosition() == -1) {
      // move is pass
    } else {
      this.positions[move.getPosition()] = color;
      Stack<Integer> flipStack = move.getFlips();
      int amountOfFlips = flipStack.size();
      for (int i = 0; i < amountOfFlips; i++) {
        this.positions[flipStack.pop()] = color;
      }
    }
    this.pushMoveToHistory(move);
    this.clearLegalMovesList();

    // debugging stuff
    pushCount++;
    // System.out.println("push");
    // this.printBoard();
  }
예제 #8
0
  public int makeComputerMove(long timeRemaining) {
    // othellonator makes a move

    Move myMove = null;
    moveCount++;
    System.out.println("(C moveCount = " + moveCount + ")");
    if (this.generateLegalMoves(myColor)) { // evaluate board, do stuff if legal moves found
      String listSize = Integer.toString(getLegalMovesListSize());
      System.out.println("(C Number of moves:" + listSize + " )");

      if (moveCount < 10) {
        myMove = Search.alphaBetaSearch(this, 6, myColor);
      } else if (moveCount >= 10 && moveCount <= 20) {
        myMove = Search.alphaBetaSearch(this, 8, myColor);
      } else {
        myMove = Search.alphaBetaSearch(this, 10, myColor);
      }
      this.applyMove(myColor, myMove); // apply the move returned by the search
      return myMove.getPosition(); // return the position of the move so it can be output
    } else return -1; // signal that no move was found
  }
예제 #9
0
  public boolean evaluateOpponentMove(int color, int position) {
    // runs generateMoveForPosition() to generate flips and push the move on to the list
    // then applies the move at the front of the list
    boolean legal = false;
    Move move = null;

    this.generateLegalMoves(myColor * -1); // evaluate legal moves for opponent
    for (int i = 0; i < this.legalMovesList.size(); i++) { // check move against legalMovesList
      Move tester = this.getLegalMove(i);
      // if opponent's move found in legalMoveList, it is legal
      if (tester.getPosition() == position) {
        legal = true;
        move = tester;
      }
    }
    // if the move is legal, apply it and return true.  otherwise return false.
    if (legal) {
      applyMove(color, move);
      return true;
    } else return false;
  }
예제 #10
0
 public void autoHome() {
   boolean found = true; // Set once for the beginning.
   while (found) { // As long as we found something on a previous pass, keep trying.
     found = false;
     // TODO: Search cellstacks as well. I got arrayIndexOutOfBounds before, because it overstepped
     // some boundary.
     for (int i = 0; i < PLAYSTACKLENGTH; i++) {
       if (stacks[i].hasCards()) {
         Card theCard = stacks[i].getTopCard();
         int homeStack = findHome(theCard);
         if (homeStack > -1) {
           found = true;
           Move move = new Move(i, homeStack, this);
           try {
             move.execute();
             addToHistory(move);
           } catch (Exception e) {
             controller.alert(e.getMessage());
           }
         }
       }
     }
   }
 }
예제 #11
0
      @Override
      @HibernateUserRead
      public void step2() {
        CardType ct = CardType.getTL(ctId);
        Date dt = new Date();
        Card c = new Card(txt, ct, dt);
        c.setCreatedInMove(Move.getCurrentMoveTL());
        c.setAuthor(User.getTL(author.getId())); // fresh
        if (newCardListener != null) newCardListener.cardCreatedTL(c);

        content.setValue("");
        content.setInputPrompt("Enter text for another card.");
        closeDrawer();

        resetCoroutine(); // for another click
      }
예제 #12
0
파일: Game.java 프로젝트: FransM22/GipfGame
  /**
   * applyMove applies the given move to the board. First, the new piece is added to the startPos
   * Then the pieces are moved in the direction of the move, and finally pieces that need to be
   * removed are removed from the board
   *
   * @param move the move that is applied
   */
  public void applyMove(Move move) {
    // An invalidMoveException can be thrown if applying that move would mean to place pieces on an
    // illegal position.
    try {
      moveCounter++;
      // If there's already a winner, the move won't be applied
      if (gipfBoardState.players.winner() != null) return;

      /*
       * Prepare for creating a new child GipfBoardState. The pieceMap and playersInGame objects of the current
       * gipfBoardState are unmodifiable, so we have to create modifiable copies.
       * If the move turns out to be legal, a new child GipfBoardState will be generated, based on the modified
       * copies of the PieceMap and the PlayersInGame objects.
       */
      // The piece map returned by getPieceMap() is unmodifiable, so it has to be converted to a new
      // (hash) map
      // the newPieceMap can be modified, after that a new GipfBoardState can be generated.
      Map<Position, Piece> newPieceMap = new HashMap<>(gipfBoardState.getPieceMap());

      // The same is true for the PlayersInGame object. It is unmodifiable, so a new instance has to
      // be created
      // for the new board state.
      PlayersInGame newPlayers = new PlayersInGame(gipfBoardState.players);

      // If the current player has enough pieces left in the reserve to perform the move (1 for a
      // normal move, 2 for
      // a Gipf move.)
      if (newPlayers.current().reserve >= move.addedPiece.getPieceValue()) {
        /*
         * Move the piece
         */
        // Each move adds a new piece to the board
        newPieceMap.put(move.startPos, move.addedPiece);

        // Move it into the direction determined by the move
        movePiecesTowards(newPieceMap, move.startPos, move.direction);

        /*
         * Remove the lines and pieces that can be removed from the board
         */
        // Create an object that keeps track of which piece is taken by whom. An EnumMap instead of
        // a HashMap is
        // used, because all keys correspond with values from the PieceColor enum.
        Map<PieceColor, Set<Line.Segment>> linesTakenBy = new EnumMap<>(PieceColor.class);
        linesTakenBy.put(WHITE, new HashSet<>());
        linesTakenBy.put(BLACK, new HashSet<>());

        // Create an object that keeps track of which individual pieces are taken by whom.
        // A HashMap is used because it can handle null keys, in contrast with EnumMaps.
        Map<PieceColor, Set<Position>> piecesBackTo = new HashMap<>();
        piecesBackTo.put(WHITE, new HashSet<>());
        piecesBackTo.put(BLACK, new HashSet<>());
        piecesBackTo.put(null, new HashSet<>()); // Used for pieces that are removed from the board

        /*
         * Distinguish between complete and incomplete moves.
         *  - Complete moves:
         *    are generated by the getAllowedMoves() method and contain all information about that move,
         *    including a choice for which lines or gipf pieces will be removed.
         *  - Incomplete moves:
         *    are performed by human players. These moves don't contain the information of which pieces are
         *    removed. This means that there may be user interaction required if the player must choose between
         *    multiple lines or gipf pieces that can be removed.
         */
        if (move.isCompleteMove) {
          // Complete moves are the easiest to handle, the positions of pieces that are removed are
          // already
          // determined.
          // This means that we only have to read the values for the pieces that are returned to
          // each player
          // into the piecesBackTo map.
          piecesBackTo.get(WHITE).addAll(move.piecesToWhite);
          piecesBackTo.get(BLACK).addAll(move.piecesToBlack);
          piecesBackTo.get(null).addAll(move.piecesRemoved);
        } else {
          // Now we have incomplete moves. This means that we have to remove the pieces that are
          // required to
          // be removed. If the player must choose between different pieces / lines, the removeLines
          // method
          // will ask the player to make a choice.

          // Get the lines that are taken by the current player (retrieved from linesTakenBy) and
          // store them
          // in the piecesBackTo map. The opponent's pieces are stored in piecesBackTo.get(null),
          // because they
          // are removed from the board.
          removeLines(newPieceMap, newPlayers.current().pieceColor, linesTakenBy, piecesBackTo);
          // linesTakenBy.get(newPlayers.current().pieceColor).addAll(getRemovableLineSegments(newPieceMap, newPlayers.current().pieceColor));

          // Get the lines that are taken by the opponent (retrieved from the linesTakenBy map), and
          // store
          // them in the piecesBackTo map. The current player's pieces are stored in
          // piecesBackTO.get(null),
          // because they are removed from the board.
          PieceColor opponentColor = newPlayers.current().pieceColor == WHITE ? BLACK : WHITE;
          removeLines(newPieceMap, opponentColor, linesTakenBy, piecesBackTo);
          // linesTakenBy.get(opponentColor).addAll(getRemovableLineSegments(newPieceMap,
          // opponentColor));
        }
        gameLogger.log(move.toString());

        // Each value in the piecesBackTo map is a set, and each element (position) of the sets of
        // all values
        // is removed from the pieceMap.
        // The number of the returned pieces for each player are added to their reserve.
        for (Map.Entry<PieceColor, Set<Position>> removedPieces : piecesBackTo.entrySet()) {
          if (removedPieces.getKey() != null) {
            // Calculate the sum for the pieces returned to this player. Normal pieces have a value
            // of 1,
            // gipf pieces a value of 2 determined in Piece.getPieceValue().
            int returnedPiecesSum =
                removedPieces
                    .getValue()
                    .stream()
                    .mapToInt(
                        position -> {
                          if (newPieceMap.containsKey(position))
                            return newPieceMap.get(position).getPieceValue();
                          else return 1;
                        })
                    .sum();

            newPlayers.get(removedPieces.getKey()).reserve += returnedPiecesSum;
            gameLogger.log(removedPieces.getKey() + " retrieved " + returnedPiecesSum + " pieces");
          }

          // The pieces are not earlier removed from the board, because the returnedPiecesSum
          // variable can
          // only be set if all the pieces are still on the board.
          removePiecesFromPieceMap(newPieceMap, removedPieces.getValue());
        }

        /*
         * Set the properties for the player, based on the move
         */
        if (move.addedPiece.getPieceType() == PieceType.GIPF) {
          newPlayers.current().hasPlacedGipfPieces = true;
        }
        if (!newPlayers.current().isPlacingGipfPieces) {
          newPlayers.current().hasPlacedNormalPieces = true;
        }

        // Update the current player's reserve for the last added piece
        newPlayers.current().reserve -= move.addedPiece.getPieceValue();

        /*
         * Check whether it is game over
         */
        // If we create a new GipfBoardState based on the calculated properties, will there be a
        // game over situation?
        if (getGameOverState(new GipfBoardState(null, newPieceMap, newPlayers))) {
          // If the current player causes a game over situation, the other player (updateCurrent()),
          // will be
          // the winner of the game.
          newPlayers = newPlayers.updateCurrent().makeCurrentPlayerWinner();
          gameLogger.log("Game over! " + newPlayers.winner().pieceColor + " won!");

          if (moveCounter != 1) {
            if (SettingsSingleton.getInstance().showExperimentOutput) {
              String moveCountString = Integer.toString(moveCounter);
              String durationString =
                  Long.toString(Duration.between(gameStartInstant, Instant.now()).toMillis());
              String winnerString = newPlayers.winner().pieceColor.toString();
              String whiteAlgorithm = whitePlayer.getClass().getSimpleName();
              String blackAlgorithm = blackPlayer.getClass().getSimpleName();

              ExperimentLogger.get()
                  .log(
                      whiteAlgorithm
                          + "; "
                          + blackAlgorithm
                          + "; "
                          + moveCountString
                          + "; "
                          + durationString
                          + "; "
                          + winnerString);
            }
          }
        }

        // We don't need to update the current player if the game has ended
        if (newPlayers.winner() == null) {
          newPlayers = newPlayers.updateCurrent();
        }

        // Create a new gipfBoardState, based on the calculated PieceMap and PlayersInGame objects.
        GipfBoardState newGipfBoardState =
            new GipfBoardState(gipfBoardState, newPieceMap, newPlayers);
        boardHistory.add(gipfBoardState);
        this.gipfBoardState = newGipfBoardState;
      } else {
        gameLogger.log("No pieces left");
      }

      // Recalculate the properties of this gipfBoardState
      gipfBoardState.boardStateProperties.updateBoardState();

    } catch (InvalidMoveException e) {
      System.out.println("Move not applied");
    }
  }
예제 #13
0
파일: Board.java 프로젝트: hodgesbe/Othello
 @Override
 public int compare(Move move1, Move move2) {
   return Integer.compare(move1.getValue(), move2.getValue());
 }
예제 #14
0
  static int MiniMax(
      int[][] board,
      int depth,
      int max_depth,
      int[] the_move,
      int turn,
      int[] counter,
      int white_best,
      int black_best) {
    // System.out.println ("\n");
    // System.out.println ("Calculating minimax");
    int the_score = 0;
    int[][] new_board = new int[8][8];
    int best_score; // , chosen_score;
    int[] best_move = new int[4];

    Vector<int[]> moves_list = new Vector<int[]>(); // vector of 4x1 arrays

    // Thread.yield();

    // assumes that depth is never equal to max_depth to begin with since
    // chosen_move is not set here
    if (depth == max_depth) {
      best_score = Evaluation(board);
      counter[0]++;
    } else {
      moves_list = Move.generate_moves(board, turn);
      best_score = which_turn(turn);
      switch (moves_list.size()) {
        case 0:
          counter[0]++;
          return best_score;
        case 1:
          if (depth == 0) {
            // forced move: immediately return control
            best_move = (int[]) moves_list.elementAt(0);
            for (int k = 0; k < 4; k++) the_move[k] = best_move[k];
            return 0;
          } else {
            // extend search since there is a forcing move
            max_depth += 1;
          }
      }

      for (int i = 0; i < moves_list.size(); i++) {
        new_board = copy_board(board); // board need not be touched
        Move.move_board(new_board, (int[]) moves_list.elementAt(i)); // returns new_board
        int temp[] = new int[4];
        the_score =
            MiniMax(
                new_board,
                depth + 1,
                max_depth,
                temp,
                opponent(turn),
                counter,
                white_best,
                black_best);

        if (turn == Checkers.BLACK && the_score > best_score) {
          best_move = (int[]) moves_list.elementAt(i);
          best_score = the_score;
          if (best_score > black_best) {
            if (best_score >= white_best) break; /*  alpha_beta cutoff  */
            else black_best = best_score; // the_score
          }
        } else if (turn == Checkers.WHITE && the_score < best_score) {
          best_move = (int[]) moves_list.elementAt(i);
          best_score = the_score;
          if (best_score < white_best) {
            if (best_score <= black_best) break; /*  alpha_beta cutoff  */
            else white_best = best_score; // the_score
          }
        }
      } // end for
    } // end else
    for (int k = 0; k < 4; k++) the_move[k] = best_move[k];
    return best_score;
  } // end minimax
예제 #15
0
 static int which_turn(int turn) {
   return Move.color(turn) == Checkers.BLACK ? -INFINITY : INFINITY;
 }
예제 #16
0
파일: Game.java 프로젝트: FransM22/GipfGame
  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;
  }
예제 #17
0
  protected void keyPressed(int keyCode) {
    int selectionLocation = getSelectionLocation();

    // Selection buttons
    if ((keyCode == KEY_NUM4) || (keyCode == -3) || (keyCode == LEFT)) {
      // NUM4, left, bbtrackball left
      gotoPrevious();
    } else if ((keyCode == KEY_NUM6) || (keyCode == -4) || (keyCode == RIGHT)) {
      // NUM5, right, bbtrackball right
      gotoNext();

      // Action buttons
    } else if ((keyCode == -5) || (keyCode == FIRE) || (keyCode == -8) || (keyCode == 10)) {
      // Emulator OK, FIRE, bbtrackball click, keyboard return
      if (selectionLocation > -1) {
        if (selectionLocation == cursorLocation) {
          // Selecting the same card that's already selected
          try {
            // Toggle selection
            stacks[selectionLocation].unselect();
          } catch (Exception e) {
            controller.alert(e.getMessage());
          }
        } else {
          try {
            // Create the move and execute it.
            Move move = new Move(selectionLocation, cursorLocation, this);
            move.execute();
            addToHistory(move);
            if (stacks[selectionLocation].hasCards()) {
              stacks[selectionLocation].unselect();
            }
          } catch (AgainstTheRulesException e) {
            // If no solution is found, then complain.
            controller.alert(e.getMessage());
          } catch (NoFreeCellException e) {
            // If the solver couldn't find enough cells, then complain.
            controller.alert(e.getMessage());
          } catch (InvalidCardException e) {
            controller.alert(e.getMessage());
          } finally {
            try {
              // And make sure nothing is left selected
              selectionLocation = getSelectionLocation();
              if (selectionLocation > -1) {
                stacks[selectionLocation].unselect();
              }
            } catch (Exception e) {
              // And if that fails, complain
              controller.alert(e.getMessage());
            }
          }
        }
        this.repaint();
      } else {
        try {
          // Select the card under the cursor
          stacks[cursorLocation].select();
        } catch (Exception e) {
          // And if that fails, complain
          controller.alert(e.getMessage());
        }
        repaint();
      }
    } else if ((keyCode == UP) || (keyCode == -1)) {
      // UP, Emulator UP
      if (getSelectionLocation() == -1) {
        // Move the selection location to the top, for convenience.
        gotoLocation(PLAYSTACKLENGTH + CELLSTACKLENGTH - 1);
        this.repaint();
      } else {
        // Move the currently-selected card home if possible, or to a free cell, if available.
        try {
          Card theCard = stacks[selectionLocation].getTopCard();
          int homeslot = findHome(theCard);
          if (homeslot > -1) {
            Move move = new Move(selectionLocation, homeslot, this);
            move.execute();
            addToHistory(move);
          } else {
            // Find a free cell and if found, create a move and execute.
            int freeCell = new FreeCellAllocator().getFreeCell();
            Move move = new Move(selectionLocation, freeCell, this);
            move.execute();
            addToHistory(move);
          }
          if (stacks[selectionLocation].hasCards()) {
            stacks[selectionLocation].unselect();
          }
        } catch (AgainstTheRulesException e) {
          // If no solution is found, then complain.
          controller.alert(e.getMessage());
        } catch (NoFreeCellException e) {
          // If the solver couldn't find enough cells, then complain.
          controller.alert(e.getMessage());
        } catch (InvalidCardException e) {
          controller.alert(e.getMessage());
        } finally {
          try {
            // And make sure nothing is left selected
            selectionLocation = getSelectionLocation();
            if (selectionLocation > -1) {
              stacks[selectionLocation].unselect();
            }
          } catch (Exception e) {
            // And if that fails, complain
            controller.alert(e.getMessage());
          }
        }
      }

      // Other buttons
    } else {
      // DEBUG
      // controller.alert("KeyCode:"+keyCode+"\nCursor:"+cursor.toString());
    }
  }
예제 #18
-17
 public void doMove(Move move)
     throws AgainstTheRulesException, NoFreeCellException, InvalidCardException {
   Card theCard = null;
   try {
     theCard = stacks[move.getFrom()].pop();
     stacks[move.getTo()].push(theCard);
   } catch (AgainstTheRulesException e1) {
     if (!theCard.equals(null)) {
       // If we managed to pop the card, deal it back.
       stacks[move.getFrom()].deal(theCard);
     }
     // TODO: If this move is already part of a movemacro, then we don't want to keep trying to
     // solve it.
     Move newMove = solveMove(move);
     newMove.execute();
     addToHistory(move);
   }
   this.repaint();
 }