有效存储国际象棋的位置

时间:2014-01-27 07:06:48

标签: database position chess

我已经阅读了与此问题相关的大量网页点击,但我仍然没有找到任何明确的答案。

我想做的是创建一个国际象棋位置数据库,能够识别换位(通常哪些是方块)。

编辑:它还应该能够识别相似(但不完全相同)的位置。

这是近20年前的讨论(当空间 是一个问题时): https://groups.google.com/forum/#!topic/rec.games.chess.computer/wVyS3tftZAA

其中一位讨论者谈论在方形矩阵上编码片段,使用4 x 64位加上一些位用于附加信息(castling,en passant等): 有六件(Pawn,Rook,Knight,Bishop,Queen,King)加上一个空的正方形,它将是3位(2 ^ 3),还有一个用于该作品颜色的位。

总共会有4个数字,每个64位,还有一些额外的信息。

问题:是否有其他更多高效方式存储国际象棋位置

我应该提到这个问题是以数据库为中心,而不是以游戏为中心(即我唯一的兴趣是有效地存储和检索,而不是创建任何AI或产生任何移动)。

谢谢, 阿德里安

9 个答案:

答案 0 :(得分:4)

板上有32块,64块正方形。方形索引可以用6位数表示,因此要表示每个部分的位置,需要32个六位数字,或总共192位,小于4x64。

通过认识到并非所有位置都可能(例如,pawn无法到达其自身颜色的末尾行)并且在这些情况下使用少于6位的位置,您可以做得更好。此外,已被另一件作品占据的位置使该位置无法用于其他作品。

作为一块也可能完全从棋盘中丢失,你应该从国王的位置开始,因为它们总是在那里 - 然后,编码另一个棋子的位置就像一个国王一样意味着这件作品已经服用。

修改

对这些部分的可能位置进行简短分析:

  • 国王,女王,骑士和车手可以在任何地方(64个位置)
  • 主教被限制在32个职位
  • 典当仅限于21,26,30,32,32,30,26和21个职位(A-H栏)。

因此,这组合法的国际象棋位置可以用零到(64 ^ 12 * 32 ^ 4 * 21 ^ 4 * 26 ^ 4 * 30 ^ 4 * 32 ^ 8)-1的整数来简单地描述,或391935874857773690005106949814449284944862535808450559999,符合188位。对此进行编码和解码是非常简单的 - 但是,有多个数字可以解码到相同的位置(例如B1的白骑士1和G1的白骑士2; G1的白骑士1和白骑士2 B1)。

由于没有两个部分可以占据相同的方块,因此存在更严格的限制,但编码和解码都有点困难,因此在实际应用中可能没用。此外,上面显示的数字非常接近2 ^ 188,所以我不认为即使这种更紧密的编码也适合187位。

答案 1 :(得分:2)

以Forsyth-Edwards符号(FEN)获取战利品。它被描述为here。它也是众所周知的,并得到许多引擎和国际象棋程序的支持。

这是起始位置的FEN:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

Fen分为6个部分。

第1段 包含碎片。黑色部分为小写,白色部分为大写。

第2段 国家,轮到谁了。 (w或b)

第3段 是为了铸造。 KQkq意味​​着两者都可以城堡。 K = King side white q = queen side black

第4段 用代数表示法的En passant目标平方。如果没有en passant目标方格,则为" - "。如果一个棋子刚刚进行了两个方格的移动,那么这就是"背后的位置"典当。无论是否有一个pawn在位以进行en passant捕获

,都会记录下来

第5段 Halfmove clock:这是自上次捕获或pawn advance以来的halfmoves数。这用于确定是否可以在五十步规则下声明平局。

第6段 Fullmove数字:完整移动的数量。它从1开始,并在Black移动后递增。

答案 2 :(得分:1)

您可以使用修改的运行长度编码,其中每个部分编码为一个片段编号(3位),0y111用于跳过前面的空格。由于存在许多彼此相邻的情况,您最终会忽略位置信息:

         All pieces are followed by color bit
