Update agent interface to accept the game state (probably a bad idea...)

This commit is contained in:
Dane Johnson 2022-05-20 10:51:47 -05:00
parent b25bd326ae
commit 0e1381c15f
2 changed files with 26 additions and 28 deletions

View File

@ -169,7 +169,7 @@ impl Player {
!self.cards.is_empty() !self.cards.is_empty()
} }
fn wins_challenge(&self, action: Action) -> bool { fn wins_challenge(&self, action: Action) -> bool {
self.cards.iter().find(|&c| c.allows_action(action)).is_some() self.cards.iter().any(|c| c.allows_action(action))
} }
fn lose(&mut self, card: Card, deck: &mut Vec<Card>) { fn lose(&mut self, card: Card, deck: &mut Vec<Card>) {
@ -178,7 +178,7 @@ impl Player {
} }
fn holds(&self, card: Card) -> bool { fn holds(&self, card: Card) -> bool {
self.cards.iter().find(|&c| *c == card).is_some() self.cards.iter().any(|c| *c == card)
} }
} }
@ -248,11 +248,10 @@ impl Game {
} }
fn player_lose_influence(&mut self, id: usize, agents: &[&dyn Agent]) -> CoupResult<()>{ fn player_lose_influence(&mut self, id: usize, agents: &[&dyn Agent]) -> CoupResult<()>{
let player = &mut self.players[id]; let card = agents[id].choose_lost_influence(self);
let card = agents[id] let player = &self.players[id];
.choose_lost_influence(&player.cards);
if player.holds(card) { if player.holds(card) {
player.lose(card, &mut self.discard); self.players[id].lose(card, &mut self.discard);
Ok(()) Ok(())
} else { } else {
Err("Player discarded a card they don't hold") Err("Player discarded a card they don't hold")
@ -268,7 +267,7 @@ impl Game {
ResMode::None => Ok(block), ResMode::None => Ok(block),
ResMode::Target => unreachable!(), ResMode::Target => unreachable!(),
ResMode::Anyone => { ResMode::Anyone => {
let challenger = self.turn_iterator().find(|&id| agents[id].should_action_challenge(&action_challenge)); let challenger = self.turn_iterator().find(|&id| agents[id].should_action_challenge(self, &action_challenge));
if let Some(challenger) = challenger{ if let Some(challenger) = challenger{
let current_player_wins = self.players[self.turn].wins_challenge(action_challenge.action); let current_player_wins = self.players[self.turn].wins_challenge(action_challenge.action);
if current_player_wins { if current_player_wins {
@ -294,7 +293,7 @@ impl Game {
action: block.action, action: block.action,
target: block.target, target: block.target,
})), })),
ResMode::Target => match agents[block.target.unwrap()].choose_block_card(&block) { ResMode::Target => match agents[block.target.unwrap()].choose_block_card(self, &block) {
Some(card) => { Some(card) => {
if card.blocks_action(block.action) { if card.blocks_action(block.action) {
Ok(Phase::BlockChallenge(phase::BlockChallenge { Ok(Phase::BlockChallenge(phase::BlockChallenge {
@ -314,7 +313,7 @@ impl Game {
} }
ResMode::Anyone => { ResMode::Anyone => {
for id in self.turn_iterator() { for id in self.turn_iterator() {
if let Some(card) = agents[id].choose_block_card(&block) { if let Some(card) = agents[id].choose_block_card(self, &block) {
if card.blocks_action(block.action) { if card.blocks_action(block.action) {
return Ok(Phase::BlockChallenge(phase::BlockChallenge { return Ok(Phase::BlockChallenge(phase::BlockChallenge {
blocker: id, blocker: id,
@ -336,7 +335,7 @@ impl Game {
} }
pub fn block_challenge(&mut self, block_challenge: phase::BlockChallenge, agents: &[&dyn Agent]) -> CoupResult<Phase> { pub fn block_challenge(&mut self, block_challenge: phase::BlockChallenge, agents: &[&dyn Agent]) -> CoupResult<Phase> {
if agents[self.turn].should_block_challenge(&block_challenge) { if agents[self.turn].should_block_challenge(self, &block_challenge) {
if self.players[block_challenge.blocker].holds(block_challenge.block_card) { if self.players[block_challenge.blocker].holds(block_challenge.block_card) {
// Player challenged incorrectly, loses influence and turn is forfeit // Player challenged incorrectly, loses influence and turn is forfeit
self.player_lose_influence(self.turn, agents)?; self.player_lose_influence(self.turn, agents)?;
@ -358,11 +357,9 @@ impl Game {
} }
pub fn resolution(&mut self, resolution: phase::Resolution, agents: &[&dyn Agent]) -> CoupResult<Phase> { pub fn resolution(&mut self, resolution: phase::Resolution, agents: &[&dyn Agent]) -> CoupResult<Phase> {
let current_player = &mut self.players.get_mut(self.turn).unwrap();
let current_agent = agents[self.turn];
match resolution.action { match resolution.action {
Income => current_player.coins += 1, Income => self.players[self.turn].coins += 1,
ForeignAid => current_player.coins += 2, ForeignAid => self.players[self.turn].coins += 2,
Coup | Assassinate => match resolution.target { Coup | Assassinate => match resolution.target {
Some(target) => { Some(target) => {
// Target may have died from challenge // Target may have died from challenge
@ -373,12 +370,12 @@ impl Game {
} }
_ => return Err("Coup/Assassinate resolution has no target"), _ => return Err("Coup/Assassinate resolution has no target"),
}, },
Tax => current_player.coins += 3, Tax => self.players[self.turn].coins += 3,
Exchange => { Exchange => {
let drawn = vec![self.deck.pop().unwrap(), self.deck.pop().unwrap()]; let drawn = vec![self.deck.pop().unwrap(), self.deck.pop().unwrap()];
let hand = current_player.cards.clone(); let hand = self.players[self.turn].cards.clone();
let mut choices = [drawn, hand].concat(); let mut choices = [drawn, hand].concat();
let discarded = current_agent.exchange(&choices); let discarded = agents[self.turn].exchange(self, &choices);
for card in discarded { for card in discarded {
if !choices.draw_first(card) { if !choices.draw_first(card) {
return Err("Exchanged a card that was not in choices"); return Err("Exchanged a card that was not in choices");
@ -386,7 +383,7 @@ impl Game {
self.deck.push(card); self.deck.push(card);
} }
} }
current_player.cards = choices; self.players[self.turn].cards = choices;
self.deck.shuffle(); self.deck.shuffle();
} }
Steal => match resolution.target { Steal => match resolution.target {
@ -453,18 +450,19 @@ use phase::Phase;
/// An interface to a game to make strategic decisions. /// An interface to a game to make strategic decisions.
pub trait Agent : fmt::Debug { pub trait Agent : fmt::Debug {
/// Should the agent challenge the action? /// Should the agent challenge the action?
fn should_action_challenge(&self, action_challenge: &phase::ActionChallenge) -> bool; fn should_action_challenge(&self, game: &Game, action_challenge: &phase::ActionChallenge) -> bool;
/// Which [card](Card) the agent wishes to use to block the current action. /// Which [card](Card) the agent wishes to use to block the current action.
/// If the agent does not wish to block, it should return [None] /// If the agent does not wish to block, it should return [None]
fn choose_block_card(&self, block: &phase::Block) -> Option<Card>; fn choose_block_card(&self, game: &Game, block: &phase::Block) -> Option<Card>;
/// Should the agent challenge the block? /// Should the agent challenge the block?
fn should_block_challenge(&self, block_challenge: &phase::BlockChallenge) -> bool; fn should_block_challenge(&self, game: &Game, block_challenge: &phase::BlockChallenge) -> bool;
/// The [Ambassador]'s exchange. /// The [Ambassador]'s exchange.
/// Given 3 or 4 [Cards](Card) the agent must return two cards to the deck. /// Given 3 or 4 [Cards](Card) the agent must return two cards to the deck.
fn exchange(&self, cards: &[Card]) -> [Card; 2]; fn exchange(&self, game: &Game, cards: &[Card]) -> [Card; 2];
/// The player has lost influence, and must choose a [Card] from their hand /// The player has lost influence, and must choose a [Card] from their hand
/// to discard. /// to discard.
fn choose_lost_influence(&self, cards: &[Card]) -> Card; fn choose_lost_influence(&self, game: &Game) -> Card;
} }
#[cfg(test)]
mod test; mod test;

View File

@ -3,19 +3,19 @@ use super::*;
#[derive(Debug)] #[derive(Debug)]
struct DummyAgent(Card, Option<Card>, bool); struct DummyAgent(Card, Option<Card>, bool);
impl Agent for DummyAgent { impl Agent for DummyAgent {
fn should_action_challenge(&self, _action_challenge: &phase::ActionChallenge) -> bool { fn should_action_challenge(&self, _game: &Game, _action_challenge: &phase::ActionChallenge) -> bool {
self.2 self.2
} }
fn choose_block_card(&self, _block: &phase::Block) -> Option<Card> { fn choose_block_card(&self, _game: &Game, _block: &phase::Block) -> Option<Card> {
self.1 self.1
} }
fn should_block_challenge(&self, _block_challenge: &phase::BlockChallenge) -> bool { fn should_block_challenge(&self, _game: &Game, _block_challenge: &phase::BlockChallenge) -> bool {
self.2 self.2
} }
fn exchange(&self, _cards: &[Card]) -> [Card; 2] { fn exchange(&self, _game: &Game, _cards: &[Card]) -> [Card; 2] {
[self.0, self.1.unwrap()] [self.0, self.1.unwrap()]
} }
fn choose_lost_influence(&self, _cards: &[Card]) -> Card { fn choose_lost_influence(&self, _game: &Game) -> Card {
self.0 self.0
} }
} }