java mtdf ai无法正常工作

时间:2015-04-03 12:50:43

标签: java algorithm artificial-intelligence

我有以下java mtdf A.I.的代码。这是行不通的。这是一个tic tac toe计划。没有错误,但AI正在选择错误的位置。 职位如下。

00 01 02
10 11 12
20 21 22

如果我选择22作为我的选项,AI应选择11作为最佳解决方案。但它选择了错误的价值。代码在Board.test()方法中。 有人可以告诉我是否做错了什么?这是我的代码:

package com.tictactoe;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;


class Point {

int x, y;

public Point(int x, int y) {
    this.x = x;
    this.y = y;
}

@Override
public String toString() {
    return "[" + x + ", " + y + "]";
}

}

class PointsAndScores {

int score;
Point point;

PointsAndScores(int score, Point point) {
    this.score = score;
    this.point = point;
}

public PointsAndScores() {
    if(point==null)point=new Point(0,0);
}
@Override
public String toString() {
    return "[" + point.x + ", " + point.y + "],Score:"+score;
}
}

class Board {
int lowestDepth = 0;
Integer hashValue = new Integer(0);
PointsAndScores bestMove = new PointsAndScores();
List<Point> availablePoints;
Scanner scan = new Scanner(System.in);
int[][] board = new int[3][3];
int[][] tempBoard = new int[3][3];
public boolean isGameOver() {
    //Game is over is someone has won, or board is full (draw)
    return (hasXWon() || hasOWon() ||     this.getAvailablePoints(board).isEmpty());
}

public boolean hasXWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] &&  board[0][0] == 1) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) {
        //System.out.println("X Diagonal Win");
        return true;
    }
    for (int i = 0; i < 3; ++i) {
        if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
                || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
            // System.out.println("X Row or Column win");
            return true;
        }
    }
    return false;
}

public boolean hasOWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) {
        // System.out.println("O Diagonal Win");
        return true;
    }
    for (int i = 0; i < 3; ++i) {
        if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
                || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2)) {
            //  System.out.println("O Row or Column win");
            return true;
        }
    }

    return false;
}

public List<Point> getAvailablePoints(int[][] array) {
    availablePoints = new ArrayList<>();
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (array[i][j] == 0) {
                availablePoints.add(new Point(i, j));
            }
        }
    }
    return availablePoints;
}

public int[][] placeAMove(Point point, int player) {
    board[point.x][point.y] = player;   //player = 1 for X, 2 for O
    return board;
}
void takeHumanInput() {
    System.out.println("Your move: ");
    int x = scan.nextInt();
    int y = scan.nextInt();
    Point point = new Point(x, y);
    placeAMove(point, 2);
}

public void displayBoard() {
    System.out.println();

    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            System.out.print(board[i][j] + " ");
        }
        System.out.println();

    }
} 

