#chess-board #chess-engine #move #generator #lookup-tables #moves #generate

chess

这是一个快速的棋子生成器。它有一套非常好的文档,所以你应该充分利用它。它(现在)使用 build.rs 文件生成所有查找表,这意味着伪合法棋子生成几乎不需要分支。有一些便利函数,例如,找到两个方格之间的所有方格。它使用复制-on-make 风格的结构,并将棋盘结构尽可能地精简,以减少复制棋盘的成本。有些地方可以进一步提高 perft-test 性能,但我选择更多地实现功能,以便在真实应用中更有用。例如,我为棋盘和兵的棋盘生成哈希,用于评估查找表(使用 Zobrist 哈希)。有两种生成棋子的方式,一种更快,另一种有更多对创建棋引擎有用的特性。更多详细信息请参阅文档。

36 个版本 (17 个稳定)

3.2.0 2021年3月12日
3.1.1 2019年7月14日
3.1.0 2019年5月27日
3.0.1 2019年1月16日
0.2.0 2016年5月29日

游戏开发 中排名 80

Download history 206/week @ 2024-03-14 276/week @ 2024-03-21 299/week @ 2024-03-28 266/week @ 2024-04-04 354/week @ 2024-04-11 309/week @ 2024-04-18 347/week @ 2024-04-25 361/week @ 2024-05-02 412/week @ 2024-05-09 428/week @ 2024-05-16 439/week @ 2024-05-23 414/week @ 2024-05-30 282/week @ 2024-06-06 327/week @ 2024-06-13 394/week @ 2024-06-20 276/week @ 2024-06-27

每月下载量 1,331
10 crates 中使用

MIT 许可证

230KB
4.5K SLoC

Rust 中快速的国际象棋库

Build Status crates.io docs.rs

这个库处理棋引擎或棋盘用户界面中的移动生成过程。

该库遵循 MAJOR.MINOR.PATCH 格式的 semver 版本号。这意味着

  • 任何破坏现有代码的 API 变更将涉及 MAJOR 版本号变更。
  • 任何添加的功能或特性,只要不影响现有应用程序,将涉及 MINOR 版本号变更。
  • 任何不影响用户的错误修复或性能改进将涉及 PATCH 版本变更。

需要 Rust 1.31 或更高版本

此库需要 rust 版本 1.27 或更高版本以在编译时检查 BMI2 指令集。此外,此构建与 rust 2018 兼容,我认为这需要 rust 1.31。

注意:由于在 AMD 架构上性能极差,已禁用 bmi2。我已选择公开两个相关函数,如果使用 bmi2 CPU。

示例

增量移动生成与捕获/非捕获排序

这里我们遍历所有移动,使用增量移动生成。下面的迭代器会在您遍历列表时生成移动,这在不是所有移动都将被查看的情况中很理想(例如,在引擎搜索函数中)。

  use chess::MoveGen;
  use chess::Board;
  use chess::EMPTY;

  // create a board with the initial position
  let board = Board::default();

  // create an iterable
  let mut iterable = MoveGen::new_legal(&board);

  // make sure .len() works.
  assert_eq!(iterable.len(), 20); // the .len() function does *not* consume the iterator

  // lets iterate over targets.
  let targets = board.color_combined(!board.side_to_move());
  iterable.set_iterator_mask(targets);

  // count the number of targets
  let mut count = 0;
  for _ in &mut iterable {
      count += 1;
      // This move captures one of my opponents pieces (with the exception of en passant)
  }

  // now, iterate over the rest of the moves
  iterable.set_iterator_mask(!EMPTY);
  for _ in &mut iterable {
      count += 1;
      // This move does not capture anything
  }

  // make sure it works
  assert_eq!(count, 20);

设置位置

Board 结构试图在所有时候保持位置合法。这在设置棋盘时可能会让人感到烦恼,例如通过用户输入。

为了解决这个问题,在 3.1.0 版本中引入了 BoardBuilder 结构。该 BoardBuilder 结构遵循非消耗性构建器模式,并且可以通过 Board::try_from(...)board_builder.try_into() 转换为 Result<Board, Error>

  use chess::{Board, BoardBuilder, Piece, Square, Color};
  use std::convert::TryInto;

  let mut board_builder = BoardBuilder::new();
  board_builder.piece(Square::A1, Piece::King, Color::White)
               .piece(Square::A8, Piece::Rook, Color::Black)
               .piece(Square::D1, Piece::King, Color::Black);
  
  let board: Board = board_builder.try_into()?;

