diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..234ae30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# will have compiled files and executables +debug/ +target/ +.vscode/ +.zed/ +.helix/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..22ae2c5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "tak_bot" +version = "0.1.0" +dependencies = [ + "tak_lib", +] + +[[package]] +name = "tak_lib" +version = "0.1.0" + +[[package]] +name = "tak_server" +version = "0.1.0" + +[[package]] +name = "tak_visualizer" +version = "0.1.0" diff --git a/tak_bot/Cargo.toml b/tak_bot/Cargo.toml index a0cc400..6c59ae3 100644 --- a/tak_bot/Cargo.toml +++ b/tak_bot/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +tak_lib = { path = "../tak_lib" } diff --git a/tak_lib/src/lib.rs b/tak_lib/src/lib.rs index b93cf3f..17d9ebd 100644 --- a/tak_lib/src/lib.rs +++ b/tak_lib/src/lib.rs @@ -1,14 +1,10 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} +pub mod piece; +pub mod tile; -#[cfg(test)] -mod tests { - use super::*; +use crate::{piece::Color, tile::Tile}; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Board { + to_move: Color, + tiles: [[Tile; N]; N], } diff --git a/tak_lib/src/piece.rs b/tak_lib/src/piece.rs new file mode 100644 index 0000000..2b28f92 --- /dev/null +++ b/tak_lib/src/piece.rs @@ -0,0 +1,82 @@ +use std::fmt::Display; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[repr(u8)] +pub enum Color { + White = 0, + Black = 1, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[repr(u8)] +pub enum Piece { + None = 0, + Flat = 1, + Wall = 2, + Caps = 3, +} +impl Display for Piece { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Piece::None => write!(f, "----"), + Piece::Flat => write!(f, "Flat"), + Piece::Wall => write!(f, "Wall"), + Piece::Caps => write!(f, "Caps"), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[repr(u8)] +pub enum ColoredPiece { + None = 0, + WhiteFlat = 1, + WhiteWall = 2, + WhiteCaps = 3, + + BlackFlat = 5, + BlackWall = 6, + BlackCaps = 7, +} + +impl ColoredPiece { + /// Constructs a new `ColoredPiece`. + pub fn new(piece: Piece, color: Color) -> Self { + let mut piece_val = (piece as u8) | ((color as u8) << 2); + if piece_val == 4 { + piece_val = 0; + } + // safety: value will always be in range + unsafe { std::mem::transmute(piece_val) } + } + + /// Gets the color of the piece, + /// returning `Color::White` if `self` is `None`. + pub fn color(&self) -> Color { + if (*self as u8 >> 2) == 1 { + Color::Black + } else { + Color::White + } + } + + /// Gets the color of the piece, + /// returning `None` if `self` is `None`. + pub fn color_opt(&self) -> Option { + let val = *self as u8; + if val == 0 { + return None; + } else if (val >> 2) == 1 { + Some(Color::Black) + } else { + Some(Color::White) + } + } + + /// Gets the piece type of this piece. + pub fn piece(&self) -> Piece { + let piece_val = *self as u8 & 0b11; + // safety: value will always be in range + unsafe { std::mem::transmute(piece_val) } + } +} diff --git a/tak_lib/src/tile.rs b/tak_lib/src/tile.rs new file mode 100644 index 0000000..29e7ecb --- /dev/null +++ b/tak_lib/src/tile.rs @@ -0,0 +1,35 @@ +use std::fmt::Debug; + +use crate::piece::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, +} + +impl Debug for Tile { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.stack_len == 0 { + write!(f, "{}", self.piece) + } else { + let stack: String = (0..self.stack_len) + .rev() + .map(|i| if (self.stack >> i) & 1 == 1 { 'w' } else { 'b' }) + .collect(); + write!(f, "{}{}", stack, self.piece) + } + } +} + +impl Tile { + pub fn stack_len(&self) -> u8 { + self.stack_len + } +}