Java 什么';我的井字游戏有什么问题吗?
我读了一篇关于minimax的教程,并试图制作一个tac-tac-toe人工智能。 但是,由于某种原因,代码不能最佳工作,我找不到。人工智能可以放置碎片,但它不是智能人工智能。我希望它是不可战胜的。深度越高,ai变得越愚蠢。 “游戏”是我的另一个类,实际的游戏在那里Java 什么';我的井字游戏有什么问题吗?,java,artificial-intelligence,tic-tac-toe,minimax,Java,Artificial Intelligence,Tic Tac Toe,Minimax,我读了一篇关于minimax的教程,并试图制作一个tac-tac-toe人工智能。 但是,由于某种原因,代码不能最佳工作,我找不到。人工智能可以放置碎片,但它不是智能人工智能。我希望它是不可战胜的。深度越高,ai变得越愚蠢。 “游戏”是我的另一个类,实际的游戏在那里 private Game game; private Piece[][] board; private Piece ai = Piece.CIRCLE; private Piece player = Piece.CROSS; pu
private Game game;
private Piece[][] board;
private Piece ai = Piece.CIRCLE;
private Piece player = Piece.CROSS;
public AI(Game game) {
this.game = game;
this.board = game.getBoard();
}
public int[] move() {
int[] result = minimax(1, ai);
return new int[] {result[1], result[2]};
}
private int[] minimax(int depth, Piece piece) {
List<int[]> possibleMoves = generateMoves();
int bestScore = (piece == ai) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
int currentScore;
int bestRow = -1;
int bestCol = -1;
if (possibleMoves.isEmpty() || depth == 0) {
// Game over or depth reached
bestScore = evaluate();
}
else {
for (int[] move : possibleMoves) {
// Try this move for the player
board[move[0]][move[1]] = player;
if (piece == ai) { // ai is maximizing player
currentScore = minimax(depth - 1, player)[0];
if (currentScore > bestScore) {
bestScore = currentScore;
bestRow = move[0];
bestCol = move[1];
}
}
else { // player is minimizing player
currentScore = minimax(depth - 1, ai)[0];
if (currentScore < bestScore) {
bestScore = currentScore;
bestRow = move[0];
bestCol = move[1];
}
}
// Undo move
board[move[0]][move[1]] = null;
}
}
return new int[] {bestScore, bestRow, bestCol};
}
private List<int[]> generateMoves() {
List<int[]> possibleMoves = new ArrayList<int[]>();
// If game over
if (game.getWinner() != null) {
return possibleMoves; // return empty list
}
// Add possible moves to list
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if (game.getBoard()[x][y] == null) {
possibleMoves.add(new int[] {x, y});
}
}
}
return possibleMoves;
}
private int evaluate() {
int score = 0;
// Evaluate
score += evaluateLine(0, 0, 0, 1, 0, 2); // row 0
score += evaluateLine(1, 0, 1, 1, 1, 2); // row 1
score += evaluateLine(2, 0, 2, 1, 2, 2); // row 2
score += evaluateLine(0, 0, 1, 0, 2, 0); // col 0
score += evaluateLine(0, 1, 1, 1, 2, 1); // col 0
score += evaluateLine(0, 2, 1, 2, 2, 2); // col 0
score += evaluateLine(0, 0, 1, 1, 2, 2); // diag 1
score += evaluateLine(0, 2, 1, 1, 2, 0); // diag 2
return score;
}
// Return +100, +10, +1 for 3-, 2-, 1-in-a-line for ai
// Return -100, -10, -1 for 3-, 2-, 1-in a line for player
// Else return 0
private int evaluateLine(int row1, int col1, int row2, int col2, int row3, int col3) {
int score = 0;
// First cell
if (board[row1][col1] == ai) {
score = 1;
}
else if (board[row1][col1] == player) {
score = -1;
}
// Second cell
if (board[row2][col2] == ai) {
if (score == 1) { // board1 is ai
score = 10;
}
else if (score == -1) { // board1 is player
return 0;
}
else { // board1 is empty
score = 1;
}
}
else if (board[row2][col2] == player) {
if (score == -1) { // board1 is player
score = -10;
}
else if (score == 1) { // board1 is ai
return 0;
}
else { // board1 is empty
score = -1;
}
}
// Third cell
if (board[row3][col3] == ai) {
if (score > 0) { // board1 and/or board2 is ai
score *= 10;
}
else if (score < 0) { // board1 and/or board2 is player
return 0;
}
else { // board1 and/or board2 is empty
score = 1;
}
}
else if (board[row3][col3] == player) {
if (score < 0) { // board1 and/or board2 is player
score *= 10;
}
else if (score > 1) { // board1 and/or board2 is ai
return 0;
}
else { // board1 and/or board2 is empty
score = -1;
}
}
return score;
}
私人游戏;
私有件[][]板;
私有工件ai=工件圆;
私人棋手=棋子.CROSS;
公共AI(游戏){
这个游戏=游戏;
this.board=game.getBoard();
}
公共int[]移动(){
int[]结果=极小极大值(1,ai);
返回新的int[]{result[1],result[2]};
}
私有整数[]最小最大值(整数深度,单件){
List possibleMoves=generateMoves();
int bestScore=(工件==ai)?Integer.MIN_值:Integer.MAX_值;
int-currentScore;
int bestRow=-1;
int-bestCol=-1;
if(possibleMoves.isEmpty()| | depth==0){
//游戏结束或达到深度
最佳分数=评估();
}
否则{
for(int[]移动:可能移动){
//为玩家试试这个动作
棋盘[移动[0]][移动[1]]=玩家;
如果(件==ai){//ai是最大化玩家
currentScore=minimax(深度-1,玩家)[0];
如果(当前分数>最佳分数){
最佳分数=当前分数;
bestRow=移动[0];
bestCol=move[1];
}
}
否则{//player将最小化player
currentScore=minimax(深度-1,ai)[0];
如果(当前分数<最佳分数){
最佳分数=当前分数;
bestRow=移动[0];
bestCol=move[1];
}
}
//撤消移动
单板[move[0]][move[1]]=null;
}
}
返回新的int[]{bestScore,bestRow,bestCol};
}
私有列表generateMoves(){
List possibleMoves=new ArrayList();
//如果比赛结束
if(game.getWinner()!=null){
return possibleMoves;//返回空列表
}
//将可能的移动添加到列表中
对于(int x=0;x<3;x++){
对于(int y=0;y<3;y++){
if(game.getBoard()[x][y]==null){
add(新的int[]{x,y});
}
}
}
返回可能的动作;
}
private int evaluate(){
智力得分=0;
//评估
分数+=评估线(0,0,0,1,0,2);//第0行
分数+=评估线(1,0,1,1,1,2);//第1行
分数+=评估线(2,0,2,1,2,2);//第2行
分数+=评估线(0,0,1,0,2,0);//列0
分数+=评估线(0,1,1,1,2,1);//列0
分数+=评估线(0,2,1,2,2,2);//列0
分数+=评估线(0,0,1,1,2,2);//诊断1
分数+=评估线(0,2,1,1,2,0);//诊断2
返回分数;
}
//返回+100、+10、+1表示人工智能的3-、2-、1-in-a-line
//返回-100,-10,-1代表3-,2-,1-在一条线上代表玩家
//否则返回0
私有int-evaluateLine(int-row1、int-col1、int-row2、int-col2、int-row3、int-col3){
智力得分=0;
//第一单元
if(线路板[row1][col1]==ai){
得分=1分;
}
else if(棋盘[row1][col1]==玩家){
得分=-1;
}
//第二单元
if(板[row2][col2]==ai){
如果(分数=1){//1是ai
得分=10分;
}
如果(分数==-1){//board1是玩家,则为else
返回0;
}
否则{//board1为空
得分=1分;
}
}
else if(棋盘[row2][col2]==玩家){
如果(分数==-1){//board1是玩家
分数=-10;
}
否则,如果(分数==1){//1是ai
返回0;
}
否则{//board1为空
得分=-1;
}
}
//第三单元
if(板[row3][col3]==ai){
如果(分数>0){//board1和/或board2为ai
分数*=10;
}
否则,如果(分数<0){//board1和/或board2是玩家
返回0;
}
否则{//board1和/或board2为空
得分=1分;
}
}
else if(棋盘[row3][col3]==玩家){
如果(分数<0){//board1和/或board2是玩家
分数*=10;
}
如果(得分>1){//board1和/或board2为ai,则为else
返回0;
}
否则{//board1和/或board2为空
得分=-1;
}
}
返回分数;
}
minimax
返回的是行/列对移动,而不是分数。所以
currentScore = minimax(depth - 1, player)[0];
毫无意义。这可能会导致移动到第3行比移动到第1行或第2行看起来更好
minmax
需要手动操作除了最佳移动之外,还返回一个分数。
minimax
返回的是行/列对移动,而不是分数。所以
currentScore = minimax(depth - 1, player)[0];
毫无意义。这可能会导致移动到第3行比移动到第1行或第2行看起来更好
minmax
需要手动操作除了最精彩的一步之外,我还记下了一个分数。我注意到了以下几点:
- 循环中的第一行表示
board[move[0]][move[1]]=player代码>。那应该是
而不是piece
,现在你的AI认为只有人类玩家的片段才会出现在棋盘上player
- 极小极大应该很容易在不到一秒钟的时间内搜索到完整的博弈树。因此,我建议允许搜索任意深度,而不是将搜索深度限制为1。这也将消除创建启发式评估函数的需要;赢了你只会给一个高分,平了你只会给0分,输了你只会给一个非常负的分数。我建议这样做的主要原因是,我怀疑求值函数也可能有问题,尽管我不确定,因为我不知道