【发布时间】:2019-03-24 15:11:17
【问题描述】:
我在为我的国际象棋游戏实施 MiniMax 算法时遇到问题。它的大部分似乎都有效,但它要么永远不会做出好的动作,要么对它们的评估(基于两个玩家的活跃棋子的分数)有问题。 例如,如果我设置检查(例如傻瓜的伴侣),人工智能会做一些随机的事情而不是杀死国王。我真的无法指出我做错了什么。
评估板的类 StandardBoardEvaluator 在经过一些测试后似乎可以工作,因此问题很可能在 MiniMax 实现中的某个地方。游戏由一个 Board 类组成,它具有我自己的 Square 类的 8x8 对象的 2D 数组,它本身具有对 Piece 的引用(可以为 null,或任何典型的棋子)。 在算法中,我不断地在 searchthree 中创建新的 Board 实例,这就是为什么我在 Board 和 Square 中制作这些“深度克隆”构造函数的原因,所以这似乎不是问题。像这样:
public Board(Board originalBoard) {
this.turnIsWhite = originalBoard.getTurnIsWhite();
winner = null;
squares = new Square[8][8];
for (int rank=0; rank<squares.length; rank++) {
for(int file=0; file<squares[rank].length; file++) {
squares[rank][file] = new Square(originalBoard.getSquare(posStringFromFileRank(rank, file)));
}
}
}
与
public Square(Square originalSquare) {
this.pos = new String(originalSquare.getPos());
this.piece = originalSquare.getPiece();
}
我有一个典型的命令类,MovePiece,用于移动棋子。这使用另一个类 MoveCheck 来检查移动命令是否合法。 MovePiece 返回一个布尔值,表示移动是否合法。这两个类都经过了严格的测试并且正在运行,所以我认为问题不在这些类中。
这是算法:
public class MiniMax implements MoveStrategy{
BoardEveluator bV;
MoveGenerator mGen;
int depth;
public MiniMax(int depth){
bV = new StandardBoardEvaluator();
mGen = new MoveGenerator();
this.depth = depth;
}
@Override
public MovePiece execute(Board board) {
MovePiece bestMove = null;
int lowestValue = Integer.MAX_VALUE;
int highestValue = Integer.MIN_VALUE;
int currentValue = 0;
String color = (board.getTurnIsWhite() ? "white" : "black");
System.out.println(color + " is evaluation best move with MiniMax depth " + depth);
List<MovePiece> allPossibleMoves = mGen.getLegalMoves(board, board.getTurnIsWhite());
for (MovePiece mp : allPossibleMoves){
Board tempBoard = new Board(board);
mp.setBoard(tempBoard);
if (mp.execute()){
currentValue = tempBoard.getTurnIsWhite() ? min(tempBoard, depth -1) : max(tempBoard, depth -1);
if (board.getTurnIsWhite() && currentValue >= highestValue){
highestValue = currentValue;
bestMove = mp;
}
else if (!board.getTurnIsWhite() && currentValue <= lowestValue){
lowestValue = currentValue;
bestMove = mp;
}
mp.unexecute();
}
}
return bestMove;
}
int min (Board board, int depth){
if (depth == 0 || board.getWinner() != null){
return bV.eveluate(board);
}
int lowestValue = Integer.MAX_VALUE;
List<MovePiece> legalMoves = mGen.getLegalMoves(board, board.getTurnIsWhite());
for (MovePiece mp : legalMoves){
Board tempBoard = new Board(board);
mp.setBoard(tempBoard);
if (mp.execute()){
int currentValue = max(tempBoard, depth - 1);
if (currentValue <= lowestValue){
lowestValue = currentValue;
}
mp.unexecute();
}
}
return lowestValue;
}
int max (Board board, int depth){
if (depth == 0 || board.getWinner() != null){
return bV.eveluate(board);
}
int highestValue = Integer.MIN_VALUE;
List<MovePiece> legalMoves = mGen.getLegalMoves(board, board.getTurnIsWhite());
for (MovePiece mp : legalMoves){
Board tempBoard = new Board(board);
mp.setBoard(tempBoard);
if (mp.execute()){
int currentValue = min(tempBoard, depth - 1);
if (currentValue >= highestValue){
highestValue = currentValue;
}
mp.unexecute();
}
}
return highestValue;
}
还有评估者类
public class StandardBoardEvaluator implements BoardEveluator {
private int scorePlayer(Board board, boolean isWhite){
return pieceValue(board, isWhite) + mobolity(isWhite, board);
}
private int mobolity(boolean isWhite, Board board){
return (int) (board.getActiveSquares(isWhite).size() * 1.5);
}
private static int pieceValue(Board board, boolean isWhite){
int piceValueScore = 0;
for (Square square : board.getActiveSquares(isWhite)){
piceValueScore += square.getPiece().getPieceValue();
}
return piceValueScore;
}
@Override
public int eveluate(Board board) {
return scorePlayer(board, true) - scorePlayer(board, false);
}
}
这是 MovePiece 类:
private Square from;
private Square to;
private Board board;
private MoveCheck mCheck;
private RulesCheck rCheck;
private boolean done = false;
private Piece killed;
public MovePiece(Board board, String from, String to) {
this.board = board;
this.from = board.getSquare(from);
this.to = board.getSquare(to);
mCheck = new MoveCheck();
}
public MovePiece(Board board, Square from, Square to) {
this.board = board;
this.from = from;
this.to = to;
mCheck = new MoveCheck();
rCheck = new RulesCheck(board);
}
public void setBoard(Board board) {
this.board = board;
}
public Board getBoard() {
return board;
}
public Square getFrom() {
return from;
}
public Square getTo() {
return to;
}
public void setFrom(Square from) {
this.from = from;
}
public void setTo(Square to) {
this.to = to;
}
public void setFrom(String from) {
this.from = board.getSquare(from);
}
public void setTo(String to) {
this.to = board.getSquare(to);
}
@Override
public boolean execute() {
rCheck = new RulesCheck(board);
if (done) {
board.movePiece(from, to);
return true;
}
else if (mCheck.isLegal(board, from, to)){
if (to.getPiece() != null) {
killed = to.getPiece();
rCheck.winCheck(killed);
}
board.setGameOutput("Moved " + from.pieceToString() + " at " + from.getPos() + " - to " + to.getPos() + "(" + to.pieceToString() + ")");
board.movePiece(from, to);
rCheck.checkPromotion(to);
done = true;
return true;
}
return false;
}
@Override
public void unexecute() {
if (to.getPiece().getClass() == Pawn.class)
((Pawn) to.getPiece()).decreaseMoves();
board.movePiece(to, from);
if (killed != null) {
to.setPiece(killed);
}
}
MoveCheck 类仅查看移动对于棋子是否合法(路径清晰,目标是敌人还是空等),不要认为这与我的问题有关,因为代码已经过测试并且可以工作。
片段值在抽象类 Piece 的子类(所有片段类型)中声明为 int。兵100分,象马300分,车500分,后900分,国王10000分。
如果有人能帮助我找出问题所在,我将永远感激不尽!如果您需要查看我没有显示的其他代码,请告诉我。
【问题讨论】:
-
你解决问题了吗?
-
不幸的是,我厌倦了我,所以我一起切换了算法。我可能会在其他时间回顾它,但现在我不能被打扰。不过感谢您的帮助!我很感激。