Water: A Zig chess library, framework, and engine

1 day ago 1

water logo

A comprehensive chess suite written in Zig.

Water aims to provide a performant chess engine library allowing users to easily architect chess engines by providing a core library and uci interface management scheme.

The water engine itself is crafted using this library, with the goals of making:

  • An iterative search engine with Alpha-Beta Pruning, Quiescence, etc.
  • A neural network-powered engine using NNUE

For a quick build of the project, simply run zig build run --release.

Note: The engine communicates through the UCI protocol. You can read more about the standard here.

  • Zig 0.15.2 - other versions will not work due to 'Writergate' and other potentially breaking changes
  • cloc for the cloc step (optional)
Step Description
build Builds water. Pass --release for ReleaseFast.
run Build and run water. Pass --release for ReleaseFast.
perft Run the perft suite. Running with --release is highly recommended.
bench Run the perft benchmarking suite. Running with --release is highly recommended.
search Run the search benchmarking suite. Running with --release is highly recommended.
package Builds the engine executable in ReleaseFast for the triples specified in build.zig.
test Run all unit tests.
lint Checks formatting of all source files excluding build.zig.
fmt Format all source code excluding build.zig.
cloc Count the total lines of zig code. Requires cloc.
docs Generates documentation for the water library using zig's docgen tool.

It is generally not recommended to run the perft suite unless there have been significant changes made to the core library. Generally, the bench step is enough for verifying performance and correctness. If you choose to run the perft suit, then you will be executing about 50,000 tests which will take many hours to complete on most hardware. These perft tests are epd variants pulled from pawnocchio as mentioned in the credits below. The marcel.epd file takes up the majority of this step's runtime and should be skipped if looking for a quick yet comprehensive test.

Note: While the docs step is able to emit the correct files, a bug in the standard library prevents reading the emitted docs on some systems. See this issue for more details.

Adding Water to Your Project

To add water as a dependency to your project, simply run zig fetch --save git+https://github.com/trevorswan11/water. This will add water as a dependency to your build.zig.zon file.

You'll then need to explicitly add it as a module in build.zig, which might looks like:

const exe = b.addExecutable(.{ .name = "foo", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "water", .module = b.dependency("water", .{}).module("water"), }, }, }), });

To confirm the dependency was added successfully, try this out in main.zig:

const std = @import("std"); const water = @import("water"); pub fn main() !void { const allocator = std.heap.page_allocator; var board = try water.Board.init(allocator, .{}); defer board.deinit(); const diagram = try water.uci.uciBoardDiagram(board, .{}); defer allocator.free(diagram); std.debug.print("{s}", .{diagram}); }

When running using zig build run, you might see some target feature errors reported by the build system. I believe this is due to a change made with the x86 backend in Zig 0.15.2, but these errors are harmless and should not get in the way of compilation or functionality.

Contributors are always welcome! As this project progresses and the engine improves, it will become increasingly difficult for a single developer to make meaningful improvements or address bugs in a timely manner. Checkout CONTRIBUTING.md for the project's guidelines.

Water could not be where it is today without the formative work done by experienced developers in the past. Core references used during development include:

  • chess-library inspired the of rewrite to zig and served as a core pillar for ideas and verifying behavior in the core library.
  • The zigMemMapper project which drove the development of the included memory mapper for tablebase parsing.
  • The Chess Programming Wiki for obvious reasons, but especially for their explanation and code examples for NNUE
  • The Avalanche chess engine which is dubbed 'the first and strongest UCI chess engine written in zig' for providing a huge source of motivation for improvement. The transposition table and classical search/evaluation algorithms are heavily inspired by this project. Though I can confirm that it is still the strongest engine written in Zig, the neural networks from this project are currently used in the water engine.
  • The pawnocchio chess engine for their extensive perft test suite which is directly used by the library's perft step.
  • The Pyrrhic library which will be used as a reference for the included syzygy suite. The syzygy suite is planned to be a faithful rewrite of this library.
  • The legendary Stockfish engine which served as an invaluable resource through all steps of the development process. This engine helped point out critical bugs early, and served as my reference point for initial elo estimates for the water engine.
Read Entire Article