简体   繁体   English

国际象棋 - 是否可以使用三角桌收集以将死结束的 pv 移动?

[英]chess - Is it possible to collect pv moves ending with checkmate, using triangular tables?

I'm trying to figure out how a traditional chess engine (no AI) works, and now I'm trying to collect pv (principal variation) moves using triangular table.我试图弄清楚传统国际象棋引擎(无 AI)是如何工作的,现在我试图使用三角表收集 pv(主要变化)移动。 So I'm using a NxN table and a very simple implementation所以我使用 NxN 表和一个非常简单的实现

private Integer alphaBeta(final int depth, int alpha, int beta) {
    ...
    pvLength[ply] = ply;
    ...
    while (move != null) {
        ...
        if (value > alpha) {  // (1)
            dPvTable[ply][ply] = move;
            nextPly = ply + 1;
            for (int p = nextPly; p < pvLength[nextPly]; ++p) {
                pvTable[ply][p] = pvTable[nextPly][p];
            }
            pvLength[ply] = pvLength[nextPly];
            ...
        }
        ...
    }
    ...
}

I am comparing the extracted pv with the pv resulting from the transposition table.我将提取的 pv 与转置表产生的 pv 进行比较。

It works well if the pv doesn't end with checkmate.如果 pv 不以将死结束,它会很好地工作。 If it does end with a checkmate, the triangular table returns only the first (correct) move.如果它确实以将死结束,则三角形表仅返回第一个(正确的)移动。

I have tried many changes but without success.我尝试了很多改变,但没有成功。 The only thing that works (at the expense of search speed) is to change the condition (1) to唯一有效(以牺牲搜索速度为代价)是将条件(1)更改为

if (value >= alpha) {

But clearly this is not an acceptable change, because this way the search explores the tree up to the last move, and does not end at the first checkmate found.但显然这不是一个可接受的变化,因为这样搜索会探索树直到最后一步,而不是在找到的第一个将死处结束。

I just wanted to know, if anyone had the same problem: is this behavior due to a flaw in my implementation?我只是想知道,如果有人遇到同样的问题:这种行为是由于我的实现中的缺陷造成的吗? Or this method just can't return all PV moves when there are checkmates?或者当有将死时,这种方法不能返回所有的 PV 移动?

I am answering my question after further verification.我在进一步验证后回答我的问题。

Premise: in my engine, checkmate is evaluated with alpha (-30000).前提:在我的引擎中,将死用 alpha (-30000) 进行评估。 I'm using iterative deepening, so (i guess) i don't need to determine the "distance" of checkmate by adding ply, as is often done to pick the "closest".我正在使用迭代深化,所以(我猜)我不需要通过添加层来确定将死的“距离”,就像通常选择“最近”一样。

So, i do not think that with this method it is possible to read the pv line during or at the end of the search, when the pv ends with a checkmate: the pv line is updated only if (value > alpha) and, when a checkmate is detected, at the next iteration this condition is no longer satisfied, because value == alpha.所以,我不认为使用这种方法可以在搜索期间或搜索结束时读取 pv 行,当 pv 以将死结束时:pv 行仅在 (value > alpha) 时更新,并且当检测到将死,在下一次迭代中不再满足这个条件,因为 value == alpha。 I tried to modify the condition (value > alpha) in order to register the pv line, but in this way the whole search is distorted.我试图修改条件(值> alpha)以注册 pv 行,但是这样整个搜索就被扭曲了。

However you always get the correct best move.但是,您总是会得到正确的最佳移动。

On the other hand, when the checkmate is not alpha, but alpha + ply, this method returns all the moves of the pv line.另一方面,当将死不是 alpha,而是 alpha + ply 时,此方法返回 pv 线的所有移动。 But this extends and slows the search.但这会扩展并减慢搜索速度。

Even using the "PV-List on the Stack" method, described in the Chess Programming Wiki, i notice the same behavior because the pv line is updated under the same condition.即使使用 Chess Programming Wiki 中描述的“堆栈上的 PV 列表”方法,我也注意到相同的行为,因为 pv 行在相同条件下更新。

This is an example, I hope it is clear enough.这是一个例子,我希望它足够清楚。

The real pv line got from TT is:
    [h2-h3      , Kg4-f4     , Rd6-f6     , Nh5xf6(R)  , g2-g3      ]

In the search, we have:

            4 ->    move=g2-g3    value= 30000    alpha=306    beta=30000
            4 // g2-g3 is a pv move (gives checkmate at ply=4), and is
            4 // registered in pvTable because value > alpha
            4 old pv=[]
            4 new pv=[g2-g3      , b4xc3(P)   ]

         3 ->    move=Nh5xf6    value=-30000    alpha=-30000    beta=-306
         3 // Nh5xf6 is a pv move, but is not registered in pvTable because
         3 // value == alpha

      2 ->    move=Rd6-f6    value= 30000    alpha=306    beta=30000
      2 // Rd6-f6 is a pv move and is registered, but in a line that is not
      2 // linked to Nh5xf6
      2 old pv=[Ng5-f7     , g6-g5      , Bh6xg5(P)  , Kf4-e4     ]
      2 new pv=[Rd6-f6     , Bb6xd8(R)  , g2-g3      , b4xc3(P)   ]

   1 ->    move=Kg4-f4    value=-30000    alpha=-30000    beta=30000
   1 // Kg4-f4 is a pv move, but is not registered in pvTable because
   1 // value == alpha

0 ->    move=h2-h3    value=30000    alpha=-30000    beta=30000
0 // so the pv remains incorrect
0 old pv=[h2-h3      , Kg4-f4     , Ng5-f7     , Kf4-e4     , Rd6xg6(P)  ]
0 new pv=[h2-h3      , Kg4-f4     , Ng5-f7     , Kf4-e4     , Rd6xg6(P)  ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM