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.
This generator produces moves for slider pieces: bishops, rooks, and queens. All
of these pieces behave identically, though with different sets of rays that
emanate from the origin square. Claude helped me significantly with the
implementation and unit testing. All the unit tests that took advantage of Claude
for implementation are marked as such with an _ai_claude suffix to the test name.
One unique aspect of this move generator that Claude suggested to me was to use
loop { } instead of a recursive call to next() when the internal iterators expire.
I may try to port this to the other move generators in the future.
To support this move generator, implement a Slider enum in core that represents
one of the three slider pieces.
Add Board::bishops(), Board::rooks() and Board::queens() to return BitBoards of
those pieces. These are analogous to the pawns() and knights() methods that return
their corresponding pieces.
Also in the board create, replace the separate sight method implementations with
a macro. These are all the same, but with a different sight method called under
the hood.
Finally, derive Clone and Debug for the bit_scanner types.
Implement thiserror::Error for a bunch of error types, and remove string errors
from the implementation of the command handler in explorer.
Clean up parsing of basic types all over the place.
Update Cargo files to include thiserror and anyhow.