0y000c 0 Pawn
0y001c 1 Rook
0y010c 2 Knight
0y011c 3 Bishop
0y100c 4 Queen
0y101c 5 King
0y110 6 Empty space
0y111 7 Repeat next symbol (count is next 6 bits, then symbol)

解码器从a1开始向右移动,在行尾向上移动,因此启动板的编码将是:

12354321      Literal white encoding from a1 to h1    32 bits
7 8 0         repeat white pawn 8 times               13 bits
7 32 6        repeat 32 empty spaces                  12 bits
7 8 8         repeat black pawn 8 times               13 bits
9abcdba9      Literal encoding of black               32 bits
                                                    ---------
                                                     102 bits total

话虽这么说,可变长度编码的额外复杂性和不确定性可能不值得节省空间。此外,在某些剧中,它可能比恒定宽度格式更差。

答案 3 :(得分:1)

如果您不需要可解码位置表示进行比较,那么您可以查看Zobrist散列。国际象棋引擎使用它来生成位置的64位单向哈希,用于在搜索树中发现转置。由于它是单向哈希,你显然无法从哈希中反转位置。散列的大小是可调的,但64位似乎是可接受的最小大小,导致很少的冲突。它是一个理想的数据库索引键,固定长度只有8个字节。由于碰撞虽然不常见,但你可以做第二遍,比较实际位置,过滤掉任何已经散列到相同值的位置,如果它是一个问题。我在我自己的一个应用程序中使用Zobrist哈希(使用SQLite),我用它来管理我的开口,并且在查找转置时没有任何问题。

答案 4 :(得分:0)

我的两分钱

短版

  • 选择数据格式,便于计算两个位置的相似度。
  • 将位置数据存储在搜索程序附近(可能在内存中)。
  • 搜索相似位置时,强行搜索所有位置。
  • 可能将搜索划分为多个线程/进程。

更长的版本

32字节(4 * 64位)是非常少量的数据。 1000万象棋位置可以达到30千兆字节。 192位是24字节,这将达到23千兆字节。可能数据库使用某种压缩,因此磁盘可能少于这些数字。我不知道存储有什么样的限制,但因为这些编码似乎非常紧凑,所以尝试最小化更多可能是不值得的。

由于需要找到相似位置的能力,我认为编码应该可以很容易地比较不同的位置。优选地,这可以在不解码的情为了使这个工作,编码应该是恒定长度(不能想到使用可变长度编码这样做的简单方法)。

索引可能会加速相似性搜索。朴素的方法将索引数据库中各个位置的所有位置。这将产生32个索引(也可能是其他信息)。至少在理论上它会使搜索闪电般快速。

索引将占用相当大的空间。可能比实际位置数据更多。他们仍然可能没有那么多帮助。例如,找到黑王所在的位置,或者在e4附近需要使用索引进行9次搜索,然后在30千兆字节的位置信息周围跳跃,这可能需要在随机位置进行磁盘访问。并且可能找到类似的位置不止一件......

如果存储格式有效,则可能只需通过所有位置数据来强制(like this)并按位置检查相似位置。这将有效地使用CPU缓存。另外,由于长度记录不变,很容易将工作分成多个处理器或机器。

是否使用以片段为中心或基于电路板的存储格式取决于您将如何计算两个位置相互比较的相似度。以件为单位可以轻松计算出一件在两个不同位置的距离。然而,在以片段为中心的方法中,每个片段都是分开识别的,因此在某个位置找到一个棋子并不容易。一个人必须检查每个兵的位置。如果棋子身份不那么重要,那么基于棋盘的存储可以很容易地检查棋子是否在想要的位置。另一方面,无法检查存在哪个精确的棋子。

答案 5 :(得分:0)

有两种简单的方法来存储电路板的信息:通过存储每个部分的位置或者为每个方块存储其中的内容。

正如Mitch所解释的那样,有一种方法可以使用RLE进行一点压缩,但是给出的例子是起始位置,这个位置特别容易描述。在另一种情况下,棋子在棋盘上展开,你可以有空间和棋子交替,而RLE不会压缩任何东西。因此,除非使用更复杂的算法,否则您将恢复无压缩。

