use crate::game::*; fn parse_move(player: Player, mv: &str) -> Result { let mut chars = mv.chars(); let c = chars.next(); if c.is_none() { return Err(String::from("Empty string cannot be parsed.")); } 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 c = chars.next(); if c.is_none() { return Err(String::from("Moves must specify a stack position.")); } let x = c.unwrap(); if (x < 'a') || (x > 'h') { return Err(String::from( "Moves must specify a valid position on the game board.", )); } let x: u8 = x as u8 - 'a' as u8; let c = chars.next(); if c.is_none() { return Err(String::from("Moves must specify a stack position.")); } let y = c.unwrap(); if (y < '1') || (y > '8') { return Err(String::from( "Moves must specify a position on the game board.", )); } let y: u8 = (y.to_digit(10).unwrap() - 1) as u8; let c = chars.next(); if c.is_none() { return Err(String::from("Moves must specify a move direction.")); } let c = c.unwrap(); let dir; // This is so cool! Rust supports some very nice patterns! match c { '+' => dir = Direction::Up, '-' => dir = Direction::Down, '<' => dir = Direction::Left, '>' => dir = Direction::Right, _ => return Err(String::from("The valid directions are +,-,<, and >.")), } let mut drops: Vec = Vec::new(); for d in chars { if let Some(u) = d.to_digit(10) { if u > 9 { return Err(String::from( "No more than 8 pieces may be dropped on a given square.", )); } else { drops.push(u as u8) } } else { return Err(String::from( "A move must specify a number of pieces dropped for each square.", )); } } let sum = drops.iter().map(|&d| d as u32).sum::(); if sum != sum_drops { 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)) } fn parse_place(player: Player, pl: &str) -> Result { let mut chars = pl.chars(); let c = chars.next(); if c.is_none() { return Err(String::from("An action cannot be blank.")); } let stone_c = c.unwrap(); let stone; let x; if (stone_c == 'F') || (stone_c == 'C') || (stone_c == 'S') { match stone_c { 'C' => stone = Stone::Capstone, 'S' => stone = Stone::Standing, _ => stone = Stone::Flat, } let c = chars.next(); if c.is_none() { return Err(String::from( "Placements must specify a position on the game board.", )); } x = c.unwrap(); } else { stone = Stone::Flat; x = stone_c; } if (x < 'a') || (x > 'h') { return Err(String::from( "Placements must specify a valid position on the game board.", )); } let x: u8 = x as u8 - 'a' as u8; let c = chars.next(); if c.is_none() { return Err(String::from( "Placements must specify a position on the game board.", )); } let y = c.unwrap(); if (y < '1') || (y > '8') { return Err(String::from( "Placements must specify a valid position on the game board.", )); } let y: u8 = (y.to_digit(10).unwrap() - 1) as u8; Ok(Action::Place(player, Position { x: x, y: y }, stone)) } pub fn parse_action(player: Player, act: &str) -> Result { if act .chars() .any(|c| c == '+' || c == '-' || c == '>' || c == '<') { parse_move(player, act) } else { parse_place(player, act) } }