Commit graph

545 commits

Author SHA1 Message Date
dae5179947 Add a README 2025-08-15 17:06:07 -07:00
182bf81126 [board] Fix a counter underflow in the piece set
During perft runs, the PieceSet counter would occasionally underflow, causing
the whole program to crash. This is because, when building a Board from a list
of bitboards, Counts::increment() was only being called once, even when the
bitboard had more than one piece in it. Fix the bug by incrementing during the
loop that sets up the mailbox.

Additionally, refactor the increment() and decrement() methods to be a little
more succinct.
2025-08-15 16:15:09 -07:00
3d73760146 [bitboard, board] Remove BitBoard::empty() and BitBoard::full()
These have been deprecated for a while. Clean up the remaining uses and remove
the methods from BitBoard.
2025-08-15 16:14:34 -07:00
3a0541a2c3 [bitboard] Add a doc comment to BitBoard::first_occupied_square 2025-07-12 20:27:47 -07:00
b6d27356ac [bitboard] Implement BitBoard::occupied_squares_direction
Iterate a BitBoard in a direction (from leading or trailing edge) based on a
board direction.
2025-07-12 20:27:47 -07:00
146e4d34d3 [core] Fix an incorrect assertion in the Score doc test
Negate with - instead of with !.
2025-07-12 20:27:47 -07:00
b505606925 [core] Export Score::CENTIPAWNS_PER_POINT to the crate
This constant is a conversion factor of points to the internal fixed point unit
of centipawns. Points are more familiar to people because pawns are worth 1 pt.

Calculate the scores of the various piece shapes with this constant.
2025-07-12 20:27:47 -07:00
b3ff8dec49 [core] Make Shape::is_promotable() const 2025-07-12 20:27:47 -07:00
484fcf342e [board] Remove a useless .into() call
Clippy pointed this out to me. This .into() call serves no purpose.
2025-07-12 20:27:47 -07:00
45183c910c [bitboard] Replace some references to BitBoard::full() and BitBoard::empty() with the const values
Two doc tests reference the methods instead of the const variables. Update them.
2025-07-12 20:27:47 -07:00
a904e4a5bb [bitboard, board] Replace ray_in_direction! macro with a function
This is simpler than writing a macro, at the expense of some overhead for calling
a function. But the Rust compiler might inline it anyway!

To support this change, implement BitBoard::first_occupied_square_direction, which
iterates a bitboard in a direction (i.e. leading or trailing) depending on the
core::Direction value passed to it.
2025-06-30 15:37:35 -07:00
e3d17219ad [board, position] Simplify check methods
Only one check-testing method, Board::is_in_check(), that tests if the current
active player is in check. It doesn't make sense to test if the non-active player
is in check.
2025-06-29 09:25:08 -07:00
a30553503f [board, explorer, position] Clean up naming of sight and movement methods
These methods have a prefix, either `sight` or `movement`, and then follow the conventions
for other "trio" clusters where there's an un-suffixed method that takes an
Option<Color>, a _active method that uses the active color, and a _unwrapped
method that takes a bare Color.
2025-06-29 09:23:20 -07:00
e7fd65672d [bitboard, board] Make BitBoard::EMPTY and BitBoard::FULL public
Deprecate the methods.

