-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
680 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright © 2024 Rak Laptudirm <[email protected]> | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::interface::bitboard_type; | ||
|
||
use super::Square; | ||
|
||
bitboard_type! { | ||
/// A set of Squares implemented as a bitset where the `1 << sq.into()` bit | ||
/// represents whether `sq` is in the BitBoard or not. | ||
struct BitBoard : u64 { | ||
// The BitBoard's Square type. | ||
Square = Square; | ||
|
||
// BitBoards representing the null and the universe sets. | ||
Empty = Self(0); | ||
Universe = Self(0xffffffffffff); | ||
|
||
// BitBoards containing the squares of the first file and the first rank. | ||
FirstFile = Self(0x0000010101010101); | ||
FirstRank = Self(0x00000000000000ff); | ||
} | ||
} | ||
|
||
use crate::interface::{BitBoardType, RepresentableType}; | ||
|
||
impl BitBoard { | ||
/// singles returns the targets of all singular moves from all the source | ||
/// squares given in the provided BitBoard. | ||
pub fn singles(bb: BitBoard) -> BitBoard { | ||
let bar = bb | bb.east() | bb.west(); | ||
(bar | bar.north() | bar.south()) ^ bb | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Make the contents of the non-namespaced | ||
// modules public, so they can be accessed | ||
// without their parent namespace. | ||
pub use self::bitboard::*; | ||
pub use self::piece::*; | ||
pub use self::position::*; | ||
pub use self::r#move::*; | ||
pub use self::square::*; | ||
|
||
// Non-namespaced modules. | ||
mod bitboard; | ||
mod r#move; | ||
mod piece; | ||
mod position; | ||
mod square; | ||
|
||
#[cfg(test)] | ||
mod tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// Copyright © 2024 Rak Laptudirm <[email protected]> | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use std::fmt; | ||
use std::str::FromStr; | ||
|
||
use thiserror::Error; | ||
|
||
use super::Square; | ||
use crate::interface::{MoveType, RepresentableType, TypeParseError}; | ||
|
||
/// Move represents an Isolation move which can be played on the Board. | ||
#[derive(Copy, Clone, PartialEq, Eq, Default)] | ||
pub struct Move(u16); | ||
|
||
impl MoveType for Move { | ||
const NULL: Self = Move(1 << 15); | ||
const MAX_IN_GAME: usize = 48; | ||
const MAX_IN_POSITION: usize = 352; | ||
} | ||
|
||
impl From<u16> for Move { | ||
fn from(value: u16) -> Self { | ||
Move(value) | ||
} | ||
} | ||
|
||
impl From<Move> for u16 { | ||
fn from(value: Move) -> Self { | ||
value.0 | ||
} | ||
} | ||
|
||
impl Move { | ||
// Bit-widths of fields. | ||
const PAWN_WIDTH: u16 = 6; | ||
const TILE_WIDTH: u16 = 6; | ||
|
||
// Bit-masks of fields. | ||
const PAWN_MASK: u16 = (1 << Move::PAWN_WIDTH) - 1; | ||
const TILE_MASK: u16 = (1 << Move::TILE_WIDTH) - 1; | ||
|
||
// Bit-offsets of fields. | ||
const PAWN_OFFSET: u16 = 0; | ||
const TILE_OFFSET: u16 = Move::PAWN_OFFSET + Move::PAWN_WIDTH; | ||
|
||
/// new returns a new jump Move from the given pawn Square to the given | ||
/// tile Square. These Squares can be recovered with the [`Move::pawn`] and | ||
/// [`Move::tile`] methods respectively. | ||
/// ``` | ||
/// use tetka_games::isolation::*; | ||
/// | ||
/// let mov = Move::new(Square::A1, Square::A3); | ||
/// | ||
/// assert_eq!(mov.pawn(), Square::A1); | ||
/// assert_eq!(mov.tile(), Square::A3); | ||
/// ``` | ||
#[inline(always)] | ||
#[rustfmt::skip] | ||
pub fn new(pawn: Square, tile: Square) -> Move { | ||
Move( | ||
(pawn as u16) << Move::PAWN_OFFSET | | ||
(tile as u16) << Move::TILE_OFFSET | ||
) | ||
} | ||
|
||
/// Source returns the pawn Square of the moving piece. This is equal to the | ||
/// tile Square if the given Move is of singular type. | ||
/// ``` | ||
/// use tetka_games::isolation::*; | ||
/// | ||
/// let mov = Move::new(Square::A1, Square::A3); | ||
/// | ||
/// assert_eq!(mov.pawn(), Square::A1); | ||
/// ``` | ||
pub fn pawn(self) -> Square { | ||
unsafe { | ||
Square::unsafe_from((self.0 >> Move::PAWN_OFFSET) & Move::PAWN_MASK) | ||
} | ||
} | ||
|
||
/// Target returns the tile Square of the moving piece. | ||
/// ``` | ||
/// use tetka_games::isolation::*; | ||
/// | ||
/// let mov = Move::new(Square::A1, Square::A3); | ||
/// | ||
/// assert_eq!(mov.tile(), Square::A3); | ||
/// ``` | ||
pub fn tile(self) -> Square { | ||
unsafe { | ||
Square::unsafe_from((self.0 >> Move::TILE_OFFSET) & Move::TILE_MASK) | ||
} | ||
} | ||
} | ||
|
||
#[derive(Error, Debug)] | ||
pub enum MoveParseError { | ||
#[error("length of move string should be 2 or 4, not {0}")] | ||
BadLength(usize), | ||
#[error("bad pawn square string \"{0}\"")] | ||
BadSquare(#[from] TypeParseError), | ||
} | ||
|
||
impl FromStr for Move { | ||
type Err = MoveParseError; | ||
|
||
/// from_str converts the given string representation of a Move into a [Move]. | ||
/// The format supported is `<pawn><tile>`. For how `<pawn>` and `<tile>` are | ||
/// parsed, take a look at [`Square::FromStr`](Square::from_str). This function | ||
/// can be treated as the inverse of the [`fmt::Display`] trait for [Move]. | ||
/// ``` | ||
/// use tetka_games::isolation::*; | ||
/// use std::str::FromStr; | ||
/// | ||
/// let jump = Move::new(Square::A1, Square::A3); | ||
/// assert_eq!(Move::from_str(&jump.to_string()).unwrap(), jump); | ||
/// ``` | ||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
if s.len() != 4 { | ||
return Err(MoveParseError::BadLength(s.len())); | ||
} | ||
|
||
let pawn = Square::from_str(&s[..2])?; | ||
let tile = Square::from_str(&s[2..])?; | ||
|
||
Ok(Move::new(pawn, tile)) | ||
} | ||
} | ||
|
||
impl fmt::Display for Move { | ||
/// Display formats the given Move in a human-readable manner. The format used | ||
/// for displaying moves is `<pawn><tile>`. For the formatting of `<pawn>` and | ||
/// `<tile>`, refer to `Square::Display`. [`Move::NULL`] is formatted as `null`. | ||
/// ``` | ||
/// use tetka_games::isolation::*; | ||
/// | ||
/// let null = Move::NULL; | ||
/// let jump = Move::new(Square::A1, Square::A3); | ||
/// | ||
/// assert_eq!(null.to_string(), "null"); | ||
/// assert_eq!(jump.to_string(), "a1a3"); | ||
/// ``` | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
if *self == Move::NULL { | ||
write!(f, "null") | ||
} else { | ||
write!(f, "{}{}", self.pawn(), self.tile()) | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Debug for Move { | ||
/// Debug formats the given Move into a human-readable debug string. It uses | ||
/// `Move::Display` trait under the hood for formatting the Move. | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright © 2024 Rak Laptudirm <[email protected]> | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use std::fmt; | ||
use std::ops; | ||
use std::str::FromStr; | ||
|
||
use crate::interface::representable_type; | ||
use crate::interface::ColoredPieceType; | ||
use crate::interface::RepresentableType; | ||
|
||
representable_type!( | ||
/// Color represents all the possible colors that an ataxx piece can have, | ||
/// specifically, Black and White. | ||
enum Color: u8 { White "w", Black "b", } | ||
); | ||
|
||
impl ops::Not for Color { | ||
type Output = Color; | ||
|
||
/// not implements the not unary operator (!) which switches the current Color | ||
/// to its opposite, i.e. [`Color::Black`] to [`Color::White`] and vice versa. | ||
fn not(self) -> Self::Output { | ||
unsafe { Color::unsafe_from(self as usize ^ 1) } | ||
} | ||
} | ||
|
||
representable_type!( | ||
/// Piece represents the types of pieces in ataxx, namely Piece and Block. | ||
enum Piece: u8 { Pawn "p", Tile "-", } | ||
); | ||
|
||
representable_type!( | ||
/// Piece represents all the possible ataxx pieces. | ||
enum ColoredPiece: u8 { WhitePawn "P", BlackPawn "p", Tile "-", } | ||
); | ||
|
||
impl ColoredPieceType for ColoredPiece { | ||
type Piece = Piece; | ||
type Color = Color; | ||
|
||
fn piece(self) -> Piece { | ||
match self { | ||
ColoredPiece::WhitePawn | ColoredPiece::BlackPawn => Piece::Pawn, | ||
ColoredPiece::Tile => Piece::Tile, | ||
} | ||
} | ||
|
||
fn color(self) -> Color { | ||
match self { | ||
ColoredPiece::WhitePawn => Color::White, | ||
ColoredPiece::BlackPawn => Color::Black, | ||
_ => panic!("Piece::color() called on Piece::Tile"), | ||
} | ||
} | ||
} |
Oops, something went wrong.