summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/board.rs140
1 files changed, 88 insertions, 52 deletions
diff --git a/src/board.rs b/src/board.rs
index 9ba89dc..bd86c12 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -1,5 +1,16 @@
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)
+ }
+}
+
#[derive(PartialEq)]
pub enum Player {
Black,
@@ -40,16 +51,7 @@ impl fmt::Display for Stone {
}
}
-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)
- }
-}
-
+// #[derive(Clone, Copy)]
pub enum Direction {
Up,
Down,
@@ -103,40 +105,68 @@ pub struct Board {
board: Vec<Stack>,
}
-// Probably it's best to split the move and place actions into their
-// own methods, they should also take an extra argument which can be
-// used to log error messages
-
// How to solve code duplication between is_legal_action and
// perform_action?
// TODO: Generate all legal actions for a given player
+pub type Logger = fn(&str);
+
impl Board {
- fn lookup(&self, pos: &Position) -> Option<&Stack> {
+ 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 lookup_square(&self, pos: &Position) -> Option<&Stack> {
let y: u16 = pos.y as u16;
let x: u16 = pos.x as u16;
self.board.get((x + y * self.size) as usize)
}
- fn is_legal_action(&self, mov: &Action) -> bool {
- match mov {
- Action::Place(player, pos, piece) => match self.lookup(pos) {
- Some(stack) => {
- // Incomplete and incorrect, must take account of
- // piece availabilty
- if stack.len() == 0 {
- true
- } else {
- false
- }
+ fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone, log: Logger) -> bool {
+ /* In order to legally place a piece:
+ 1. The desired square must be empty
+ 2. The player must have sufficient pieces
+ */
+ match self.lookup_square(pos) {
+ Some(stack) => {
+ if (stack.len() > 0) || (self.remaining_pieces(player, stone) == 0) {
+ log("Not");
+ false
+ } else {
+ true
}
- None => false,
- },
- Action::Move(player, pos, direction, drops) => match self.lookup(pos) {
- Some(stack) => {
- /* Rules for moving a stack:
- 0. There are stones
+ }
+ None => false,
+ }
+ }
+
+ fn is_legal_move(
+ &self,
+ player: &Player,
+ pos: &Position,
+ direction: &Direction,
+ drops: &Vec<u8>,
+ ) -> bool {
+ match self.lookup_square(pos) {
+ Some(stack) => {
+ /* 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
@@ -146,28 +176,34 @@ impl Board {
We check 0,1,2, and 3 first
*/
- if (stack.len() == 0)
- || (drops.len() == 0)
- || (stack[0].0 != *player)
- || (drops[0] > 1)
- || (drops.iter().sum::<u8>() as u16 > self.size)
- {
- false
- } else {
- let steps: usize = drops.len() - 1;
- let cap: bool = stack[0].1 == Stone::Capstone;
- let (dy, dx): (i8, i8) = match direction {
- Direction::Up => (1, 0),
- Direction::Down => (-1, 0),
- Direction::Left => (0, -1),
- Direction::Right => (0, 1),
- };
+ if (stack.len() == 0)
+ || (drops.len() == 0)
+ || (stack[0].0 != *player)
+ || (drops[0] > 1)
+ || (drops.iter().sum::<u8>() as u16 > self.size)
+ {
+ false
+ } else {
+ let steps: usize = drops.len() - 1;
+ let cap: bool = stack[0].1 == Stone::Capstone;
+ let (dy, dx): (i8, i8) = match direction {
+ Direction::Up => (1, 0),
+ Direction::Down => (-1, 0),
+ Direction::Left => (0, -1),
+ Direction::Right => (0, 1),
+ };
- false
- }
+ false
}
- None => false,
- },
+ }
+ None => false,
+ }
+ }
+
+ fn is_legal_action(&self, mov: &Action, log: Logger) -> bool {
+ match mov {
+ Action::Place(player, pos, stone) => self.is_legal_place(player, pos, stone, log),
+ Action::Move(player, pos, direction, drops) => false,
}
}
}