我创建了minimax,pvs和alpha-beta算法,并使用随机树来遍历它们的结果。该树的每个父节点有[2,10]个子节点,总深度为10.每个叶子节点的随机值为[0,10]。
当我运行树遍历minimax算法时,结果值通常为2或3.这对我来说很奇怪,因为我猜它会给出5或者4或6,但它总是2或3.这是minimax算法它应该给出最小的最小值,这是令人困惑的,为什么它似乎几乎给出了整个树的最小值,因为我开始算法作为最大化的玩家。
结果如下:
Alpha Beta: 2.0, time: 10.606461 milli seconds
PVS: 2.0, time: 41.119652 milli seconds
Minimax: 2.0, time: 184.492937 milli seconds
这是源代码,不包括Timer类,因为这与我的问题无关。
import testing.utilities.data.Timer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
public class MinimaxAlphaBetaTest {
public static void main(String[] args) {
Node parent = new Node(0.);
int depth = 10;
createTree(parent,depth);
Timer t = new Timer().start();
double ab = alphabeta(parent,depth+1,Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY,true);
t.stop();
System.out.println("Alpha Beta: "+ab+", time: "+t.getTime());
t = new Timer().start();
double pv = pvs(parent,depth+1,Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY,1);
t.stop();
System.out.println("PVS: "+pv+", time: "+t.getTime());
t = new Timer().start();
double mm = minimax(parent,depth+1,true);
t.stop();
System.out.println("Minimax: "+mm+", time: "+t.getTime());
}
public static void createTree(Node n, int depth){
if(depth == 0) {
n.getChildren().add(new Node((double) randBetween(0, 10)));
return;
}
for (int i = 0; i < randBetween(2,10); i++) {
Node nn = new Node(0.);
n.getChildren().add(nn);
createTree(nn,depth-1);
}
}
private static Random r; // pseudo-random number generator
private static long seed; // pseudo-random number generator seed
// static initializer
static {
// this is how the seed was set in Java 1.4
seed = System.currentTimeMillis();
r = new Random(seed);
}
public static int randBetween(int min, int max){
return r.nextInt(max-min+1)+min;
}
public static double pvs(Node node, int depth, double alpha, double beta, int color){
if(depth == 0 || node.getChildren().isEmpty())
return color*node.getValue();
int i = 0;
double score;
for(Node child : node.getChildren()){
if(i++==0)
score = -pvs(child,depth-1,-beta,-alpha,-color);
else {
score = -pvs(child,depth-1,-alpha-1,-alpha,-color);
if(alpha<score || score<beta)
score = -pvs(child,depth-1,-beta,-score,-color);
}
alpha = Math.max(alpha,score);
if(alpha>=beta)
break;
}
return alpha;
}
public static double alphabeta(Node node, int depth, double alpha, double beta, boolean maximizingPlayer){
if(depth == 0 || node.getChildren().isEmpty())
return node.getValue();
double v = maximizingPlayer ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
for(Node child : node.getChildren()){
if(maximizingPlayer) {
v = Math.max(v, alphabeta(child, depth - 1, alpha, beta, false));
alpha = Math.max(alpha, v);
}else {
v = Math.min(v, alphabeta(child, depth - 1, alpha, beta, true));
beta = Math.min(beta, v);
}
if(beta <= alpha)
break;
}
return v;
}
public static double minimax(Node node, int depth, boolean maximizingPlayer){
if(depth == 0 || node.getChildren().isEmpty())
return node.getValue();
double v = maximizingPlayer ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
for(Node child : node.getChildren()){
if(maximizingPlayer)
v = Math.max(v,minimax(child,depth-1,false));
else
v = Math.min(v,minimax(child,depth-1,true));
}
return v;
}
static class Node{
List<Node> children = new ArrayList<>();
double value;
public Node(double value) {
this.value = value;
}
public List<Node> getChildren() {
return children;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
return Double.compare(node.value, value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
}
感谢Jiri Tousek评论,现在有意义,当用奇数的深度运行时给出一个通常高于5的数字和一个通常低于5的偶数,例如11,它会产生以下结果:
Alpha Beta: 7.0, time: 39.697701 milli seconds
PVS: 7.0, time: 216.849568 milli seconds
Minimax: 7.0, time: 998.207216 milli seconds
用奇数运行它,它看起来像深度3,结果来自我所见(5,6,7,8,9,10),深度5结果来自我所见过的(7,8,9),深度7结果来自我所见过的7或8,深度9结果来自我所见过的是8,深度11我见过7和8
而偶数产生{2,4,(2,3,4,5,6)},{6,8,10,(2,3)}
因此,在运行算法并查找结果时,轮到谁更重要?
IE如果它是最大化器,那么进入一个奇怪的深度,如果它是最小化器转向均匀深度,任何深度产生理想的移动?
答案 0 :(得分:0)
由于你以最大值(在最顶层)开始并且向下达到10级,你将选择最深层次的最小值。
由于您选择[2-10]数字的最小(不是平均值),您不能指望它大致为5 - 它通常会更低。事实上,范围[0-10]中6个数字的最小值为5或更高的概率大约为(1/2)^6 ~ 1.5%
。
然后操作交替进行。我无法在那里计算任何好的概率,但直观地说,效果应该是中性的。
可能有助于查看在一次最小值的交替之后发生的事情。让我们每个节点有6个孩子(为了简单起见)。如前所述,&#34; min&#34;阶段将是5或更高,大约是(1/2)^6
。对于&#34; max&#34;阶段导致5或更高,任何孩子足够5或更高。有6个孩子,所以机会大概是1 - (1 - (1/2)^6)^6 ~ 9%
。
这已经远远低于最底层5+数字的最初50%几率。然后,另一次迭代将导致1 - (1 - (0.09)^6)^6 ~ 3e-6
概率为5+。