OOP Java 跳棋游戏

问题描述 投票:0回答:1

我可以毫无问题地运行程序,但是当我尝试迈出第一步时,我收到错误。我尝试添加一些调试语句,并在控制台中得到以下内容:

我已经研究了 movePiece 和 isLegal() 但我找不到任何奇怪的东西。有人可以帮我找到这个问题吗?显然欢迎任何建议。

我的代码分为 4 类。

  1. Board.java
import java.util.Arrays;

public class Board {
    private static final int X = 0;
    private static final int Y = 1;
    private static final int BOARD_MIN = 1;
    private static final int[] boardDimensions = {8, 8};
    private final int totalPieces = 24;

    private final Piece[] pieces;
    private boolean xToMove;
    private int oCaptures;
    private int xCaptures;

    public Board() {
        xToMove = true;
        pieces = new Piece[totalPieces];
        initializePieces();
    }

    // Helper method to initialize pieces
    private void initializePieces() {
        int index = 0;

        // Populates the 'O' pieces from the top
        for (int y = boardDimensions[Y]; y >= BOARD_MIN; y--) {
            for (int x = BOARD_MIN; x <= boardDimensions[X]; x++) {
                if (y % 2 == x % 2 && index < totalPieces / 2) {
                    pieces[index] = new CheckersPiece('O', true,  x, y);
                    index++;
                }
            }
            if (index >= totalPieces / 2) {
                break;
            }
        }

        // Populates the 'X' pieces from the bottom
        for (int y = BOARD_MIN; y <= boardDimensions[Y]; y++) {
            for (int x = BOARD_MIN; x <= boardDimensions[X]; x++) {
                if (y % 2 == x % 2 && index < totalPieces) {
                    pieces[index] = new CheckersPiece('X', true,  x, y);
                    index++;
                }
            }
            if (index >= totalPieces) {
                break;
            }
        }
    }

    // Instantiates and returns a deep copy
    public Board(Board other) {
        pieces = new Piece[totalPieces];
        int index = 0;

        for (Piece otherPiece : other.pieces) {
            this.pieces[index] = new CheckersPiece(
                    otherPiece.getSymbol(),
                    otherPiece.isCrowned(),
                    otherPiece.getPosition()
            ) {
                @Override
                public int[][] getMoves() {
                    return new int[0][];
                }
            };
            index++;
        }
        this.xToMove = other.xToMove;
        this.oCaptures = other.oCaptures;
        this.xCaptures = other.xCaptures;
    }

    public void movePiece(int[] move, int x, int y) throws IllegalMove {
        var piece = getPiece(x, y);
        if (piece == null) {
            System.out.println("DEBUG: No piece at position " + x + ", " + y);
            throw new IllegalArgumentException("Invalid piece position");
        }

        Piece otherPiece = getPiece(move);

        if (otherPiece == null) {
            if (piece.getSymbol() != 'X' || !isLegalMove(piece, move)) {
                System.out.println("DEBUG: Illegal move for 'X'");
                throw new IllegalMove();
            }
            piece.setPosition(move);
            xToMove = !xToMove;
        } else {
            if (!isLegalMove(piece, move) || !canJump(piece, otherPiece)) {
                System.out.println("DEBUG: Illegal jump for 'X'");
                throw new IllegalMove();
            }
            piece.setPosition(piece.getSkip(otherPiece));
            otherPiece.remove();
            if (piece.getSymbol() == 'X') oCaptures++;
            else xCaptures++;
            xToMove = hasJump(piece);
        }

        if (canCrown(piece))
            piece.crown();
    }


    public boolean xToMove() {
        return xToMove;
    }

    public boolean canCrown(Piece piece) {
        // If the piece is on the back rank for its symbol
        return piece.getSymbol() == 'O' && piece.getPosition()[Y] == boardDimensions[Y] ||
                piece.getSymbol() == 'X' && piece.getPosition()[Y] == BOARD_MIN;
    }

