Skip to content

Commit

Permalink
ataxx: version 0.2.0 (#3)
Browse files Browse the repository at this point in the history
# Changelog
- Added support for gaps (`Piece::Gap`).
- Removed the `Board` type, replaced by a better `Position`.
- Parsing a `Move` from a string (`FromStr` for `Move).
- Implemented `IntoIterator` for `MoveList`.
- Implemented a not operator (`!`) for `Hash`.
- Add the `UPDATE_HASH` template parameter to `after_move`
- Make the internal value of a `Hash` private.
- Implemented the `std::error::Error` trait for all errors.
- Added a perft function (`ataxx::perft`).
- Renamed `Color` to `Piece`.
- Add a bunch of tests to validate changes.
  • Loading branch information
raklaptudirm committed May 27, 2024
1 parent b99226e commit 1d73d61
Show file tree
Hide file tree
Showing 15 changed files with 912 additions and 861 deletions.
14 changes: 11 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
- pull_request

env:
# treat warnings as errors
RUSTFLAGS: -D warnings
RUSTDOCFLAGS: -D warnings

# use colors when printing
CARGO_TERM_COLOR: always

jobs:
Expand All @@ -21,8 +26,11 @@ jobs:

steps:
- uses: actions/checkout@v4

# update rust to latest stable version
- run: rustup update stable && rustup default stable

- run: cargo clippy --verbose
- run: cargo build --verbose
- run: cargo test --verbose
- run: cargo clippy # look for lint errors
- run: cargo build # look for build errors
- run: cargo test # look for test errors
- run: cargo doc # look for bad documentation
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
[workspace]
members = [
"ataxx"
]
]

[profile.release]
opt-level = 3
codegen-units = 1
lto = true
3 changes: 2 additions & 1 deletion ataxx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ataxx"
version = "0.1.0"
version = "0.2.0"
edition = "2021"

authors = ["Rak Laptudirm <[email protected]>"]
Expand All @@ -12,6 +12,7 @@ keywords = ["ataxx"]
categories = ["games"]

[dependencies]
thiserror = "1.0"
num-traits = "0.2"
num-derive = "0.4"
strum = "0.26"
Expand Down
61 changes: 46 additions & 15 deletions ataxx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,60 @@

<samp>ataxx</samp> is a Rust package which provides various functionalities to deal with the [Ataxx](https://en.wikipedia.org/wiki/Ataxx) game in pure Rust. It provides various functionalities like board representation, move generation, UAI client creation, etc.

```rs
```rust
use ataxx::*;
use std::str::FromStr;
use ataxx::{ Board, Square, Move };

fn main() {
// Parse Ataxx Board from FEN
let mut board = Board::from_str("x5o/7/7/7/7/7/o5x x 0 1").unwrap();
println!("{}" board);
let position = Position::from_str("x5o/7/7/7/7/7/o5x x 0 1").unwrap();

// Make moves on the Board
board.make_move(Move::new_single(Square::F1));
println!("{}", board);
println!("{}\n", position);
println!("perft(6): {}", perft(position, 6));
}

// An implementation of the standard perft function which walks the move
// generation tree of strictly legal moves to count all the leaf nodes of a
// certain depth. Nodes are only counted at the end after the last make-move.
// Thus "higher" terminal nodes (e.g. mate or stalemate) are not counted,
// instead the number of move paths of a certain depth. Perft ignores draws by
// repetition or by the fifty-move rule.
//
// A more advanced implementation of perft is available as `ataxx::perft`.
fn perft(position: Position, depth: u8) -> u64 {
// perft(0) = 1
if depth == 0 {
return 1;
}

// perft(1) = number of moves in the position
if depth == 1 {
// Counting the number of moves in a Position is provided as a separate
// function which is faster than the simple `generate_moves.len()`.
return position.count_moves() as u64;
}

// Undo moves from the Board
board.undo_move();
println!("{}", board);
let mut nodes: u64 = 0;
let movelist = position.generate_moves();

// MoveList implements IntoIterator, so it can be directly used in a for loop.
for m in movelist {
// Providing false as the value of the `UPDATE_HASH` template constant
// disables updating the position's Hash in `after_move` which makes
// it faster than `after_move::<true>()` and can be done here since we
// don't use the position's Hash anywhere.
let new_position = position.after_move::<false>(m);
nodes += perft(new_position, depth - 1);
}

nodes
}

```

## Features
- Fast Board representation and Move generation using BitBoards.
- Types for various features of Ataxx, including `Board`, `Position`, `Move`, `Square`, `Color`, etc.
- Support for semi-unique hashing of Ataxx positions for hash tables.
- Parsing `Position` and `Board` from FEN strings.
- Fast Board representation and Move generation, resulting a perft faster than [<samp>libataxx</samp>](https://github.com/kz04px/libataxx).
- Types for various features of Ataxx, including `Position`, `Move`, `Square`, `Piece`, etc.
- Support for semi-unique hashing of Ataxx positions for hash tables, which is faster yet as strong as zobrist hashing.
- Parsing a FEN string into a `Position`.

Refer to the [documentation](https://docs.rs/ataxx) for a full in depth list of features and functions.
15 changes: 13 additions & 2 deletions ataxx/src/bitboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ impl BitBoard {
/// ```
#[inline(always)]
pub fn lsb(self) -> Square {
Square::try_from(self.0.trailing_zeros()).unwrap()
Square::unsafe_from(self.0.trailing_zeros())
}

/// get_msb returns the most significant Square from the BitBoard.
Expand All @@ -372,7 +372,12 @@ impl BitBoard {
/// ```
#[inline(always)]
pub fn msb(self) -> Square {
Square::try_from(63 - self.0.leading_zeros()).unwrap()
Square::unsafe_from(63 - self.0.leading_zeros())
}

pub fn singles(self) -> BitBoard {
let bar = self | self.east() | self.west();
bar | bar.north() | bar.south()
}
}

Expand Down Expand Up @@ -558,6 +563,12 @@ impl BitBoard {
}
}

impl From<BitBoard> for u64 {
fn from(value: BitBoard) -> Self {
value.0
}
}

// Private constants wrapped in methods for indexing.
impl BitBoard {
const FILE: [BitBoard; File::N] = [
Expand Down
Loading

0 comments on commit 1d73d61

Please sign in to comment.