From fa04cc6ecf3ac1b4b8e8561c5969ee64f09f59fa Mon Sep 17 00:00:00 2001 From: tslil clingman <> Date: Mon, 20 Jan 2020 23:41:44 -0800 Subject: Some bug in moving tall stacks ... ? --- src/game.rs | 21 ++++++++++++++------ src/main.rs | 7 ++++--- src/parser.rs | 64 +++++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 64 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/game.rs b/src/game.rs index 2922121..4cb6fdd 100644 --- a/src/game.rs +++ b/src/game.rs @@ -317,16 +317,16 @@ impl GameState { } } - let num_dropped = drops.iter().map(|&d| d as usize).sum::(); + let sum_dropped = drops.iter().map(|&d| d as usize).sum::(); let carry_capacity = self.size as usize; - if num_dropped > carry_capacity { + if sum_dropped > carry_capacity { return Err(format!( "A move may not exceed the carry capacity of {} stones.", self.size )); } - if num_dropped != std::cmp::max(carry_capacity, stack_len) { + if sum_dropped != std::cmp::min(carry_capacity, stack_len) { return Err(String::from( "A move must effect the whole stack, up to the carry limit.", )); @@ -356,7 +356,7 @@ impl GameState { } if let Some(stack) = &self.board.get(self.pos_to_idx(&pos_new)) { if stack.len() > 0 { - match stack[0].stone { + match stack[stack.len() - 1].stone { Stone::Capstone => { return Err(String::from( "A move may not cover a capstone.", @@ -409,10 +409,19 @@ impl GameState { let idx = copy.pos_to_idx(&pos); let stack: &Stack = &self.board[self.pos_to_idx(pos)]; - copy.board[idx].clear(); + let len = copy.board[idx].len(); - let num_drops = drops.len(); let mut offset = 0; + if len > self.size as usize { + for _i in 0..self.size { + copy.board[idx].pop(); + } + offset = self.size - 1; + } else { + copy.board[idx].clear(); + } + + let num_drops = drops.len(); for drop_idx in 0..num_drops { let pos = pos_vec[pos_vec.len() - 1]; let idx = copy.pos_to_idx(&pos); diff --git a/src/main.rs b/src/main.rs index 6bbe52d..ff98d41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,11 +76,12 @@ fn main() { loop { let inp = action_entry.read_action(); - let stone_owner = game.query_stone_owner(); - let player = game.query_current_player(); - match parse_action(stone_owner, &inp) { + match parse_action(&game, &inp) { Err(err) => message_log.log_error(format!("Input \"{}\": {}", inp, err)), Ok(act) => { + let stone_owner = game.query_stone_owner(); + let player = game.query_current_player(); + message_log.log_message(format!( "{} performs {}{}", player, diff --git a/src/parser.rs b/src/parser.rs index a1d9a32..73457f0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,6 @@ use crate::game::*; -fn parse_move(player: Player, mv: &str) -> Result { +fn parse_move(mv: &str, game: &Game) -> Result { let mut chars = mv.chars(); let c = chars.next(); @@ -9,19 +9,28 @@ fn parse_move(player: Player, mv: &str) -> Result { } let dc = c.unwrap(); - if (dc < '1') || ('9' < dc) { - return Err(String::from( - "Moves must begin with a digit in 1-8 indicating the number of drops.", - )); - } - let sum_drops = dc.to_digit(10).unwrap(); + let sum_drops: u8; + let x; + if (dc >= 'a') && (dc <= 'h') { + // Drop number omitted, must be 1 drop. + sum_drops = 1; + x = dc; + } else { + if (dc < '1') || ('9' < dc) { + return Err(String::from( + "Moves must begin with a digit in 1-8 indicating the number of drops.", + )); + } + sum_drops = dc.to_digit(10).unwrap() as u8; - let c = chars.next(); - if c.is_none() { - return Err(String::from("Moves must specify a stack position.")); + let c = chars.next(); + if c.is_none() { + return Err(String::from("Moves must specify a stack position.")); + } + + x = c.unwrap(); } - let x = c.unwrap(); if (x < 'a') || (x > 'h') { return Err(String::from( "Moves must specify a valid position on the game board.", @@ -48,7 +57,9 @@ fn parse_move(player: Player, mv: &str) -> Result { } let c = c.unwrap(); - let dir; // This is so cool! Rust supports some very nice patterns! + // This is so cool! Rust supports some very nice patterns, and + // checks for uninitialised variables too! + let dir; match c { '+' => dir = Direction::Up, '-' => dir = Direction::Down, @@ -75,17 +86,28 @@ fn parse_move(player: Player, mv: &str) -> Result { } let sum = drops.iter().map(|&d| d as u32).sum::(); - if sum != sum_drops { + let pos = Position { x: x, y: y }; + if sum == 0 { + // Omitted all the drops, it's a total stack move + drops.push(0); + if let Some(stack) = game.query_square(&pos) { + drops.push(std::cmp::min(stack.len() as u8, game.get_size())); + } else { + return Err(String::from( + "Moves must specify a valid position on the game board.", + )); + } + } else if sum != sum_drops as u32 { return Err(format!( "The move called for {} stones, but {} were dropped.", sum_drops, sum )); } - Ok(Action::Move(player, Position { x: x, y: y }, dir, drops)) + Ok(Action::Move(game.query_stone_owner(), pos, dir, drops)) } -fn parse_place(player: Player, pl: &str) -> Result { +fn parse_place(pl: &str, game: &Game) -> Result { let mut chars = pl.chars(); let c = chars.next(); @@ -139,16 +161,20 @@ fn parse_place(player: Player, pl: &str) -> Result { } let y: u8 = (y.to_digit(10).unwrap() - 1) as u8; - Ok(Action::Place(player, Position { x: x, y: y }, stone)) + Ok(Action::Place( + game.query_stone_owner(), + Position { x: x, y: y }, + stone, + )) } -pub fn parse_action(player: Player, act: &str) -> Result { +pub fn parse_action(game: &Game, act: &str) -> Result { if act .chars() .any(|c| c == '+' || c == '-' || c == '>' || c == '<') { - parse_move(player, act) + parse_move(act, game) } else { - parse_place(player, act) + parse_place(act, game) } } -- cgit v1.3.1