use std::{collections::HashMap, fmt::Display}; use rand::{seq::SliceRandom, thread_rng}; const MIN_CARD: u8 = 0; const MAX_CARD: u8 = 104; fn main() { let mut players = Vec::from([ Player { value_function: |card, line| line.push_cost(card).unwrap_or_default(), hand: Default::default(), score: 0, }, Player { value_function: |card, line| line.push_cost(card).unwrap_or_default(), hand: Default::default(), score: 0, }, Player { value_function: |card, line| line.push_cost(card).unwrap_or_default(), hand: Default::default(), score: 0, }, ]); round(&mut players); round(&mut players); round(&mut players); round(&mut players); } fn round(players: &mut [Player]) { let mut cards: Vec = (MIN_CARD..MAX_CARD).collect(); cards.shuffle(&mut thread_rng()); let deck = &mut cards.iter(); let mut state = deck.take(5).copied().map(Line::from).collect::>(); for player in &mut *players { player.set_hand(deck.take(10).copied().collect()); println!("Player: {player}"); } for (i, line) in state.iter().enumerate() { println!("Line {i}: {line}"); } while !players.iter().any(|p| p.hand.is_empty() || p.score > 66) { let cards: Vec = players.iter_mut().map(|p| p.evaluate(&state)).collect(); for (player, card) in players.iter_mut().zip(cards) { let line = state .iter_mut() .min_by_key(|line| (player.value_function)(card, line)) .unwrap(); if let Some(score) = line.push(card) { player.score += score; } } for (i, line) in state.iter().enumerate() { println!("Line {i}: {line}"); } } for player in &mut *players { println!("Player: {player}"); } } fn display_cards(cards: &[u8]) -> String { cards .iter() .map(|c| format!("{c}")) .collect::>() .join("][") } #[derive(Debug, Default)] struct Line { cards: Vec, } impl Line { fn head(&self) -> &u8 { self.cards.last().unwrap() } fn count(&self) -> u8 { self.cards.len().try_into().unwrap() } fn push(&mut self, card: u8) -> Option { let cost = self.push_cost(card); if cost.is_some() { self.cards.clear(); } self.cards.push(card); cost } fn push_cost(&self, card: u8) -> Option { (self.count() >= 5 || card <= *self.head()).then_some(self.count()) } } impl Display for Line { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let cards = self .cards .iter() .map(|c| format!("{c}")) .collect::>() .join("]["); write!(f, "[{cards}]") } } impl From for Line { fn from(value: u8) -> Self { Self { cards: Vec::from([value]), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] struct Move { value: u8, line: usize, card: u8, } impl Display for Move { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[{}] to line {}", self.card, self.line) } } struct Player { value_function: fn(card: u8, line: &Line) -> u8, hand: Vec, score: u8, } impl Player { fn set_hand(&mut self, mut hand: Vec) { hand.sort(); self.hand = hand } fn evaluate(&mut self, state: &[Line]) -> u8 { let value_function = self.value_function; let mut cards = HashMap::new(); for line in state { for card in &self.hand { let value = value_function(*card, line); cards .entry(card) .and_modify(|o| { *o = value.max(*o); }) .or_insert(value); } } cards .iter() .max_by_key(|e| e.1) .and_then(|e| self.hand.iter().position(|c| c == e.1)) .map(|index| self.hand.remove(index)) .unwrap() } } impl Display for Player { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Score: {}, Hand: {}", self.score, display_cards(&self.hand) ) } }