我认为jlahd通过计算两次中心棋子在计算中犯了一个错误,所以实际上存储每个棋子位置所需的空间不是188位而是168位。如果已经提升了典当,你还需要存储。所以事实上,对于棋子来说,有(32 + 4x64)^ 16种可能性。这总共223位= 28字节。

如果我们为每个广场存储其内容,我们需要计算广场的可能性。对于大多数正方形,有6个可能的白色部分和黑色相同。对于顶行和底行,不能显示一种颜色的pawn。因此,对于中心正方形是13个可能性,对于顶部和底部正方形是12个可能性,因此13 ^ 48×12 ^ 16个可能性。 en-passant的位置是17个可能性。所以这大概是240位。

总而言之,似乎你可以通过存储棋子位置而不是每个方格的内容来获得12.5%的空间。

答案 6 :(得分:0)

在板上最多考虑32个。每块可以在64个正方形之一上。以预定顺序独立地表示片段位置需要32 * 6 = 192位。

除了可以将每个pawn提升为rook,bishop,knight或queen外,因此对于每个pawn,我们还需要将其状态编码为3个附加位(4种可能的片段类型和普通pawn)。

32 * 6 + 16 * 3 = 240位/ 30字节

在许多情况下,您将需要有关位置所在的游戏/变体状态的其他信息:

密码文件:4位(8个文件,无)

版权:4位(短/长白色/黑色)

sideToMove:1位(白色/黑色)

总共增加249位/ 32字节。

这可能不是最紧凑的表示形式,但是很容易编码/解码。

答案 7 :(得分:0)

紧凑且合理可理解的,最坏情况(或总是如果方便的话)完整位置规范的 25 个字节:

  • 64 位来标识哪些字段是空的,哪些不是。 “开启”位数定义了接下来实际编码的片段数(下一个最多 32 个片段)。
  • 最多使用 32 × 4 位来标识每件作品(包括颜色)。他们按董事会顺序提及。城堡权和过路信息也可以编码到这个中(仍然可以城堡的车获得的编码与不能的车不同,而刚刚移动了 2 个位置的棋子获得了自己的编码):

000 普通兵; 001 刚上升两个位置的棋子; 010骑士; 011主教; 100车不动,王也不动; 101只移动的车,或者它的王; 110 皇后; 111王。

附加信息需要 1 个字节:

  • 轮到谁了:1 位,
  • 自上次移动或捕获以来的层数,(最多 100):7 位

答案 8 :(得分:0)

22 字节的快速内部建议(灵感来自霍夫曼编码)。解码/编码并不容易,但也不难。严肃的节目可能有更好的技巧。

  • 最初我们有 32 个空方块,每种颜色有 8P、2k、2B、2R、1K、1Q;
  • 对于那些将使用 1、3、5、5、5、6、6 位的霍夫曼编码;例如空=0,白色 P=100,k=10100,B=10101,R=10110,K=101110,Q=101111,黑色与白色相同,但从 11 开始而不是 10;
  • 所以我们的 64 个符号(每平方 1 个)将使用:32 + 2 x (8x3 + 5x2 + 5x2 + 5x2 + 6x1 + 6x1) = 164 位。

现在是特殊情况:

  • 1 位用于显示颜色;
  • castling:要编写可以形成城堡的车,让我们重新使用 pawn 符号(不要混淆:第一行没有 pawn)。那是 3 位而不是 5 位,所以我们不会在这里丢失!
  • 顺便说一句:只要提到列,如果有的话。这是 7 个或更少的选择。所以 3 位(000 表示没有传入,其他任何指定列);
  • 提升:对于每一个大约 2 个棋子消失,被一个空闲的方块和一个皇后代替,所以 (-3 - 3 + 1 + 6) = 在最坏的情况下多 1 个位;

因此没有提升:164 + 1 + 4 = 168 位 = 21 字节; 提供 8 个皇后促销的非常假设的情况:22 字节;

这是我为内部解决方案所能做的最好的事情。