    // Checks if one piece can jump an adjacent piece.
    public boolean canJump(Piece piece, Piece other) {
        if (other != null) {
            try {
                CheckersPiece otherCheckersPiece = (CheckersPiece) other;

                return piece.getSymbol() != otherCheckersPiece.getSymbol() &&
                        onBoard(piece.getSkip(otherCheckersPiece)) &&
                        getPiece(piece.getSkip(otherCheckersPiece)) == null;
            } catch (ClassCastException e) {
                return false;
            }
        } else {
            return false;
        }
    }
    // Checks if a piece is capable of jumping any other piece.
    public boolean hasJump(Piece piece) {
        for (int[] move : piece.getMoves()) {
            // If the move is valid and there is an adjacent piece
            if (move != null && getPiece(move) != null) {
                // If it can jump the piece
                if (canJump(piece, getPiece(move))) {
                    return true;
                }
            }
        }
        return false;
    }

    // Prints the current board to the console.
    public void printBoard() {

        for (int y = boardDimensions[Y]; y >= BOARD_MIN; y--) {

            System.out.println("   " + "-".repeat(boardDimensions[X] * 5));
            System.out.printf("%2d |", y);

            for (int x = BOARD_MIN; x <= boardDimensions[X]; x++) {

                Piece piece = getPiece(x, y);
                String pieceSymbol = (piece != null) ? piece.toString() : " ";

                System.out.printf(" %s |", pieceSymbol);
            }

            System.out.println();
        }

        // Print captures only once at the end
        System.out.println("   " + "-".repeat(boardDimensions[X] * 5));
        for (int i = 0; i < boardDimensions[X]; i++)
            System.out.printf("%5c", (char) i + 97);
        System.out.println();
        System.out.print(" " + "X".repeat(xCaptures));
        System.out.println(" " + "O".repeat(oCaptures));
    }

    public static boolean onBoard(int... position) {
        return (BOARD_MIN <= position[X] && position[X] <= boardDimensions[X] &&
                BOARD_MIN <= position[Y] && position[Y] <= boardDimensions[Y]);
    }

    public Piece getPiece(int... position) {
        for (Piece piece : pieces) {
            if (Arrays.equals(piece.getPosition(), position))
                return piece;
        }
        return null;
    }

    public boolean isLegalMove(Piece piece, int... move) {
        if (piece == null || move == null) {
            System.out.println("DEBUG: Invalid piece or move");
            return false;
        }

        // Check if the move is a jump
        if (getPiece(move) != null && canJump(piece, getPiece(move))) {
            System.out.println("DEBUG: Jump move is valid");
            return true;
        }

        // Check if the piece is crowned
        if (piece.isCrowned()) {
            // Check if it's the correct player's turn
            if ((piece.getSymbol() == 'X' && xToMove) || (piece.getSymbol() == 'O' && !xToMove)) {
                // Check if the move is valid (empty space)
                if (getPiece(move) == null) {
                    System.out.println("DEBUG: Move is valid");
                    return true;
                } else {
                    System.out.println("DEBUG: Move is not valid, space is occupied");
                }
            } else {
                System.out.println("DEBUG: Wrong player's turn");
            }
        } else {
            // For uncrowned pieces, check the turn and allow horizontal moves without jumps
            if ((piece.getSymbol() == 'X' && xToMove) || (piece.getSymbol() == 'O' && !xToMove)) {
                if (move[X] == piece.getPosition()[X]) {
                    System.out.println("DEBUG: Uncrowned piece move is valid");
                    return true;
                } else {
                    System.out.println("DEBUG: Invalid move for uncrowned piece");
                }
            } else {
                System.out.println("DEBUG: Wrong player's turn for uncrowned piece");
            }
        }

        return false;
    }

    public boolean hasLegalMove(Piece piece) {
        for (int[] move : piece.getMoves()) {
            if (isLegalMove(piece, move)) {
                return true;
            }
        }
        return false;
    }

    public boolean isDrawn() {
        for (Piece piece : pieces) {
            if (hasLegalMove(piece)) {
                return false;
            }
        }
        return true;
    }

    public int getWinner() {
        if (oCaptures == totalPieces / 2) {
            return 1;
        }
        if (xCaptures == totalPieces / 2) {
            return -1;
        }
        return 0;
    }
}
  1. 跳棋.java
