如何在 Java 中加速 minimax 算法?
How to speed up minimax algorithm in Java?
我正在想办法提高这个算法的速度。它适用于两个游戏(2 人游戏,CPU vs Human),但问题是当我分配超过三堆时(包含许多石头,所以每个玩家可以捡起不止一个) , 计算机玩家需要永远计算移动:
public Object[] minimax(int depth, int player) {
if(hasPlayer1Won(player)){
return new Object[]{get_default_input(1),1};
}else if(hasPlayer2Won(player)){
return new Object[]{get_default_input(1),-1};
}
List<T> movesAvailable = getNextStates();
if(movesAvailable.isEmpty()){
return new Object[]{get_default_input(0), 0};
}
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
T computersMove = getNextStates().get(0);
int i = 0;
for (T move: movesAvailable) {
makeAMove(move, player);
Object[] result = minimax(depth + 1, player == G.PLAYER1 ? G.PLAYER2 : G.PLAYER1);
int currentScore = (int)result[1];
if(player == G.PLAYER1){
max = Math.max(currentScore, max);
if(currentScore >= 0 && depth == 0) {
computersMove = move;
}
if(currentScore == 1){
resetMove(move);
break;
}
if(i==movesAvailable.size() - 1 && max < 0){
if (depth == 0){
computersMove = move;
}
}
}else{
min = Math.min(currentScore, min);
if(min == -1) {
resetMove(move);
break;
}
}
i++;
resetMove(move);
}
return new Object[]{computersMove, player == G.PLAYER1 ? max: min};
}
我已经成功测试了以下改进minimax的方法(用它来玩井字和霸气):
Alpha beta pruning - used a special variant of this type of pruning, in conjunction with Lazy evaluation - 基本上我没有生成整棵树,而是在每一层上生成了一个最优移动,并为其他状态-动作对保留了 Lazy 持有者(应用 Lazy 评估方法,通过使用供应商并在与我持有的不同的移动时调用它)。
Heuristic pruning - 请参阅该书中关于启发式的章节。我基本上只生成了树的前 d 个分支,而不是确定性结果,我将那本书中描述的启发式函数应用于当前状态以确定启发式结果。每当移动 (d+1) 时,我都会使用相同的方法生成另一个分支。
这里,d 是您选择的级别(最安全的方法是通过测试)
Parallel computing 也看看这个,你可能会发现它更难实现,但它会带来回报
前 2 个选项为我节省了大量的计算时间,这样我就可以在 5x5 的棋盘上以最佳方式玩 Domineering,并在 10x10 的棋盘上试探性地玩(它可以更好,具体取决于你想要它玩得有多好) ).
我正在想办法提高这个算法的速度。它适用于两个游戏(2 人游戏,CPU vs Human),但问题是当我分配超过三堆时(包含许多石头,所以每个玩家可以捡起不止一个) , 计算机玩家需要永远计算移动:
public Object[] minimax(int depth, int player) {
if(hasPlayer1Won(player)){
return new Object[]{get_default_input(1),1};
}else if(hasPlayer2Won(player)){
return new Object[]{get_default_input(1),-1};
}
List<T> movesAvailable = getNextStates();
if(movesAvailable.isEmpty()){
return new Object[]{get_default_input(0), 0};
}
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
T computersMove = getNextStates().get(0);
int i = 0;
for (T move: movesAvailable) {
makeAMove(move, player);
Object[] result = minimax(depth + 1, player == G.PLAYER1 ? G.PLAYER2 : G.PLAYER1);
int currentScore = (int)result[1];
if(player == G.PLAYER1){
max = Math.max(currentScore, max);
if(currentScore >= 0 && depth == 0) {
computersMove = move;
}
if(currentScore == 1){
resetMove(move);
break;
}
if(i==movesAvailable.size() - 1 && max < 0){
if (depth == 0){
computersMove = move;
}
}
}else{
min = Math.min(currentScore, min);
if(min == -1) {
resetMove(move);
break;
}
}
i++;
resetMove(move);
}
return new Object[]{computersMove, player == G.PLAYER1 ? max: min};
}
我已经成功测试了以下改进minimax的方法(用它来玩井字和霸气):
Alpha beta pruning - used a special variant of this type of pruning, in conjunction with Lazy evaluation - 基本上我没有生成整棵树,而是在每一层上生成了一个最优移动,并为其他状态-动作对保留了 Lazy 持有者(应用 Lazy 评估方法,通过使用供应商并在与我持有的不同的移动时调用它)。
Heuristic pruning - 请参阅该书中关于启发式的章节。我基本上只生成了树的前 d 个分支,而不是确定性结果,我将那本书中描述的启发式函数应用于当前状态以确定启发式结果。每当移动 (d+1) 时,我都会使用相同的方法生成另一个分支。 这里,d 是您选择的级别(最安全的方法是通过测试)
Parallel computing 也看看这个,你可能会发现它更难实现,但它会带来回报
前 2 个选项为我节省了大量的计算时间,这样我就可以在 5x5 的棋盘上以最佳方式玩 Domineering,并在 10x10 的棋盘上试探性地玩(它可以更好,具体取决于你想要它玩得有多好) ).