From 30fcafe293bd5d272fff24f66ddafe4ed835d5f0 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Wed, 18 May 2022 12:19:12 -0500 Subject: [PATCH] Added positive tests for blocking --- src/lib.rs | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 343fc0d..1d5cf0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,6 +236,43 @@ impl Game { player.lose(card, &mut self.discard); } + pub fn block(&mut self, block: phase::Block, agents: &[&dyn Agent]) -> CoupResult { + match block.action.blocker_mode() { + ResMode::None => Ok(Phase::Resolution(phase::Resolution { + action: block.action, + target: block.target, + })), + ResMode::Target => match agents[block.target.unwrap()].choose_block_card(&block) { + Some(card) => Ok(Phase::BlockChallenge(phase::BlockChallenge { + blocker: block.target.unwrap(), + block_card: card, + action: block.action, + target: block.target, + })), + None => Ok(Phase::Resolution(phase::Resolution { + action: block.action, + target: block.target, + })), + } + ResMode::Anyone => { + for id in self.turn_iterator() { + if let Some(card) = agents[id].choose_block_card(&block) { + return Ok(Phase::BlockChallenge(phase::BlockChallenge { + blocker: id, + block_card: card, + action: block.action, + target: block.target, + })) + } + } + Ok(Phase::Resolution(phase::Resolution { + action: block.action, + target: block.target, + })) + } + } + } + pub fn block_challenge(&mut self, block_challenge: phase::BlockChallenge, agents: &[&dyn Agent]) -> CoupResult { if agents[self.turn].should_block_challenge(&block_challenge) { if self.players[block_challenge.blocker].holds(block_challenge.block_card) { @@ -318,7 +355,8 @@ pub mod phase { #[derive(PartialEq, Debug)] pub struct Block { - + pub action: Action, + pub target: Option, } #[derive(PartialEq, Debug)] @@ -339,6 +377,7 @@ pub mod phase { use phase::Phase; pub trait Agent : fmt::Debug { + fn choose_block_card(&self, block: &phase::Block) -> Option; fn should_block_challenge(&self, block_challenge: &phase::BlockChallenge) -> bool; fn exchange(&self, cards: &[Card]) -> [Card; 2]; fn choose_lost_influence(&self, cards: &[Card]) -> Card; @@ -349,10 +388,14 @@ mod test { use super::*; macro_rules! make_dummy_agent { - ($sbc: expr, $e: expr, $cli: expr) => {{ + ($cbc: expr, $sbc: expr, $e: expr, $cli: expr) => {{ #[derive(Debug)] struct DummyAgent; impl Agent for DummyAgent { + #[allow(unused)] + fn choose_block_card(&self, block: &phase::Block) -> Option { + $cbc + } #[allow(unused)] fn should_block_challenge(&self, block_challenge: &phase::BlockChallenge) -> bool { $sbc @@ -370,11 +413,112 @@ mod test { }} } + #[test] + fn test_block() { + let non_blocking_agent = make_dummy_agent!(None, unimplemented!(), unimplemented!(), unimplemented!()); + let ambassador_block_agent = make_dummy_agent!(Some(Ambassador), unimplemented!(), unimplemented!(), unimplemented!()); + let duke_block_agent = make_dummy_agent!(Some(Duke), unimplemented!(), unimplemented!(), unimplemented!()); + + let deck = vec![]; + let discard = vec![]; + let players = vec![ + Player { coins: 2, cards: vec![Duke, Captain] }, + Player { coins: 2, cards: vec![Contessa] }, + Player { coins: 2, cards: vec![Ambassador] }, + ]; + let game = Game { + deck, + discard, + players, + turn: 0 + }; + + + // Test unblockable + { + let mut game = game.clone(); + assert_eq!( + game.block(phase::Block { + action: Income, + target: None, + }, &[&non_blocking_agent, &ambassador_block_agent, &ambassador_block_agent]), + Ok(Phase::Resolution(phase::Resolution { + action: Income, + target: None + })) + ); + } + + // Test target blocked + { + let mut game = game.clone(); + assert_eq!( + game.block(phase::Block { + action: Steal, + target: Some(2), + }, &[&non_blocking_agent, &ambassador_block_agent, &ambassador_block_agent]), + Ok(Phase::BlockChallenge(phase::BlockChallenge { + blocker: 2, + block_card: Ambassador, + action: Steal, + target: Some(2), + })) + ); + } + + // Test target non-blocked + { + let mut game = game.clone(); + assert_eq!( + game.block(phase::Block { + action: Steal, + target: Some(2), + }, &[&non_blocking_agent, &ambassador_block_agent, &non_blocking_agent]), + Ok(Phase::Resolution(phase::Resolution { + action: Steal, + target: Some(2), + })) + ); + } + + // Test anyone blocked + { + let mut game = game.clone(); + assert_eq!( + game.block(phase::Block { + action: ForeignAid, + target: None, + }, &[&non_blocking_agent, &non_blocking_agent, &duke_block_agent]), + Ok(Phase::BlockChallenge(phase::BlockChallenge { + blocker: 2, + block_card: Duke, + action: ForeignAid, + target: None, + })) + ); + } + + // Test no one blocked + { + let mut game = game.clone(); + assert_eq!( + game.block(phase::Block { + action: ForeignAid, + target: None, + }, &[&non_blocking_agent, &non_blocking_agent, &non_blocking_agent]), + Ok(Phase::Resolution(phase::Resolution { + action: ForeignAid, + target: None, + })) + ); + } + } + #[test] fn test_block_challenge() { - let challenge_agent = make_dummy_agent!(true, unimplemented!(), Assassin); - let non_challenge_agent = make_dummy_agent!(false, unimplemented!(), Assassin); - let block_agent = make_dummy_agent!(unimplemented!(), unimplemented!(), Contessa); + let challenge_agent = make_dummy_agent!(unimplemented!(), true, unimplemented!(), Assassin); + let non_challenge_agent = make_dummy_agent!(unimplemented!(), false, unimplemented!(), Assassin); + let block_agent = make_dummy_agent!(unimplemented!(), unimplemented!(), unimplemented!(), Contessa); let deck = vec![]; let discard = vec![]; let players = vec![ @@ -440,7 +584,7 @@ mod test { #[test] fn test_resolution() { - let dummy_agent = make_dummy_agent!(unimplemented!(), [Contessa, Duke], Captain); + let dummy_agent = make_dummy_agent!(unimplemented!(), unimplemented!(), [Contessa, Duke], Captain); let deck = vec![Contessa, Contessa]; let discard = vec![]; let players = vec![