import java.util.Scanner;
import java.util.Stack;

public class Checkers {
    private static final int FORWARD_LEFT = 0;
    private static final int FORWARD_RIGHT = 1;
    private static final int BACKWARD_LEFT = 2;
    private static final int BACKWARD_RIGHT = 3;
    private static final char QUIT = 'q';
    private static final char RESIGN = 'r';
    private static final char BACKWARD = 'b';
    private static final char LEFT = 'l';
    private static final char RIGHT = 'r';
    private static final char UNDO = 'u';

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        Board board = new Board();
        Stack<Board> boardStates = new Stack<>();

        board.printBoard();

        while (true) {

            printPrompt(board);
            String input = in.nextLine();

            // Checks for commands
            if (input.isBlank()) {
                System.out.println("Error: No command given.");
                continue;
            }
            if (input.toLowerCase().charAt(0) == QUIT) {
                break;
            }
            if (input.toLowerCase().charAt(0) == RESIGN) {
                System.out.println(board.xToMove() ?
                        "White resigns. Black has won!" :
                        "Black resigns. White has won!");
                break;
            }
            if (input.toLowerCase().charAt(0) == UNDO) {
                if (!boardStates.isEmpty()) {
                    board = boardStates.pop();
                    board.printBoard();
                } else {
                    System.out.println("Error: Cannot undo. No previous state available.");
                }
                continue;
            }
            if (input.equalsIgnoreCase("help")) {
                System.out.println("""
                        Enter <letter><number> <(l)eft/(r)ight> <(b)ack> to move.
                        Example: a3 right
                        Example: b8 left back
                        Example: c1 r b
                        """);
                continue;
            }

            String[] inputs = input.split(" ");

            // Translates a1 to x=1, y=1, etc.
            int x;
            int y;
            try {
                x = getInt(inputs[0].toLowerCase().charAt(0));
                y = Integer.parseInt(inputs[0].substring(1));
            } catch (NumberFormatException e) {
                System.out.println("Error: Invalid input. Please enter a valid position.");
                continue;
            }

            if (inputs.length < 2) {
                System.out.println("Error: No direction given.");
                continue;
            }

            // Checks for a backward command
            boolean forward = true;
            if (inputs.length > 2) {
                if (inputs[2].toLowerCase().charAt(0) == BACKWARD)
                    forward = false;
            }

            // Sets "direction" index for piece's array of moves based on commands;
            // the index will get the move in the corresponding direction.
            int direction = getDirection(inputs[1].toLowerCase().charAt(0), forward);
            if (direction == -1) {
                System.out.println("Error: Invalid direction. Please enter 'left' or 'right'.");
                continue;
            }

            int[] move;
            try {
                move = board.getPiece(x, y).getMoves()[direction];
            } catch (NullPointerException e) {
                System.out.println("Error: Invalid move. No piece at position " + inputs[0]);
                continue;
            }

            // Pushes a deep copy to the stack
            boardStates.push(new Board(board));

            try {
                board.movePiece(move, x, y);
            } catch (IllegalMove e) {
                System.out.println("Error: Illegal move.");
                boardStates.pop();
                continue;
            }

            board.printBoard();

            if (board.isDrawn()) {
                System.out.println("Game is Drawn");
                break;
            }

            if (board.getWinner() != 0) {
                System.out.println(board.getWinner() == 1 ?
                        "Game over: White has won!" :
                        "Game over: Black has won!");
                break;
            }

        }
        System.out.println("Terminating program...");
        in.close();

    }

    // Common logic for direction setting
    public static int getDirection(char inputChar, boolean forward) {
        return switch (inputChar) {
            case LEFT -> forward ? FORWARD_LEFT : BACKWARD_LEFT;
            case RIGHT -> forward ? FORWARD_RIGHT : BACKWARD_RIGHT;
            default -> -1;
        };
    }
    public static void printPrompt(Board board) {
        System.out.println("Commands: help, (U)ndo, (R)esign, (Q)uit");
        System.out.println(board.xToMove() ? "X's turn." : "O's turn.");
    }

    public static int getInt(char character) {
        return character - 96;
    }
}


  1. Piece.java
