Пробовал отлаживать мой код MiniMax, но не нашел здесь проблемы. Основной метод — evalGame()
, который возвращает 1 при победе, -1 при проигрыше и 0 при ничьей. Есть ли очевидные ошибки, которые я допустил в алгоритме MiniMax?
package tictactoe;
import static tictactoe.Player.*;
import java.util.Arrays;
public class MinimaxTTT {
private Player[] board = new Player[9];
private static Player player = X;
public MinimaxTTT() {
Arrays.fill(board, E);
player = X;
}
public MinimaxTTT(Player[] b, Player p) {
for(int i = 0; i < 9; i++) {
board[i] = b[i];
}
player = p;
}
public static boolean checkWin(Player[] b, Player p) {
if((b[0]==p&&b[1]==p&&b[2]==p)
|| (b[0]==p&&b[3]==p&&b[6]==p)
|| (b[0]==p&&b[4]==p&&b[8]==p)
|| (b[0]==p&&b[1]==p&&b[2]==p)
|| (b[1]==p&&b[4]==p&&b[7]==p)
|| (b[0]==p&&b[1]==p&&b[2]==p)
|| (b[2]==p&&b[4]==p&&b[6]==p)
|| (b[2]==p&&b[5]==p&&b[8]==p)
|| (b[0]==p&&b[3]==p&&b[6]==p)
|| (b[3]==p&&b[4]==p&&b[5]==p)
|| (b[0]==p&&b[4]==p&&b[8]==p)
|| (b[2]==p&&b[4]==p&&b[6]==p)
|| (b[3]==p&&b[4]==p&&b[5]==p)
|| (b[1]==p&&b[4]==p&&b[7]==p)
|| (b[2]==p&&b[5]==p&&b[8]==p)
|| (b[3]==p&&b[4]==p&&b[5]==p)
|| (b[0]==p&&b[3]==p&&b[6]==p)
|| (b[2]==p&&b[4]==p&&b[6]==p)
|| (b[6]==p&&b[7]==p&&b[8]==p)
|| (b[6]==p&&b[7]==p&&b[8]==p)
|| (b[1]==p&&b[4]==p&&b[7]==p)
|| (b[2]==p&&b[5]==p&&b[8]==p)
|| (b[6]==p&&b[7]==p&&b[8]==p)
|| (b[0]==p&&b[4]==p&&b[8]==p)) {
return true;
}
return false;
}
private static boolean checkTie(Player[] b) {
for(int i = 0; i < 9; i++) {
if(b[i] == E) {
return false;
}
}
return true;
}
private static boolean gameOver(Player[] b) {
return checkTie(b) || checkWin(b, X) || checkWin(b, O);
}
private static int maxOfArray(int[] a) {
int max = a[0];
for (int i : a)
if (max < i)
max = i;
return max;
}
private static int minOfArray(int[] a) {
int min = a[0];
for (int i : a)
if (min > i)
min = i;
return min;
}
private static int getEmptyNumber(Player[] b) {
int spaces = 0;
for(int i = 0; i < 9; i++) {
if(b[i] == E)
spaces++;
}
return spaces;
}
private static int evalGame(Player[] b, Player p, Player currentP) {
if(gameOver(b)) {
if(checkWin(b, p)) {
return 1;
} else if(checkWin(b, p == X ? O : X)) {
return -1;
} else {
return 0;
}
} else {
int[] arrayEval = new int[getEmptyNumber(b)];
for(int i = 0; i < getEmptyNumber(b); i++) {
arrayEval[i] = evalGame(possibleBoards(b, currentP)[i], p, currentP == X ? O : X);
}
if(currentP == p) {
return maxOfArray(arrayEval);
} else {
return minOfArray(arrayEval);
}
}
}
public static Player[][] possibleBoards(Player[] b, Player p) {
Player[][] toReturn = new Player[getEmptyNumber(b)][9];
int spaces = 0;
for(int i = 0; i < 9; i++) {
if(b[i] == E) {
for(int j = 0; j < 9; j++) {
toReturn[spaces][j] = b[j];
}
toReturn[spaces][i] = p;
spaces++;
}
}
return toReturn;
}
public static void main(String[] args) {
Player[] p = new Player[9];
Arrays.fill(p, E);
p[1] = X;
System.out.println(evalGame(p, O, O));
}
}
X
иO
(какой тип данных) в вызовахcheckWin
и т.п.? Я предполагаю, что это константы, объявления которых вы не публиковали? - person mbomb007   schedule 18.12.2014if(checkWin(b, p)) { return 1; } else if(checkWin(b, p == X ? O : X)) { return -1; } else { return 0; }
Я думаю, чтоreturn 0
означает ничью. - person Charlie   schedule 18.12.2014checkWin
? - person Max Meijer   schedule 18.12.2014gameOver()
должен проверить, есть ли в матрице незаполненные квадраты. Не следует проверять, кто победит. Кроме того, вы проверяете ничью, и если это возвращает false, есть победитель, вам не нужны два вызоваcheckWin()
. Этот метод может возвращать (например) false, если X выигрывает, и true в противном случае. Имеет ли это смысл? - person hfontanez   schedule 18.12.2014gameOver
возвращает значение true, если ни один элемент массива не содержит нулевой символ. Для проверки win arr[?][0], arr[?][0] и arr[?][0] должны иметь один и тот же символ, ИЛИ arr[0][?], arr[1][?], и arr[2][?] должны иметь один и тот же символ, ИЛИ arr[0][0], arr[1][1], и arr[2][2] должны иметь один и тот же символ, ИЛИ arr[0] [2], arr[1][1] и arr[2][0] должны иметь один и тот же символ. Что-то такое... - person hfontanez   schedule 18.12.2014checkWin()
проверил много повторяющихся строк игрового поля. Обратите внимание, что есть только 8 возможных выигрышных 3-в-рядов: 3 по горизонтали, 3 по вертикали и 2 по диагонали. - person mbomb007   schedule 18.12.2014gameOver()
должен проверять только пустые квадраты? Я думаю, что мое объяснение выше заключается в том, как должны быть построены методы. - person hfontanez   schedule 18.12.2014if(gameOver(b)) {
можно было бы даже удалить. Он выполняет одну и ту же проверку 4 или более раз. Хотя не думаю, что это корень проблемы. Программу было бы легче понять, если бы вместо этого у игрока было свойство, которое было установлено либо наX
, либо наO
, тогда вы передаете как доску, так и игрока, чтобы проверить наличие пустых квадратов или выигрыш. Затем при проверке выигрыша вы можете использоватьp.letter
или что-то еще. - person mbomb007   schedule 18.12.2014