Add simple player

This commit is contained in:
hal8174 2025-07-13 22:27:26 +02:00
parent ecec35b20f
commit 2d9ecd55b6
Signed by: hal8174
SSH key fingerprint: SHA256:JwuqS+eVfISfKr+DkDQ6NWAbGd1jFAHkPpCM1yCnlTs
4 changed files with 125 additions and 7 deletions

View file

@ -48,10 +48,10 @@ fn compare(player_builders: &[Box<dyn PlayerBuilder>], games: usize) {
fn main() { fn main() {
let player: Vec<Box<dyn PlayerBuilder>> = vec![ let player: Vec<Box<dyn PlayerBuilder>> = vec![
Box::new(player::highest::Highest {}), Box::new(player::random::Random { seed: 0 }),
Box::new(player::highest::Highest {}), Box::new(player::random::Random { seed: 1 }),
Box::new(player::highest::Highest {}), Box::new(player::random::Random { seed: 2 }),
Box::new(player::highest::Highest {}), Box::new(player::single_look_ahead::SingleLookAhead {}),
]; ];
compare(&player, 10000000); compare(&player, 10000000);

View file

@ -14,7 +14,20 @@ pub trait PlayerBuilder: Sync {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct AdditionalInformation {} pub struct AdditionalInformation {
num_player: usize,
not_seen_cards: Vec<Card>,
}
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)] #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Color { pub enum Color {
@ -118,6 +131,8 @@ pub fn herzen<const OUTPUT: bool>(
.map(|i| full_deck[(hand_size * i)..(hand_size * (i + 1))].to_vec()) .map(|i| full_deck[(hand_size * i)..(hand_size * (i + 1))].to_vec())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let remainder = &full_deck[hand_size * player.len()..];
let mut round_starting_player = starting_player; let mut round_starting_player = starting_player;
let mut points = vec![0; player.len()]; let mut points = vec![0; player.len()];
@ -136,7 +151,17 @@ pub fn herzen<const OUTPUT: bool>(
println!("# Player {index}"); 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::<Vec<_>>(),
};
let played_card = player[index].select_card(&hands[index], &stack, &ai); let played_card = player[index].select_card(&hands[index], &stack, &ai);
@ -183,7 +208,6 @@ pub fn herzen<const OUTPUT: bool>(
round_starting_player = winner; round_starting_player = winner;
} }
let remainder = &full_deck[hand_size * player.len()..];
let remainder_cost = remainder.iter().map(|c| c.cost()).sum::<u8>(); let remainder_cost = remainder.iter().map(|c| c.cost()).sum::<u8>();
if OUTPUT { if OUTPUT {

View file

@ -1,3 +1,5 @@
pub mod single_look_ahead;
pub mod cli { pub mod cli {
use crate::game::{playeble, Player, PlayerBuilder}; use crate::game::{playeble, Player, PlayerBuilder};

View file

@ -0,0 +1,92 @@
use crate::game::{playeble, Player, PlayerBuilder};
pub struct SingleLookAhead {}
impl PlayerBuilder for SingleLookAhead {
fn build(&self) -> Box<dyn crate::game::Player> {
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
}
}
}