public void resetBoard() {
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            board[i][j] = 0;
        }
    }
}
public int evaluateBoard() {
    int score = 0;

    //Check all rows
    for (int i = 0; i < 3; ++i) {
        int blank = 0;
        int X = 0;
        int O = 0;
        for (int j = 0; j < 3; ++j) {
            if (board[i][j] == 0) {
                blank++;
            } else if (board[i][j] == 1) {
                X++;
            } else {
                O++;
            }

        } 
        score+=changeInScore(X, O); 
    }

    //Check all columns
    for (int j = 0; j < 3; ++j) {
        int blank = 0;
        int X = 0;
        int O = 0;
        for (int i = 0; i < 3; ++i) {
            if (board[i][j] == 0) {
                blank++;
            } else if (board[i][j] == 1) {
                X++;
            } else {
                O++;
            } 
        }
        score+=changeInScore(X, O);
    }

    int blank = 0;
    int X = 0;
    int O = 0;

    //Check diagonal (first)
    for (int i = 0, j = 0; i < 3; ++i, ++j) {
        if (board[i][j] == 1) {
            X++;
        } else if (board[i][j] == 2) {
            O++;
        } else {
            blank++;
        }
    }

    score+=changeInScore(X, O);

    blank = 0;
    X = 0;
    O = 0;

    //Check Diagonal (Second)
    for (int i = 2, j = 0; i > -1; --i, ++j) {
        if (board[i][j] == 1) {
            X++;
        } else if (board[i][j] == 2) {
            O++;
        } else {
            blank++;
        }
    }

    score+=changeInScore(X, O);

    return score;
}
private int changeInScore(int X, int O){
    int change;
    if (X == 3) {
        change = 100;
    } else if (X == 2 && O == 0) {
        change = 10;
    } else if (X == 1 && O == 0) {
        change = 1;
    } else if (O == 3) {
        change = -100;
    } else if (O == 2 && X == 0) {
        change = -10;
    } else if (O == 1 && X == 0) {
        change = -1;
    } else {
        change = 0;
    } 
    return change;
}
 private String getHashCode(int[][] board){
     String strHash="";
       for (int i = 0; i < 3; ++i) {
           for (int j = 0; j < 3; ++j) {
               strHash = strHash+board[i][j];
           }
       }
 return strHash;
 }
 private TableEntry test(int[][] board,int maxDepth,int currentDepth,int gamma){
     MTDTicTacToe.LOGGER.log(Level.INFO, "test() started.maxDepth:"+maxDepth+",currentDepth:"+currentDepth+",gamma:"+gamma);
     int currentScore = 0;
     if(currentDepth>lowestDepth){
         lowestDepth=currentDepth;
     }
     TableEntry entry = MTDTicTacToe.mapTranspositionTable.get(getHashCode(board));
     if(entry==null){
         entry = new TableEntry();
         entry.bestMove = new PointsAndScores();
     }
     if(entry!=null && entry.depth>maxDepth-currentDepth){
         // Early outs for stored positions
         if(entry.minScore>gamma){
             entry.bestMove.score=entry.minScore;
             return entry;
         }else if(entry.maxScore<gamma){
             entry.bestMove.score=entry.maxScore;
             return entry;
         }
     }else{//we need to create the entry
         entry.hashValue = getHashCode(board);
         entry.depth = maxDepth - currentDepth;
         entry.minScore = Integer.MIN_VALUE;
         entry.maxScore = Integer.MAX_VALUE; 
        // Now we have the entry, we can get on with the test
     }
     MTDTicTacToe.mapTranspositionTable.put(getHashCode(board),entry);
     //Check if we’re done recursing 
     if(this.isGameOver() || currentDepth == maxDepth){
          entry.minScore = entry.maxScore = this.evaluateBoard();
          entry.bestMove.score=entry.minScore;
          this.bestMove.point = entry.bestMove.point;
          return entry;
     }
     // Now go into bubbling up mode 
     bestMove = new PointsAndScores();
     bestMove.score=Integer.MIN_VALUE;
     int[][] newBoard=new int[3][3];
     MTDTicTacToe.copyArrayUtil(board,newBoard);
     TableEntry entry2;
     for(Point point:this.getAvailablePoints(newBoard)){
         newBoard[point.x][point.y]=1;
         entry2 = test(newBoard,maxDepth,currentDepth+1,-gamma);
         currentScore = - entry2.bestMove.score;
         //Update the best score 
         if(currentScore > bestMove.score){// Track the current best move 
             entry.bestMove.point = point ;
             entry.bestMove.score = currentScore;
             bestMove.score = currentScore;
             bestMove.point = point;
         }
      //MTDTicTacToe.LOGGER.log(Level.INFO,"ENTRY####2:"+entry2);
     }
     //If we pruned, then we have a min score, otherwise we have a max score.
     if(bestMove.score< gamma){
         entry.maxScore = bestMove.score;
     } else{
         entry.minScore = bestMove.score;
     }
    //MTDTicTacToe.LOGGER.log(Level.INFO,"tableEntries:"+MTDTicTacToe.mapTranspositionTable);
     MTDTicTacToe.LOGGER.log(Level.INFO, "test() Ended.maxDepth:"+maxDepth+",currentDepth:"+currentDepth+",gamma:"+gamma+",entry:"+entry);
     //Store the entry and return the best score and move. 
     return entry;
 }
 private TableEntry mtd(int maxDepth,int guess){
     int MAX_ITERATIONS = 1;//10;
     TableEntry entry=null;
     for(int i=0;i<MAX_ITERATIONS;i++){
         int gamma = guess;
         entry = test(board,maxDepth,0,gamma-1);
          guess = entry.bestMove.score;
         if(gamma==guess){break;}
     }
     return entry;
 }
 public TableEntry mtdf(int maxDepth){
     maxDepth=3;
     TableEntry entry=null;
     int guess=0;
     for(int depth=2;depth<maxDepth;depth++){
         entry = mtd(depth,guess);
         //TODO if(timeout)break;
     }
     return entry;
 }

public void placeAMove(Point point) {
    board[point.x][point.y] = 1;   //player = 1 for X, 2 for O
}
}
class TableEntry{
String hashValue;
int minScore;
int maxScore;
PointsAndScores bestMove;
int depth;

@Override
public String toString() {
    return "hashValue:" + hashValue +",minscore:"+minScore+",maxscore:"+maxScore+ ",bestMove:" + bestMove + ",depth:"+depth+"\n";
}

}
public class MTDTicTacToe {
public static Map<String,TableEntry> mapTranspositionTable = new HashMap<String,TableEntry>();
   static final Logger LOGGER = Logger.getLogger(MTDTicTacToe.class.getName());
 public static void main(String[] args) throws Exception{ 
     Handler fileHandler  = new FileHandler("./MTDTicTacToe.log");
     LOGGER.addHandler(fileHandler);
     fileHandler.setLevel(Level.ALL);
     LOGGER.setLevel(Level.ALL);

        Board b = new Board();
        Random rand = new Random();

        b.displayBoard();

        System.out.println("Who's gonna move first? (1)Computer (2)User: ");
        int choice = b.scan.nextInt();
        if (choice == 1) {
            Point p = new Point(rand.nextInt(3), rand.nextInt(3));
            b.placeAMove(p, 1);
            b.displayBoard();
        }
        int maxDepth=10;
        TableEntry entry=null;
        while (!b.isGameOver()) {
            System.out.println("Your move: ");
            Point userMove = new Point(b.scan.nextInt(), b.scan.nextInt());

            b.placeAMove(userMove, 2); //2 for O and O is the user
            b.displayBoard();
            if (b.isGameOver()) break;

            copyArrayUtil(b.board,b.tempBoard);

            entry=b.mtdf(maxDepth);
            copyArrayUtil(b.tempBoard,b.board);
            b.placeAMove(entry.bestMove.point);//move player 1 - computer
            b.displayBoard();
        }

        if (b.hasXWon()) {
            System.out.println("Unfortunately, you lost!");
        } else if (b.hasOWon()) {
            System.out.println("You win!");
        } else {
            System.out.println("It's a draw!");
        }
         LOGGER.log(Level.INFO, "Tic tac toe game Ended.");
 }

 public static void copyArrayUtil(int[][] t1,int[][] t2){
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            t2[i][j] = t1[i][j];
        }
    }
 }
    }

0 个答案:

没有答案