📄 minimaxplayer.java
字号:
// MinimaxPlayer.java
/**
*
* @author Sean Bridges
* @version 1.0
*
* The MinimaxPlayer uses the minimax algorithm to determine what move it should
* make. Looks ahead depth moves. The number of moves will be on the order
* of n^depth, where n is the number of moves possible, and depth is the number
* of moves the engine is searching. Because of this the minimax player periodically
* polls the thread that calls getMove(..) to see if it was interrupted. It the thread
* is intertupted, the player returns null after it checks.
*/
public class MinimaxPlayer extends DefaultPlayer
{
//----------------------------------------------
//instance variables
//the number of levels minimax will look ahead
private int depth = 1;
private Player minPlayer;
//----------------------------------------------
//constructors
/** Creates new MinimaxPlayer */
public MinimaxPlayer(String name, int number, Player minPlayer)
{
super(name, number);
this.minPlayer = minPlayer;
}
//----------------------------------------------
//instance methods
/**
* Get the number of levels that the Minimax Player is currently looking
* ahead.
*/
public int getDepth()
{
return depth;
}
/**
* Set the number of levels that the Minimax Player will look ahead
* when getMove is next called
*/
public void setDepth(int anInt)
{
depth = anInt;
}
/** Passed a copy of the board, asked what move it would like to make.
*
* The MinimaxPlayer periodically polls the thread that makes this call to
* see if it is interrupted. If it is the player returns null.
*
* Looks ahead depth moves.
*/
public Move getMove(Board b)
{
MinimaxCalculator calc = new MinimaxCalculator(b,this,minPlayer);
return calc.calculateMove(depth);
}
}//end MinimaxPlayer
/**
* The MinimaxCalculator does the actual work of finding the minimax move.
* A new calculator should be created each time a move is to be made.
* A calculator should only be used once.
*/
final class MinimaxCalculator
{
//-------------------------------------------------------
//instance variables
//the number of moves we have tried
private int moveCount = 0;
private long startTime;
private Player minPlayer;
private Player maxPlayer;
private Board board;
private final int MAX_POSSIBLE_STRENGTH;
private final int MIN_POSSIBLE_STRENGTH;
//-------------------------------------------------------
//constructors
MinimaxCalculator(Board b, Player max, Player min)
{
board = b;
maxPlayer = max;
minPlayer = min;
MAX_POSSIBLE_STRENGTH = board.getBoardStats().getMaxStrength();
MIN_POSSIBLE_STRENGTH = board.getBoardStats().getMinStrength();
}
//-------------------------------------------------------
//instance methods
/**
* Calculate the move to be made.
*/
public Move calculateMove(int depth)
{
startTime = System.currentTimeMillis();
if(depth == 0)
{
System.out.println("Error, 0 depth in minumax player");
Thread.dumpStack();
return null;
}
Move[] moves = board.getPossibleMoves(maxPlayer);
int maxStrength = MIN_POSSIBLE_STRENGTH;
int maxIndex = 0;
for(int i = 0; i < moves.length; i++)
{
if(board.move(moves[i]))
{
moveCount++;
int strength = expandMinNode(depth -1, maxStrength);
if(strength > maxStrength)
{
maxStrength = strength;
maxIndex = i;
}
board.undoLastMove();
}//end if move made
//if the thread has been interrupted, return immediately.
if(Thread.currentThread().isInterrupted())
{
return null;
}
}//end for all moves
long stopTime = System.currentTimeMillis();
System.out.print("MINIMAX: Number of moves tried:" + moveCount);
System.out.println(" Time:" + (stopTime - startTime) + " milliseconds");
return moves[maxIndex];
}
/**
* A max node returns the max score of its descendents.
* parentMinimum is the minumum score that the parent has already encountered.
* if we find a score that is higher than this, we will return that score
* immediately rather than continue to expand the tree, since
* the min node above us only cares if we are lower than its current
* min score.
*/
private int expandMaxNode(int depth, int parentMinimum)
{
//base step
if(depth == 0 || board.isGameOver())
{
return board.getBoardStats().getStrength(maxPlayer);
}
//recursive step
Move[] moves = board.getPossibleMoves(maxPlayer);
int maxStrength = MIN_POSSIBLE_STRENGTH;
for(int i = 0; i < moves.length; i++)
{
if(board.move(moves[i]))
{
moveCount++;
int strength = expandMinNode(depth -1, maxStrength);
if(strength > parentMinimum)
{
board.undoLastMove();
return strength;
}
if(strength > maxStrength)
{
maxStrength = strength;
}
board.undoLastMove();
}//end if move made
}//end for all moves
return maxStrength;
}//end expandMaxNode
/**
* The min node chooses the smallest of its descendents.
* parentMaximum is the maximum that the parent max node has already found,
* if we find something smaller than this, return immediatly, since the
* parent max node will choose the greatest value it can find.
*/
private int expandMinNode(int depth, int parentMaximum)
{
//base step
if(depth == 0 || board.isGameOver())
{
return board.getBoardStats().getStrength(maxPlayer);
}
//recursive step
Move[] moves = board.getPossibleMoves(minPlayer);
int minStrength = MAX_POSSIBLE_STRENGTH;
for(int i = 0; i < moves.length; i++)
{
if(board.move(moves[i]))
{
moveCount++;
int strength = expandMaxNode(depth -1, minStrength);
if(strength < parentMaximum)
{
board.undoLastMove();
return strength;
}
if(strength < minStrength)
{
minStrength = strength;
}
board.undoLastMove();
}//end if move made
}//end for all moves
return minStrength;
}//end expandMaxNode
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -