Я делаю игру Connect 4. Цель состоит в том, чтобы выровнять четыре элемента одинаково.
У меня есть двойной массив: Player[6][7]
, который заполняется игроком, игравшим в этом слоте.
Я работаю над условиями победы, есть:
И диагонали не работают.
Вот мой код, который проверяет победы:
private final Player[][] board = new Player[6][7]; // the board filled
public Player hasWinner() {
// Lines (rows)
for(int y = 0; y < board.length; y++) { // simple lines
Player last = null;
int nb = 0;
Player[] line = board[y];
for(int x = 0; x < line.length; x++) {
Player played = line[x];
if ((last == null || played == last) && played != null) { // new player or same as before
nb++;
if (nb == 4) // it's this !
return played;
} else { // else reset
nb = (played == null ? 0 : 1);
}
last = played;
}
}
// Columns
for(int x = 0; x < board[0].length; x++) { // simple columns
Player last = null;
int nb = 0;
for(int y = 0; y < board.length; y++) { // for each columns
Player played = board[y][x];
if ((last == null || played == last) && played != null) { // new player or same as before
nb++;
if (nb == 4) // it's this !
return played;
} else { // else reset
nb = (played == null ? 0 : 1);
}
last = played;
}
}
// ➡️ HERE IS THE INTERESTING PART
// Diagonals
for(int i = -board.length; i < board[0].length; i++) { // diagonals
Player last = null;
int nb = 0;
for(int j = 0; j < 9; j++) {
if (board.length <= j || board[j].length <= j)
continue;
Player played = board[j][j];
if ((last == null || played == last) && played != null) { // new player or same as before
nb++;
if (nb == 4) // it's this !
return played;
} else { // else reset
nb = (played == null ? 0 : 1);
}
last = played;
}
for(int j = 9; j < 0; j--) {
if (board.length <= j || board[j].length <= j)
continue;
Player played = board[j][board[j].length - j];
if ((last == null || played == last) && played != null) { // new player or same as before
nb++;
if (nb == 4) // it's this !
return played;
} else { // else reset
nb = (played == null ? 0 : 1);
}
last = played;
}
}
return null;
}
Как сделать так, чтобы победа с диагоналями работала?
Я бы это сделал так: hasWinner(Player[] slots)
тогда вы могли бы создавать новые массивы со своей доски для проверки и передавать их в has Winner. Логика hasWinner будет очень простой — пройтись по массиву и найти четыре подряд.
Избегайте магических чисел, таких как 9
. Используйте длину строк и столбцов матрицы в качестве верхних границ. Укажите константу для размера совпадения, например 4.
Что касается диагоналей, сравните текущего игрока с направлением [row + dy, col + dx]
.
public class Connect4 {
private static final int ROWS = 6;
private static final int COLS = 7;
private static final int MATCH_SIZE = 4; // Number of pieces needed to win
private final Player[][] board = new Player[ROWS][COLS]; // the board
public Player hasWinner() {
// Check horizontal lines
for (int y = 0; y < board.length; y++) {
Player last = null;
int count = 0;
for (int x = 0; x < board[y].length; x++) {
Player current = board[y][x];
if (current != null && current == last) {
count++;
if (count == MATCH_SIZE) {
return current;
}
} else {
count = 1;
last = current;
}
}
}
// Check vertical lines
for (int x = 0; x < board[0].length; x++) {
Player last = null;
int count = 0;
for (int y = 0; y < board.length; y++) {
Player current = board[y][x];
if (current != null && current == last) {
count++;
if (count == MATCH_SIZE) {
return current;
}
} else {
count = 1;
last = current;
}
}
}
// Check diagonal lines (top-left to bottom-right)
for (int y = 0; y <= board.length - MATCH_SIZE; y++) {
for (int x = 0; x <= board[y].length - MATCH_SIZE; x++) {
Player current = board[y][x];
if (current != null &&
current == board[y + 1][x + 1] &&
current == board[y + 2][x + 2] &&
current == board[y + 3][x + 3]) {
return current;
}
}
}
// Check diagonal lines (bottom-left to top-right)
for (int y = MATCH_SIZE - 1; y < board.length; y++) {
for (int x = 0; x <= board[y].length - MATCH_SIZE; x++) {
Player current = board[y][x];
if (current != null &&
current == board[y - 1][x + 1] &&
current == board[y - 2][x + 2] &&
current == board[y - 3][x + 3]) {
return current;
}
}
}
return null; // No winner found
}
}
Повторений много, мы можем использовать направления для сканирования строк, столбцов и т. д.
public class Connect4 {
private static final int ROWS = 6;
private static final int COLS = 7;
private static final int MATCH_SIZE = 4; // Number of pieces needed to win
private final Player[][] board = new Player[ROWS][COLS]; // the board
public Player hasWinner() {
for (int y = 0; y < ROWS; y++) {
for (int x = 0; x < COLS; x++) {
Player current = board[y][x];
if (current == null) {
continue;
}
// Check right (horizontal)
if (x <= COLS - MATCH_SIZE && checkDirection(y, x, 0, 1)) {
return current;
}
// Check down (vertical)
if (y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, 0)) {
return current;
}
// Check down-right (diagonal)
if (x <= COLS - MATCH_SIZE && y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, 1)) {
return current;
}
// Check down-left (anti-diagonal)
if (x >= MATCH_SIZE - 1 && y <= ROWS - MATCH_SIZE && checkDirection(y, x, 1, -1)) {
return current;
}
}
}
return null; // No winner found
}
private boolean checkDirection(int y, int x, int dy, int dx) {
Player player = board[y][x];
for (int i = 1; i < MATCH_SIZE; i++) {
if (board[y + i * dy][x + i * dx] != player) {
return false;
}
}
return true;
}
}
board[j][j]
иboard[j][board[j].length - j]
— это только (своего рода) главные диагонали; но поскольку нам нужно только 4 из 6х7, диагоналей гораздо больше (например,[j][j+1]
,[j+1][j]
) - я бы проверял после каждого хода, завершает ли новая фигура четыре подряд