import java.util.Arrays;

public abstract class Piece {

    private static final int[] OFF_BOARD = {0, 0};
    protected static final int X = 0;
    protected static final int Y = 1;

    private final char symbol;  // Use char to represent 'X' or 'O'
    private int[] position;
    protected final boolean isCrowned;

    public Piece(char symbol, boolean isCrowned, int... position) {
        this.symbol = symbol;
        this.isCrowned = isCrowned;
        this.position = position;
    }

    public int[] getPosition() {
        return Arrays.copyOf(position, position.length);
    }

    public void setPosition(int... position) {
        this.position = position;
    }

    public void remove() {
        setPosition(OFF_BOARD);
    }

    public char getSymbol() {
        return symbol;
    }

    public boolean isCrowned() {
        return isCrowned;
    }

    public int[] getSkip(Piece other) {
        return getSkip(other.getPosition());
    }

    public int[] getSkip(int... position) {
        int x = this.position[X] > position[X] ? this.position[X] - 2 : this.position[X] + 2;
        int y = this.position[Y] > position[Y] ? this.position[Y] - 2 : this.position[Y] + 2;
        return new int[]{x, y};
    }

    public abstract int[][] getMoves();

    public void crown() {
    }

    public abstract String pieceSymbol();

    @Override
    public String toString() {
        return pieceSymbol();
    }
}

class CheckersPiece extends Piece {

    public CheckersPiece(char symbol, boolean isCrowned, int... position) {
        super(symbol, isCrowned, position);
    }

    @Override
    public int[][] getMoves() {
        int[] currentPosition = getPosition();
        int forward = currentPosition[Y] + (getSymbol() == 'O' ? 1 : -1);
        int backward = currentPosition[Y] - (getSymbol() == 'O' ? 1 : -1);
        int left = currentPosition[X] - 1;
        int right = currentPosition[X] + 1;

        int[] forwardLeft = null;
        int[] forwardRight = null;
        int[] backwardLeft = null;
        int[] backwardRight = null;

        if (Board.onBoard(left, forward)) {
            forwardLeft = Arrays.copyOf(new int[]{left, forward}, 2);
            System.out.println("DEBUG: Checking move for " + getSymbol() + " at " + Arrays.toString(forwardLeft));
        }
        if (Board.onBoard(right, forward)) {
            forwardRight = Arrays.copyOf(new int[]{right, forward}, 2);
            System.out.println("DEBUG: Checking move for " + getSymbol() + " at " + Arrays.toString(forwardRight));
        }
        if (Board.onBoard(left, backward) && isCrowned()) {
            backwardLeft = Arrays.copyOf(new int[]{left, backward}, 2);
            System.out.println("DEBUG: Checking move for " + getSymbol() + " at " + Arrays.toString(backwardLeft));
        }
        if (Board.onBoard(right, backward) && isCrowned()) {
            backwardRight = Arrays.copyOf(new int[]{right, backward}, 2);
            System.out.println("DEBUG: Checking move for " + getSymbol() + " at " + Arrays.toString(backwardRight));
        }

        return new int[][]{forwardLeft, forwardRight, backwardLeft, backwardRight};
    }

    @Override
    public String pieceSymbol() {
        return Character.toString(getSymbol());
    }

}

  1. 非法移动.java
class IllegalMove extends Exception {
}
java oop checkers
1个回答
-1
投票

我运行了该应用程序并试用了该功能。我能够为玩家 x 迈出第一步,但我必须添加“b”来表示后退。我移动了“a3 r b”,它向右、向上、对角地移动。问题似乎在于基于棋盘和玩家方向的功能。棋盘以 arial 视图呈现,但如果您实际上正在与某人玩西洋跳棋,则方向(左或右,上或下)将根据玩家而反转。

此外,每个项目文件夹只有一个公共类,仅供参考。不确定这是否会导致您运行游戏时出现初步问题 - 可能取决于 IDE?

© www.soinside.com 2019 - 2024. All rights reserved.