I think I'm undoing a change I made earlier. 🙃
2025-06-29 09:18:44 -07:00
8db533cb52 [board] Use $crate in the fen! macro so you don't have to import Board to get one back 2025-06-27 08:44:56 -07:00
74c0e4144f [position] Remove the to_move_factor from symmetric evaluation
Just use material balance.
2025-06-24 20:04:41 -07:00
1ae6d5df48 [core, position] Rename the type of Score's inner value → Value 2025-06-24 20:01:05 -07:00
4e80cc36ca [core] Implement Display for Score 2025-06-24 15:20:31 -07:00
80ac8ea036 [core] Import std::fmt and remove std:: from Display symbol spelling 2025-06-24 15:18:49 -07:00
9f2dc3fa76 [position] Update import ordering in position.rs 2025-06-21 21:09:01 -07:00
54d9c3838d [position] Export Position::active_color()
Passes through to the Board method.
2025-06-21 21:08:32 -07:00
4b96db230d [board, moves] Derive Clone on several error types
- PlacePieceError
- MakeMoveError
- UnmakeMoveError
2025-06-21 21:08:04 -07:00
f84319272c [explorer, position] Make Position.board private to the crate
Export a Position::board() method that returns a reference to the internal Board.
2025-06-21 21:07:26 -07:00
4ae1fd62b7 [perft] Remove an unused Move import
This was causing a warning.
2025-06-20 14:25:27 -07:00
abaf277fb4 [core] Use the matches! macro to calculate the value of Shape::is_promotable
I learned about this macro a little while ago and it's better than writing out
a match block by hand, and also doesn't require static or const data, like the
previous implementation did.
2025-06-20 14:25:10 -07:00
a91bb8c983 [board] Remove the unused Mailbox::new method
Just use Mailbox::default().
2025-06-20 14:24:16 -07:00
7f25548335 [board, core, position] A simple static evaluation method for scoring positions
Implement a new Evaluator struct that evaluates a Board and returns a score. This
evaluation mechanism uses only a material balance function. It doesn't account
for anything else.

Supporting this, add a Counts struct to the internal piece set structure of a
Board. This struct is responsible for keeping counts of how many pieces of each
shape are on the board for each color. Export a count_piece() method on Board
that returns a count of the number of pieces of a particular color and shape.

Implement a newtype wrapper around i32 called Score that represents the score of
a position in centipawns, i.e. hundredths of a pawn. Add piece values to the
Shape enum.
2025-06-20 14:23:57 -07:00
481ae70698 [core] Directly index the array of Squares with a given index
In Square::from_index_unchecked, instead of using TryFrom to convert the index
to a square, just index directly into the Square::ALL array. This function is
already marked unsafe.
2025-06-19 14:32:07 -07:00
1d8a0dc3a4 Add a release-debug profile
This profile builds binaries for release, but includes debugging information.
Useful for profiling!
2025-06-19 14:27:52 -07:00
0f5a538f0a [explorer, perft, position] Move node count into a new PerftCounters struct 2025-06-19 11:34:59 -07:00
4ce7e89cdb [board, explorer, moves] Clean up the castling rights API
Reorganize castling rights API on Board into methods named according to
conventions applied to other API.

Board::has_castling_right
Board::has_castling_right_active
Board::has_castling_right_unwrapped

    These all check if a color has the right to castle on a particular side
    (wing) of the board. The first takes an Option<Color>, the latter two
    operate on bare Colors: the active color, or an explicit Color.

Board::grant_castling_right
Board::grant_castling_right_active
Board::grant_castling_right_unwrapped

    Grant castling rights to a color. Color arguments follow the pattern above.

Board::revoke_castling_right
Board::revoke_castling_right_active
Board::revoke_castling_right_unwrapped

    Revoke castling rights from a color. Color arguments follow the pattern
    above.

The latter two groups of methods take a new CastleRightsOption type that
specifies either a single Wing or All.

Rework the implementation of CastleRights to take a CastleRightsOption. Update
the unit tests and make sure everything builds.
2025-06-18 23:44:40 +00:00
933924d37a [board] When loading a FEN string, start with no castling rights
The default value of the castle::Rights struct is with all rights granted. When
loading a FEN string, start with none and add to it.
2025-06-18 08:26:29 -07:00
9972ce94d0 [moves] Revoke castling rights only for the player that moved
There was a bug in the code that revokes castling rights after a king move where
it revoked the rights for *all* players, rather than just the current player.
Fix it.
2025-06-18 08:25:41 -07:00
c5cc0646ef [perft] Add back the block on searching into seen positions
Check if the board position has been seen and stop recursion if so.
2025-06-18 08:22:12 -07:00
bf17017694 [explorer] Add several commands to help with debugging
flags
: Print flags for the current board position. This prints the castling rights
and whether the player can castle (regardless of whether they have the right).