进行走棋

在这里,我们在棋盘上走一步棋。棋盘是一个创建时复制的结构,这意味着每次走棋时,你都会创建一个新的棋盘。你可以使用 board.make_move() 来更新当前位置,但你不能撤销这步棋。棋盘结构经过优化以减小复制时间。

  use chess::{Board, ChessMove, Square, Color};

  let m = ChessMove::new(Square::D2, Square::D4, None);

  let board = Board::default();
  assert_eq!(board.make_move_new(m).side_to_move(), Color::Black);

表示完整游戏

棋类游戏不仅仅是棋盘上的内容。Game 对象跟踪游戏的历史,以便进行和棋提议、认输、50回合规则和棋、重复和棋等,总之,任何需要游戏历史的情况。

  use chess::{Game, Square, ChessMove};

  let b1c3 = ChessMove::new(Square::B1, Square::C3, None);
  let c3b1 = ChessMove::new(Square::C3, Square::B1, None);
  
  let b8c6 = ChessMove::new(Square::B8, Square::C6, None);
  let c6b8 = ChessMove::new(Square::C6, Square::B8, None);
  
  let mut game = Game::new();
  assert_eq!(game.can_declare_draw(), false);
  
  game.make_move(b1c3);
  game.make_move(b8c6);
  game.make_move(c3b1);
  game.make_move(c6b8);
  
  assert_eq!(game.can_declare_draw(), false); // position has shown up twice
  
  game.make_move(b1c3);
  game.make_move(b8c6);
  game.make_move(c3b1);
  game.make_move(c6b8);
  assert_eq!(game.can_declare_draw(), true); // position has shown up three times

FEN 字符串

BoardBuilderBoardGame 都实现了 FromStr,以便您可以将 FEN 字符串转换为对象。此外,BoardBuilderBoard 实现了 std::fmt::Display,以便将它们转换为 FEN 字符串。

  use chess::Board;
  use std::str::FromStr;
  
  assert_eq!(
      Board::from_str("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
              .expect("Valid Position"),
    Board::default()
  );

编译时选项

在编译时,我强烈建议使用 RUSTFLAGS="-C target-cpu=native",特别是为了获取几乎所有现代 CPU 都可用的 popcnt 和 ctzl 指令。这用于内部确定位图中有多少个棋子,以及棋子位于哪个位置。由于这里使用的类型系统,这些任务实际上只需要一条指令。此外,通过使用此标志,在具有指令的机器上启用了 BMI2。

BMI2

截至本库 1.0.3 版本,在支持它的机器上使用 BMI2 指令集。这以两种方式加快了逻辑的执行速度

  • 它使用内置指令执行与魔幻位图相同的逻辑。
  • 通过将走法存储在 u16 而不是 u64 中,减少了缓存负载,这可以通过单条指令解压缩为 u64。

在没有 BMI2 的目标上,该库回退到魔幻位图。这是在编译时检查的。

Shakmaty

另一个 Rust 棋类库是 'shakmaty' crate。这是一个非常好的库,比这个库有更多功能。它支持各种棋类变体以及 UCI 协议。然而,这些功能是有代价的,并且在这个库中,所有测试用例的性能都比我抛出的要快。为了比较这两个库,我已经在 'chess_perft' 应用程序中添加了对 'shakmaty' 的支持,并将许多基准测试移动到该 crate 中。您可以在 https://github.com/jordanbray/chess_perft 上查看结果。

它做什么

这个库允许您从 FEN 格式的字符串创建棋盘,列出棋盘的所有合法走法并执行走法。

这个库还允许您查看各种棋盘状态信息,例如王车易位权利。

这个库具有非常快速的走法生成(其存在的主要目的),将会进行更多的优化。所有使棋走法生成变得快速的技巧都被使用。

它不能做什么

这并不是一个棋引擎,只是一个走法生成器。这也不是一个棋盘界面,只是一个走法生成器。这也不是一个棋盘PGN解析器、数据库、UCI通信器、XBOARD/WinBoard协议、网站或大师。只是一个谦逊的走法生成器。

API 文档

...可在https://jordanbray.github.io/chess/chess/找到。

还有其他什么吗?

没有了。祝您玩得开心。

依赖项

约200KB