diff --git a/tak_bot/Cargo.toml b/tak_bot/Cargo.toml index 6c59ae3..0705a20 100644 --- a/tak_bot/Cargo.toml +++ b/tak_bot/Cargo.toml @@ -2,6 +2,7 @@ name = "tak_bot" version = "0.1.0" edition = "2024" +default-run = "tak_bot" [dependencies] tak_lib = { path = "../tak_lib" } diff --git a/tak_lib/src/piece.rs b/tak_lib/src/piece.rs index 2b28f92..348eed5 100644 --- a/tak_lib/src/piece.rs +++ b/tak_lib/src/piece.rs @@ -1,4 +1,4 @@ -use std::fmt::Display; +use std::fmt::Debug; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[repr(u8)] @@ -7,7 +7,7 @@ pub enum Color { Black = 1, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(u8)] pub enum Piece { None = 0, @@ -15,7 +15,7 @@ pub enum Piece { Wall = 2, Caps = 3, } -impl Display for Piece { +impl Debug for Piece { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Piece::None => write!(f, "----"), @@ -50,6 +50,29 @@ impl ColoredPiece { unsafe { std::mem::transmute(piece_val) } } + /// Constructs a new `ColoredPiece` from the given raw value. + pub fn from_u8_opt(val: u8) -> Option { + if val <= 7 && val != 4 { + // safety: value is checked to be in range + Some(unsafe { std::mem::transmute(val) }) + } else { + None + } + } + + /// Constructs a new `ColoredPiece` from the given raw value. + /// + /// ## Panics + /// This panics if `val` is outside the range `0..=7` or is `4`. + pub fn from_u8(val: u8) -> Self { + if val <= 7 && val != 4 { + // safety: value is checked to be in range + unsafe { std::mem::transmute(val) } + } else { + panic!("`val` ({}) was not in range for `ColoredPiece`!", val); + } + } + /// Gets the color of the piece, /// returning `Color::White` if `self` is `None`. pub fn color(&self) -> Color { diff --git a/tak_lib/src/tile.rs b/tak_lib/src/tile.rs index 29e7ecb..74085d6 100644 --- a/tak_lib/src/tile.rs +++ b/tak_lib/src/tile.rs @@ -1,35 +1,84 @@ use std::fmt::Debug; -use crate::piece::Piece; +use crate::piece::ColoredPiece; +/// A tile on the board. +/// +/// bits [2:0] represent the top piece (if any). +/// - bit [2] being the color. +/// - bits [1:0] being the piece type (if any). +/// bits [15:8] represent the number of pieces underneath the top piece. +/// bits [127:16] are the colors of the stacked pieces. +/// - bit [16] is the top-most piece, and bit [127] is the bottom-most piece. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Tile { - /// The colors of the stacked pieces. - /// - /// bit 0 represents the top of the stack (not counting the top piece). - stack: u64, - /// The length of the stack. - stack_len: u8, - /// The piece that is on the tile - piece: Piece, -} +pub struct Tile(u128); impl Debug for Tile { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.stack_len == 0 { - write!(f, "{}", self.piece) + if self.stack_len() == 0 { + self.top_piece().fmt(f) } else { - let stack: String = (0..self.stack_len) + let stack = self.stack(); + let stack: String = (0..self.stack_len()) .rev() - .map(|i| if (self.stack >> i) & 1 == 1 { 'w' } else { 'b' }) + .map(|i| if (stack >> i) == 1 { 'b' } else { 'w' }) .collect(); - write!(f, "{}{}", stack, self.piece) + write!(f, "{}:{:?}", stack, self.top_piece()) } } } impl Tile { + /// An empty tile. + pub const EMPTY: Tile = Tile(0); + + const PIECE_OFFSET: u8 = 0; + const PIECE_MASK: u128 = 0b111u128; + + const LEN_OFFSET: u8 = 8; + const LEN_MASK: u128 = 0xFF00u128; + + const STACK_OFFSET: u8 = 16; + const STACK_MASK: u128 = !0xFFFFu128; + + /// Gets the top piece. + pub fn top_piece(&self) -> ColoredPiece { + ColoredPiece::from_u8((self.0 & 0b111) as u8) + } + + /// Sets the top piece. + pub fn set_top_piece(&mut self, piece: ColoredPiece) { + // clear top_piece + self.0 &= !Self::PIECE_MASK; + // set top_piece + self.0 |= (piece as u128) << Self::PIECE_OFFSET; + } + + /// Gets the length of the stack. pub fn stack_len(&self) -> u8 { - self.stack_len + (self.0 >> 8) as u8 + } + + /// Sets the stack length. + pub fn set_stack_len(&mut self, len: u8) { + // clear stack_len + self.0 &= !Self::LEN_MASK; + // set stack_len + self.0 |= (len as u128) << Self::LEN_OFFSET; + } + + /// Gets the stacked pieces as a bit array. + /// + /// The LSB is the top-most piece, whereas the MSB is the bottom-most piece. + pub fn stack(&self) -> u128 { + self.0 >> Self::STACK_OFFSET + } + + /// Sets the stacked pieces. + pub fn set_stack(&mut self, stack: u128) { + // clear stack + self.0 &= !Self::STACK_MASK; + // set stack + self.0 |= (stack as u128) << Self::STACK_OFFSET; } }