aboutsummaryrefslogtreecommitdiff
path: root/src/board.rs
diff options
context:
space:
mode:
authortslil clingman <>2020-01-18 17:03:09 -0500
committertslil clingman <>2020-01-18 17:03:09 -0500
commitcdbcc1d2faf198629f5d598bb9a7ba6ab15a922a (patch)
tree9ba2960ba2444d879df42d574ba4b0390c0e8116 /src/board.rs
parentf6a94720061877903487ed98bfee9f19df264a9d (diff)
working on game tracking
Diffstat (limited to 'src/board.rs')
-rw-r--r--src/board.rs362
1 files changed, 0 insertions, 362 deletions
diff --git a/src/board.rs b/src/board.rs
deleted file mode 100644
index 578842c..0000000
--- a/src/board.rs
+++ /dev/null
@@ -1,362 +0,0 @@
-use std::fmt;
-
-#[derive(Clone, Copy)]
-pub struct Position {
- pub x: u8,
- pub y: u8,
-}
-impl fmt::Display for Position {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:x}{}", 10 + self.x, self.y + 1)
- }
-}
-
-#[derive(PartialEq)]
-pub enum Player {
- Black,
- White,
-}
-
-impl fmt::Display for Player {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Player::Black => "B",
- Player::White => "W",
- }
- )
- }
-}
-
-#[derive(PartialEq)]
-pub enum Stone {
- Flat,
- Standing,
- Capstone,
-}
-
-impl fmt::Display for Stone {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Stone::Flat => "",
- Stone::Standing => "S",
- Stone::Capstone => "C",
- }
- )
- }
-}
-
-// #[derive(Clone, Copy)]
-pub enum Direction {
- Up,
- Down,
- Left,
- Right,
-}
-
-impl fmt::Display for Direction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Direction::Up => "+",
- Direction::Down => "-",
- Direction::Left => "<",
- Direction::Right => ">",
- }
- )
- }
-}
-
-pub enum Action {
- Place(Player, Position, Stone),
- Move(Player, Position, Direction, Vec<u8>),
-}
-
-impl fmt::Display for Action {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Action::Place(player, pos, stone) => write!(f, "{}{}{}", pos, player, stone),
- Action::Move(_, pos, direction, drops) => write!(
- f,
- "{}{}{}",
- pos,
- direction,
- drops.into_iter().map(|q| q.to_string()).collect::<String>()
- ),
- }
- }
-}
-
-pub type Stack = Vec<(Player, Stone)>;
-
-pub struct Board<L>
-where
- L: Fn(String),
-{
- size: u8,
- black_flats: u8,
- white_flats: u8,
- black_capstones: u8,
- white_capstones: u8,
- board: Vec<Stack>,
- log: L,
-}
-
-// How to solve code duplication between is_legal_action and
-// perform_action?
-
-// TODO: Generate all legal actions for a given player
-
-impl<L: Fn(String)> Board<L> {
- pub fn get_size(&self) -> u8 {
- self.size
- }
-
- // Defaults to 5x5 if requested things are out of range
- pub fn new(size: u8, log: L) -> (Board<L>, bool) {
- let (flats, caps, correct) = match size {
- 3 => (10, 0, true),
- 4 => (15, 0, true),
- 6 => (30, 1, true),
- 7 => (40, 2, true),
- 8 => (50, 2, true),
- _ => (21, 1, false),
- };
- (
- Board {
- size: size,
- black_flats: flats,
- white_flats: flats,
- black_capstones: caps,
- white_capstones: caps,
- board: {
- let mut v: Vec<Stack> = Vec::new();
- for _i in 0..size * size {
- v.push(Vec::new());
- }
- v
- },
- log: log,
- },
- correct,
- )
- }
-
- pub fn remaining_pieces(&self, player: &Player, stone: &Stone) -> u8 {
- match player {
- Player::Black => {
- if *stone == Stone::Capstone {
- self.black_capstones
- } else {
- self.black_flats
- }
- }
- Player::White => {
- if *stone == Stone::Capstone {
- self.white_capstones
- } else {
- self.white_flats
- }
- }
- }
- }
-
- fn within_bounds(&self, pos: &Position) -> bool {
- if (pos.x < self.size) && (pos.y < self.size) {
- true
- } else {
- false
- }
- }
-
- pub fn query_square(&self, pos: &Position) -> Option<&Stack> {
- if self.within_bounds(pos) {
- self.board.get(self.pos_to_idx(pos))
- } else {
- None
- }
- }
-
- fn pos_to_idx(&self, pos: &Position) -> usize {
- let y: usize = pos.y as usize;
- let x: usize = pos.x as usize;
- x + y * (self.size as usize)
- }
-
- fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone) -> bool {
- /* In order to legally place a piece:
- 1. The desired square must be empty
- 2. The player must have sufficient pieces
- */
- if self.within_bounds(pos) {
- if let Some(stack) = &self.board.get(self.pos_to_idx(pos)) {
- if stack.len() > 0 {
- (self.log)(format!("{} is already occupied.", pos));
- false
- } else if self.remaining_pieces(&player, &stone) == 0 {
- (self.log)(format!(
- "{} has no more remaining {} pieces.",
- player, stone
- ));
- false
- } else {
- true
- }
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_place.",
- pos
- ));
- false
- }
- } else {
- (self.log)(format!("Position {} is not within bounds.", pos));
- false
- }
- }
-
- fn is_legal_move(
- &self,
- player: &Player,
- pos: &Position,
- direction: &Direction,
- drops: &Vec<u8>,
- ) -> bool {
- if self.within_bounds(pos) {
- /* Rules for moving a stack:
- 0. There are stones
- 1. Top stone belongs to player
- 2. Zero or One stones dropped on starting square
- 3. Total number of stones moved does not exceed the carry capacity
- 4. Direction does not contain a capstone
- 5. Wall may only appear on last spot if it's capstone alone that covers
- 6. All stones are used up before then end of the board is met
- */
- if let Some(stack) = &self.board.get(self.pos_to_idx(pos)) {
- if stack.len() == 0 {
- (self.log)(format!("{} has no stones to move.", pos));
- return false;
- } else if drops.len() == 0 {
- (self.log)(format!("A drop sequence for must be specified for a move."));
- return false;
- } else if stack[0].0 != *player {
- (self.log)(format!(
- "{} may not move the stack at {} as it belongs to {}.",
- player, pos, stack[0].0
- ));
- return false;
- } else if drops[0] > 1 {
- (self.log)(format!(
- "A move may only drop 0 or 1 stones at it's origin square."
- ));
- return false;
- // Do the sum in u32 just in case ?
- } else if drops.iter().map(|&d| d as u32).sum::<u32>() > self.size as u32 {
- (self.log)(format!(
- "A move may not exceed the carry limit of {} stones.",
- self.size
- ));
- return false;
- }
- let mut steps: usize = drops.len() - 1;
- let cap: bool = stack[0].1 == Stone::Capstone;
- let mut pos_new = Position { x: pos.x, y: pos.y };
-
- while steps > 0 {
- steps -= 1;
- if {
- match direction {
- Direction::Up => pos_new.y + 1 >= self.size,
- Direction::Down => pos_new.y == 0,
- Direction::Left => pos_new.x + 1 >= self.size,
- Direction::Right => pos_new.x == 0,
- }
- } {
- (self.log)(format!("A move may not extend past the board."));
- return false;
- } else {
- match direction {
- Direction::Up => pos_new.y += 1,
- Direction::Down => pos_new.y -= 1,
- Direction::Left => pos_new.x += 1,
- Direction::Right => pos_new.x -= 1,
- }
- if let Some(stack) = &self.board.get(self.pos_to_idx(&pos_new)) {
- if stack.len() > 0 {
- match stack[0].1 {
- Stone::Capstone => {
- (self.log)(format!("A move may not cover a capstone."));
- return false;
- }
- Stone::Standing => {
- if (steps > 1) || (!cap) {
- (self.log)(format!(
- "A move may not cover a standing stone."
- ));
- return false;
- }
- }
- Stone::Flat => (),
- }
- }
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_move (1).",
- pos_new
- ));
- return false;
- }
- }
- }
- return true;
- } else {
- (self.log)(format!(
- "Internal error: lookup for {} failed in is_legal_move (2).",
- pos
- ));
- return false;
- }
- } else {
- (self.log)(format!("Position {} is not within bounds.", pos));
- false
- }
- }
-
- pub fn is_legal_action(&self, act: &Action) -> bool {
- match act {
- Action::Place(player, pos, stone) => self.is_legal_place(player, pos, stone),
- Action::Move(player, pos, direction, drops) => {
- self.is_legal_move(player, pos, direction, drops)
- }
- }
- }
-
- // Unconditional and so could lead to invalid state, but private
- fn place_stone(&mut self, player: Player, pos: Position, stone: Stone) {
- let idx = self.pos_to_idx(&pos);
- self.board[idx].push((player, stone));
- }
-
- fn move_stack(&mut self, player: Player, pos: Position, direction: Direction, drops: Vec<u8>) {}
-
- pub fn perform_action(&mut self, act: Action) -> bool {
- if self.is_legal_action(&act) {
- match act {
- Action::Place(player, pos, stone) => self.place_stone(player, pos, stone),
- Action::Move(player, pos, direction, drops) => {
- self.move_stack(player, pos, direction, drops)
- }
- }
- true
- } else {
- false
- }
- }
-}