From 2d9ecd55b6e81f0373f9580fa2c74f89efacd139 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 13 Jul 2025 22:27:26 +0200 Subject: [PATCH] Add simple player --- src/bin/compare.rs | 8 +-- src/game.rs | 30 +++++++++-- src/player/mod.rs | 2 + src/player/single_look_ahead.rs | 92 +++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 src/player/single_look_ahead.rs diff --git a/src/bin/compare.rs b/src/bin/compare.rs index a5cc050..4f4f064 100644 --- a/src/bin/compare.rs +++ b/src/bin/compare.rs @@ -48,10 +48,10 @@ fn compare(player_builders: &[Box], games: usize) { fn main() { let player: Vec> = vec![ - Box::new(player::highest::Highest {}), - Box::new(player::highest::Highest {}), - Box::new(player::highest::Highest {}), - Box::new(player::highest::Highest {}), + Box::new(player::random::Random { seed: 0 }), + Box::new(player::random::Random { seed: 1 }), + Box::new(player::random::Random { seed: 2 }), + Box::new(player::single_look_ahead::SingleLookAhead {}), ]; compare(&player, 10000000); diff --git a/src/game.rs b/src/game.rs index e18eb22..1ae86a2 100644 --- a/src/game.rs +++ b/src/game.rs @@ -14,7 +14,20 @@ pub trait PlayerBuilder: Sync { } #[derive(Debug)] -pub struct AdditionalInformation {} +pub struct AdditionalInformation { + num_player: usize, + not_seen_cards: Vec, +} + +impl AdditionalInformation { + pub fn get_num_player(&self) -> usize { + self.num_player + } + + pub fn get_not_seen_cards(&self) -> &[Card] { + &self.not_seen_cards + } +} #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Color { @@ -118,6 +131,8 @@ pub fn herzen( .map(|i| full_deck[(hand_size * i)..(hand_size * (i + 1))].to_vec()) .collect::>(); + let remainder = &full_deck[hand_size * player.len()..]; + let mut round_starting_player = starting_player; let mut points = vec![0; player.len()]; @@ -136,7 +151,17 @@ pub fn herzen( println!("# Player {index}"); } - let ai = AdditionalInformation {}; + let ai = AdditionalInformation { + num_player: player.len(), + not_seen_cards: hands + .iter() + .enumerate() + .filter_map(|(i, h)| if i != index { Some(h) } else { None }) + .flatten() + .chain(remainder.iter()) + .copied() + .collect::>(), + }; let played_card = player[index].select_card(&hands[index], &stack, &ai); @@ -183,7 +208,6 @@ pub fn herzen( round_starting_player = winner; } - let remainder = &full_deck[hand_size * player.len()..]; let remainder_cost = remainder.iter().map(|c| c.cost()).sum::(); if OUTPUT { diff --git a/src/player/mod.rs b/src/player/mod.rs index c9fe709..b12bcd3 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -1,3 +1,5 @@ +pub mod single_look_ahead; + pub mod cli { use crate::game::{playeble, Player, PlayerBuilder}; diff --git a/src/player/single_look_ahead.rs b/src/player/single_look_ahead.rs new file mode 100644 index 0000000..49b8148 --- /dev/null +++ b/src/player/single_look_ahead.rs @@ -0,0 +1,92 @@ +use crate::game::{playeble, Player, PlayerBuilder}; + +pub struct SingleLookAhead {} + +impl PlayerBuilder for SingleLookAhead { + fn build(&self) -> Box { + Box::new(SingleLookAhead {}) + } +} + +impl Player for SingleLookAhead { + fn select_card( + &mut self, + hand: &[crate::game::Card], + stack: &[crate::game::Card], + additional_information: &crate::game::AdditionalInformation, + ) -> crate::game::Card { + let _ = additional_information; + + if stack.is_empty() { + // first card + + // Play card that is least likely to get the stack. + // For each card calculate likelihood of getting the stack + + hand.iter() + .map(|&c| { + // likelyhood that player can play a card that is lower + // = likelyhood that player does not have card of the color + // + likelyhood that player has card of color that is lower than c given that he has card of color + + // let individual_card_probability = hand.len() as f64 + // / additional_information.get_not_seen_cards().len() as f64; + + ( + c, + additional_information + .get_not_seen_cards() + .iter() + .filter(|&d| c.color == d.color) + .count(), + ) + }) + .max_by(|(_, va), (_, vb)| va.partial_cmp(vb).unwrap()) + .unwrap() + .0 + } else if hand.iter().any(|c| c.color == stack[0].color) { + // serve + let mut playable_cards = hand.to_vec(); + + playable_cards.sort(); + + playable_cards.retain(|&c| playeble(c, hand, stack.first().map(|d| d.color))); + + let highest_card_played = stack + .iter() + .filter(|c| c.color == stack[0].color) + .max_by_key(|c| c.color) + .unwrap(); + + playable_cards + .iter() + .copied() + .filter(|c| c.value < highest_card_played.value) + .max_by_key(|c| c.value) + .unwrap_or(playable_cards[0]) + } else { + // throw + hand.iter() + .map(|&c| { + // likelyhood that player can play a card that is lower + // = likelyhood that player does not have card of the color + // + likelyhood that player has card of color that is lower than c given that he has card of color + + // let individual_card_probability = hand.len() as f64 + // / additional_information.get_not_seen_cards().len() as f64; + + ( + c, + additional_information + .get_not_seen_cards() + .iter() + .filter(|&d| c.color == d.color && d.value < c.value) + .count(), + ) + }) + .max_by(|(_, va), (_, vb)| va.partial_cmp(vb).unwrap()) + .unwrap() + .0 + } + } +}