我正在为Java中的控制台开发Connect Four游戏。我对获胜条件有疑问,因为我不知道如何编程。这是我的代码我的主要:
public class Main {
public static char[] playerNumber = new char[]{'1', '2'};
public static char[] Badge = new char[]{'X', 'O'};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int moves = 7 * 6;
int whichPlayer = 0;
for (int i = 0; i < 10; i++) {
System.out.println(" FOUR IN A ROW");
System.out.println("-------------------------------------------------------");
System.out.println("Welcome to the amazing game Four In A Row:");
System.out.println("Enter a number between 0 and 6 for choosing a column.");
System.out.println();
Board board = new Board();
board.fillBoard();
board.presentBoard();
do {
// 1. get a badge
char Player = playerNumber[whichPlayer];
char badge = Badge[whichPlayer];
// 2. make a turn
board.makeTurn(badge, Player);
board.presentBoard();
// 3. Tjek om der er vinder
if (board.checkWinHorizontal() || board.checkWinVertical()) {
System.out.println("Player " + Player + " has won!");
break;
}
// 4. change the player
whichPlayer = 1 - whichPlayer;
// 5. decrease moves
--moves;
if (moves == 0) {
System.out.println("Game over, nobody has won.");
System.out.println("Do you want to play again? 'Y' or 'N':");
String newGame = scanner.nextLine();
if (newGame.equals("Y") || newGame.equals("y")) {
break;
}
if (newGame.equals("N") || newGame.equals("n")) {
System.out.println("Thanks for the game!");
return;
}
}
// 6. repeat
} while (true);
}
}
这是我的董事会成员的代码:
public class Board {
char[][] board = new char[6][7];
int column;
// Fills the empty spaces
public void fillBoard() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
board[i][j] = ' ';
}
}
}
// Prints the board
public void presentBoard() {
for (int i = 0; i < 6; i++) {
System.out.print(" | ");
for (int j = 0; j < 7; j++) {
System.out.print(board[i][j] + " | ");
}
System.out.println();
System.out.print(" -----------------------------");
System.out.println();
}
}
// Turn
public void makeTurn(char badge, char Player) {
Scanner scanner = new Scanner(System.in);
do {
// 1. Ask for a column
System.out.println("Player " + Player + " turn: ");
column = scanner.nextInt();
// 2. Check if it's between 0 and 6
if (column > 6) {
System.out.println("That is not a valid number. Please enter a number between 0 and 6: ");
continue;
}
// 3. Place a badge
for (int i = 6 - 1; i >= 0; i--) {
if (board[i][column] == ' ') {
board[i][column] = badge;
return;
}
}
// If column is full
System.out.println("Column " + column + " is full. Try another column:");
} while (true);
}
// Check for vertical win
public boolean checkWinVertical() {
return verticalWin(5, column);
}
// Check for horizontal win
public boolean checkWinHorizontal() {
return horizontalWin(5,column);
}
// Conditions for vertical win
private boolean verticalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x-1][y] == charToCheck &&
board[x-2][y] == charToCheck &&
board[x-3][y] == charToCheck) {
return true;
}
return false;
}
// Conditions for horizontal win
private boolean horizontalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x][y+1] == charToCheck &&
board[x][y+2] == charToCheck &&
board[x][y+3] == charToCheck) {
return true;
}
return false;
}
我已成功让游戏在阵列的底行水平和垂直识别胜利,但我不知道如何让游戏识别整个阵列。我只关注水平和垂直,因为对角线对我来说太复杂了。我不知道这是正确的做法还是有更好的做法。 谢谢!
答案 0 :(得分:1)
这是另一个解决方案。它与前面提到的相同的一般概念:循环遍历每一行/列,检查连续4的条纹。也许这个实现将提供一些其他见解。下面,我展示了检查水平条纹的示例方法。对于垂直,您将迭代遍历内部for循环中的行。
public boolean checkWin(char badge) {
return checkHorizontalStreaks(board, badge)
|| checkVerticalStreaks(board, badge);
}
private boolean checkHorizontalStreaks(char[][] board, char badge) {
for (int row = 0; row < board.length; row++) {
// loop throught each row
int currentStreak = 0;
for (int col = 0; col < board[row].length; col++) {
// loop through each column in the row
if (board[row][col] == badge) {
// keep the streak of 'badge' going
currentStreak++;
if (currentStreak == 4) {
// winner
return true;
}
} else {
// restart the streak
currentStreak = 0;
}
}
}
return false;
}
然后使用
更新您的Main类 if (board.checkWin(badge)) {
System.out.println("Player " + Player + " has won!");
break;
}
我下注有一种更有效的方法来确定胜利者(可能将网格视为图形并用一些特殊逻辑遍历它)。但是,我怀疑这可能足以满足您的需求。我会为您提供输出,但它适用于几个不同的测试用例。
答案 1 :(得分:0)
可能你可以检查最后一个场地周围的所有相邻场地,所以在用户轮到他之后。因此,为了向上检查,您可以这样做:
public boolean checkUp(int rowPlayed, int columnPlayed){
boolean checked = false;
if(rowplayed + 1 <= maxrows){ //Checks if you didn't hit the top
if(board[rowPlayed+1][columnPlayed] != null){
if(board[rowPlayed+1][columnPlayed].getPlayer() == currentPlayer){
checked = true;
}
}
}
return checked;
}
并且例如实现如下:
public void checkWin(int rowPlayed, int columnPlayed){
boolean checkingWin = true;
int countWin = 0;
while(checkingWin){
if(checkUp(rowPlayed + countWin, columnPlayed)){
countWin++;
}
else{
checkingWin = false;
}
if(countWin == 4){
checkinWin = false;
//Insert win confirmation here
}
}
}
它是部分伪代码,因为我不确切知道你如何处理代码中的内容,也不知道这是否是最好的方法。但我希望它对你有帮助。
答案 2 :(得分:0)
这是一个很长的答案,我会绕过房子,所以你可以看到我如何达到我的解决方案(最后也扩展到对角线检查)。
我会使用最后一块作为起点并从那里开始工作,因为检查所有组合是详尽无遗的。
鉴于添加的最后一部分的行和列,我需要决定我需要实现的目标。
我已经知道当前的行和列有我想要的那种颜色,所以我可以忽略它。
对于水平匹配,我想检查一下,我想检查同一行中左右两边的碎片是否有相同的颜色,如果颜色不同或没有碎片则停止。
想象一下下面的棋盘(#=空,R =红棋,Y =黄棋:
6 # # # # # # # #
5 # # # # # # # #
4 # # # # # # # #
3 # # # # # # # #
2 # # # # # # # #
1 # # # # # # # #
0 Y R R R Y Y Y R
0 1 2 3 4 5 6 7
最后一步是黄色,第0行,第4列。
所以我想从[0] [4]左右检查,看看颜色的连续部分的总数是3,(不是4),因为我知道[0] [4]是黄色的,可以打折。
基于此,我可以采用递归方法检查相邻的一侧,然后递归地执行相同的操作,只要我保持匹配相同颜色的部分或不遇到空槽。
我开始右边的检查(演示):
private static final int COLS = 7;
private static final int ROWS = 6;
public enum Piece {RED, YELLOW}; // null is empty
private Piece[][] board = new Piece[ROWS][COLS]; // the board
private int checkRight(Piece piece, int row, int col) {
// assume valid row for now
col++; // moving col to the right
if (col >= COLS || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkRight for the next col
return 1 + checkRight(piece, row, col);
}
}
现在我可以在左边执行相同的操作。
private int checkLeft(Piece piece, int row, int col) {
// assume valid row for now
col--; // moving col to the left
if (col < 0 || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkLeft for the next col
return 1 + checkLeft(piece, row, col);
}
}
要检查胜利者的水平,我可以这样做:
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return checkRight(piece, row, col) + checkLeft(piece, row, col) == 3;
}
呃,那里有很多重复吗?
我们可以通过引入一个新的参数direction
将两个方法压缩成一个,如果我们分别通过值1和-1移动col正面或负面,它们可以改变:
private int check(Piece piece, int row, int col, int direction) {
col += direction; // direction is either 1 (right) or -1 (left)
if (col < 0 || col >= COLS || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col);
}
}
为此新参数更新checkWinner()
:
private static final int POSITIVE = 1; // right at the moment
private static final int NEGATIVE = -1; // left at the moment
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return check(piece, row, col, POSITIVE) + check(piece, row, col, NEGATIVE) == 3;
}
现在我可以为垂直实现相同类型的逻辑,但是保持相同的col
并更改row
。我将详细跳过这一部分,并转到包含此和对角线检查的解决方案。
这是使用enum
名为CheckType
的{{1}}存储值完成的,row
和col
应更改并由check()
方法使用。例如对于HORIZONTAL
,列更改为1或-1(取决于调用check()
时指定的方向),行仍为0。
public class Board {
public enum Piece {
RED, YELLOW
};
private enum CheckType {
HORIZONTAL(0, 1), VERTICAL(1, 0), DIAGNONAL_UP(1, 1), DIAGNONAL_DOWN(-1, 1);
int row;
int col;
CheckType(int row, int col) {
this.row = row;
this.col = col;
}
}
private static final int POSITIVE = 1;
private static final int NEGATIVE = -1;
private static final int ROWS = 6;
private static final int COLS = 7;
private Piece[][] board = new Piece[ROWS][COLS];
private boolean hasWinner = false;
public boolean hasWinner() {
return hasWinner;
}
private void checkWinner(Piece piece, int row, int col) {
// check all values of enum CheckType for a winner
// so HORIZONTAL, VERTICAL, etc..
int enumIndex = 0;
while (!hasWinner && enumIndex < CheckType.values().length) {
hasWinner = check(piece, row, col, POSITIVE, CheckType.values()[enumIndex])
+ check(piece, row, col, NEGATIVE, CheckType.values()[enumIndex]) == 3;
enumIndex++;
}
}
private int check(Piece piece, int row, int col, int direction, CheckType type) {
row += type.row * direction;
col += type.col * direction;
if (row >= ROWS || row < 0 || col >= COLS || col < 0 || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col, direction, type);
}
}
// for completeness, adding a Piece
public boolean add(Piece piece, int col) {
int row = 0;
while (row < ROWS && board[row][col] != null) {
row++;
}
if (row < ROWS) {
board[row][col] = piece;
// check for winner after successful add
checkWinner(piece, row, col);
}
return row < ROWS;
}
}
希望这有帮助。