From 1d6eeada8378e215689386bfdb76b38616a7e256 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Fri, 20 May 2022 14:42:16 -0500 Subject: [PATCH] Cli player with some ability to play --- src/cli.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 - src/main.rs | 21 ++++++++- 3 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/cli.rs diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..faada8e --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,130 @@ +use coup::*; +use Action::*; + +use std::io; +use std::io::Write; + +#[derive(Debug)] +pub struct HumanAgent { + turn: usize +} + +impl HumanAgent { + pub fn new(turn: usize) -> Self { + HumanAgent { turn } + } + + fn inform(&self, game: &Game) { + let player = &game.players[self.turn]; + println!("Player {}:", self.turn); + match player.cards.as_slice() { + &[card1, card2] => println!("Your identities are {} and {}", card1, card2), + &[card] => println!("Your identity is {}", card), + _ => unreachable!(), + } + println!("Remaining players are:"); + for id in 0..game.players.len() { + if id == self.turn || !game.players[id].is_alive() { + continue + } + println!(" Player {} with {} coins and {} influence", + id, game.players[id].coins, game.players[id].cards.len()); + } + println!("Discard is showing:"); + for card in &game.discard { + println!(" {}", card); + } + } +} + +impl Agent for HumanAgent { + fn choose_move(&self, game: &Game) -> Move { + self.inform(game); + println!("Choose an action"); + let action = loop { + for i in 1..=7 { + println!(" {}) {}", i, get_action(i).unwrap()); + } + let index = get_index(); + if let Some(action) = get_action(index) { + break action; + } else { + println!("Bad choice"); + } + }; + let target = if action.is_targeted() { Some(get_index()) } else { None }; + Move { action, target } + } + fn should_action_challenge(&self, game: &Game, move_: Move) -> bool { + self.inform(game); + loop { + if let Some(target) = move_.target { + if target == self.turn { + print!("Will you challenge {} targeting you?", move_.action); + } else { + print!("Will you challenge {} targeting Player {}?", move_.action, target); + } + } else { + print!("Will you challenge {}?", move_.action); + } + match yes_or_no() { + Some(b) => break b, + None => println!("Bad input"), + } + } + } + fn choose_block_card(&self, game: &Game, move_: Move) -> Option { + todo!(); + } + fn should_block_challenge(&self, game: &Game, move_: Move, block: Block) -> bool { + todo!(); + } + fn exchange(&self, game: &Game, cards: &[Card]) -> [Card; 2] { + todo!(); + } + fn choose_lost_influence(&self, game: &Game) -> Card { + todo!(); + } +} + +fn get_action(index: usize) -> Option { + match index { + 1 => Some(Income), + 2 => Some(ForeignAid), + 3 => Some(Coup), + 4 => Some(Tax), + 5 => Some(Assassinate), + 6 => Some(Exchange), + 7 => Some(Steal), + _ => None + } +} + +fn get_index() -> usize { + let mut string = String::new(); + io::stdin() + .read_line(&mut string) + .unwrap(); + string + .trim() + .parse() + .unwrap() +} + +fn yes_or_no() -> Option { + print!(" [y/n]: "); + io::stdout().flush().unwrap(); + let mut string = String::new(); + io::stdin() + .read_line(&mut string) + .unwrap(); + let string = string.to_uppercase(); + let string = string.trim(); + if string.starts_with("Y") { + Some(true) + } else if string.starts_with("N") { + Some(false) + } else { + None + } +} diff --git a/src/lib.rs b/src/lib.rs index 05ea960..ba0cbac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -412,7 +412,6 @@ pub struct Block { /// some phases might be skipped. #[derive(PartialEq, Debug)] pub enum Phase { - Action(Move), ActionChallenge(Move), Block(Move), BlockChallenge(Move, Block), diff --git a/src/main.rs b/src/main.rs index 8344815..bc9d233 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,22 @@ use coup::*; -fn main() { - println!("Hello, world!"); +mod cli; +use cli::HumanAgent; + +fn main() -> CoupResult<()> { + let mut game = Game::new(2); + let agents: &[&dyn Agent] = &[&HumanAgent::new(0), &HumanAgent::new(1)]; + while !game.is_game_over() { + let mut phase = game.action(agents)?; + while phase != Phase::Done { + phase = match phase { + Phase::ActionChallenge(move_) => game.action_challenge(move_, agents)?, + Phase::Block(move_) => game.block(move_, agents)?, + Phase::BlockChallenge(move_, block) => game.block_challenge(move_, block, agents)?, + Phase::Resolution(move_) => game.resolution(move_, agents)?, + Phase::Done => unreachable!(), + } + } + } + Ok(()) }