diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/board.rs | 175 |
1 files changed, 134 insertions, 41 deletions
diff --git a/src/board.rs b/src/board.rs index bd86c12..484c31a 100644 --- a/src/board.rs +++ b/src/board.rs @@ -97,7 +97,7 @@ impl fmt::Display for Action { type Stack = Vec<(Player, Stone)>; pub struct Board { - size: u16, + size: u8, black_flats: u8, white_flats: u8, black_capstones: u8, @@ -110,7 +110,7 @@ pub struct Board { // TODO: Generate all legal actions for a given player -pub type Logger = fn(&str); +pub type Logger = fn(String); impl Board { fn remaining_pieces(&self, player: &Player, stone: &Stone) -> u8 { @@ -132,10 +132,18 @@ impl Board { } } + fn within_bounds(&self, pos: &Position) -> bool { + if (pos.x < self.size) && (pos.y < self.size) { + true + } else { + false + } + } + 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) + let y: usize = pos.y as usize; + let x: usize = pos.x as usize; + self.board.get(x + y * (self.size as usize)) } fn is_legal_place(&self, player: &Player, pos: &Position, stone: &Stone, log: Logger) -> bool { @@ -143,16 +151,30 @@ impl Board { 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"); + if self.within_bounds(pos) { + match self.lookup_square(pos) { + Some(stack) => { + if stack.len() > 0 { + log(format!("{} is already occupied.", pos)); + false + } else if self.remaining_pieces(player, stone) == 0 { + log(format!( + "{} has no more remaining {} pieces.", + player, stone + )); + false + } else { + true + } + } + None => { + log(format!("Internal error, lookup for {} failed.", pos)); false - } else { - true } } - None => false, + } else { + log(format!("Position {} is not within bounds.", pos)); + false } } @@ -162,41 +184,112 @@ impl Board { pos: &Position, direction: &Direction, drops: &Vec<u8>, + log: Logger, ) -> bool { - match self.lookup_square(pos) { - Some(stack) => { + if self.within_bounds(pos) { + match self.lookup_square(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 - - 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), - }; - + 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 + */ + Some(stack) => { + if stack.len() == 0 { + log(format!("{} has no stones to move.", pos)); + false + } else if drops.len() == 0 { + log(format!("A drop sequence for must be specified for a move.")); + false + } else if stack[0].0 != *player { + log(format!( + "{} may not move the stack at {} as it belongs to {}.", + player, pos, stack[0].0 + )); + false + } else if drops[0] > 1 { + log(format!( + "A move may only drop 0 or 1 stones at it's origin square." + )); + false + // Do the sum in u32 just in case ? + } else if drops.iter().map(|&d| d as u32).sum::<u32>() > self.size as u32 { + log(format!( + "A move may not exceed the carry limit of {} stones.", + self.size + )); + false + } else { + 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 }; + let mut result = true; + while steps > 0 { + 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, + } + } { + log(format!("A move may not extend past the board.")); + result = false; + break; + } 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, + } + match self.lookup_square(&pos_new) { + Some(stack) => { + if stack.len() > 0 { + match stack[0].1 { + Stone::Capstone => { + log(format!( + "A move may not cover a capstone." + )); + result = false; + break; + } + Stone::Standing => { + if (steps > 1) || (!cap) { + log(format!( + "A move may not cover a standing stone." + )); + result = false; + break; + } + } + Stone::Flat => (), + } + } + } + None => { + log(format!("Internal error, lookup for {} failed.", pos)); + result = false; + break; + } + } + } + steps -= 1; + } + result + } + } + None => { + log(format!("Internal error, lookup for {} failed.", pos)); false } } - None => false, + } else { + log(format!("Position {} is not within bounds.", pos)); + false } } |
