我可以毫无问题地运行程序,但是当我尝试迈出第一步时,我收到错误。我尝试添加一些调试语句,并在控制台中得到以下内容:
我已经研究了 movePiece 和 isLegal() 但我找不到任何奇怪的东西。有人可以帮我找到这个问题吗?显然欢迎任何建议。
我的代码分为 4 类。
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;
}
}
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;
}
}
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());
}
}
class IllegalMove extends Exception {
}
我运行了该应用程序并试用了该功能。我能够为玩家 x 迈出第一步,但我必须添加“b”来表示后退。我移动了“a3 r b”,它向右、向上、对角地移动。问题似乎在于基于棋盘和玩家方向的功能。棋盘以 arial 视图呈现,但如果您实际上正在与某人玩西洋跳棋,则方向(左或右,上或下)将根据玩家而反转。
此外,每个项目文件夹只有一个公共类,仅供参考。不确定这是否会导致您运行游戏时出现初步问题 - 可能取决于 IDE?