make
: Finally reimplement the make command. Change the format so it takes a move in
the UCI long algebraic style.

perft
: Run perft to a given depth on the current board position.
2025-06-18 08:21:31 -07:00
6996cbeb15 [position] Remove the Perft trait
It wasn't serving a purpose.
2025-06-17 16:42:57 -07:00
f3b31d5514 [perft] Print the fen string of the board position 2025-06-17 16:42:35 -07:00
076cdfe66f Remove empty dependencies list from Cargo.lock 2025-06-17 16:42:17 -07:00
801e15fd5a Add style_edition to rustfmt.toml
Set style edition to 2024.
2025-06-17 16:24:46 -07:00
c7b9544004 [moves] Revoke castling rights when King and Rook make moves of their starting squares
When the King moves, revoke all rights for the moving player. When the rook moves,
revoke castling rights for that side of the board, if it's moving off its starting
square.
2025-06-17 16:18:48 -07:00
d73630c85e [perft, position] Print moves and nodes counted at first level
At the first level of depth, print the move and the number of nodes counted in
the tree underneath that node. This behavior imitates Stockfish, and helps with
debugging.

Clean up the output of the Perft binary, and update the check-positions script
to compensate.
2025-06-17 16:17:46 -07:00
37cb9bcaa0 [board, moves] Reorganize castling_right API on Board
Board::color_has_castling_right takes an Option<Color> which it unwraps. With that
unwrapped Color, it can call…

Board::color_has_castling_right_unwrapped, which performs the evaluation with a
non-Option Color.

Clean up some imports.
2025-06-17 08:28:39 -07:00
8dc1e859e0 [chessfriend] Empty crate
The idea for this crate is that it'll be the entry point for interacting with
the chess engine.
2025-06-16 19:29:57 -07:00
4650f88e0a Bump the resolver version in the workspace Cargo.toml 2025-06-16 13:50:18 -07:00
0e61598937 [explorer] Remove make_command module 2025-06-16 13:49:53 -07:00
45037d6fc1 [explorer, moves, perft] A few rustfmt changes that reorder imports 2025-06-16 13:49:29 -07:00
bd112efdf3 Reformat the members list in Cargo.toml
When I added the perft crate, it added it alphabetically at the end of the line
with the moves crate. Why?
2025-06-16 09:02:36 -07:00
7744dd06f0 [position, perft] Move Perft into the position crate
Move the Perft trait into the position crate, and let the perft binary call into
that.

Amend Position::make_move to return a bool in the Ok case that indicates whether
the position has been seen before. Use this to decide whether to continue
recursing during the Perft run. I haven't seen that this makes a difference in
the counts returned by Perft yet.
2025-06-16 09:01:58 -07:00
f0b6cb5f08 [core] Do a little cleanup in core::coordinates
Import std::fmt and remove some commented out code.
2025-06-16 08:58:22 -07:00
3951af76cb [core, moves, position] Implement parsing long algebraic moves
UCI uses a move format it calls "long algebraic". They look like either "e2e4"
for a regular move, or "h7h8q" for a promotion. Implement parsing these move
strings as a two step process. First define an AlgebraicMoveComponents struct
in the moves crate that implements FromStr. This struct reads out an origin
square, a target square, and an optional promotion shape from a string. Then,
implement a pair of methods on Position that take the move components struct
and return a fully encoded Move struct with them.

This process is required because the algebraic string is not enough by itself to
know what kind of move was made. The current position is required to understand
that.

Implement Shape::is_promotable().

Add a NULL move to the Move struct. I'm not sure what this is used for yet, but
the UCI spec specifically calls out a string that encodes a null move, so I added
it. It may end up being unused!

Do a little bit of cleanup in the core crate as well. Use deeper imports (import
std::fmt instead of requring the fully qualified type path) and remove some
unnecessary From implementations.

This commit is also the first instance (I think) of defining an errors module
in lib.rs for the core crate that holds the various error types the crate exports.
2025-06-16 08:57:48 -07:00