diff --git a/src/main.rs b/src/main.rs index 29800cb..8bc803a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ #![allow(non_snake_case)] use bitvec::prelude::*; +use core::fmt; use rand::prelude::*; +use rand::seq::SliceRandom; use std::cmp::max; +use std::collections::HashMap; +use std::convert::TryInto; use std::io; #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -19,6 +23,23 @@ struct Card { rank: u8, // 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A <- 2 is 0, ... A is 12 } +impl fmt::Display for Card { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let rank: String = if self.rank == 12 { + "A".to_string() + } else if self.rank == 11 { + "K".to_string() + } else if self.rank == 10 { + "Q".to_string() + } else if self.rank == 9 { + "J".to_string() + } else { + (self.rank + 2).to_string() + }; + write!(f, "{} {:?}", rank, self.suit) + } +} + #[derive(Debug, Clone)] struct GameState { player: u8, @@ -39,6 +60,133 @@ struct Node { state: GameState, outcomes: [Option>; 52], } + +fn printHand(state: &GameState) { + let mut hand_clone = state.hand.clone(); + hand_clone.sort_by_key(|x| match (x) { + Some(card) => cardToNum(*card), + None => 255, + }); + for card in hand_clone { + match card { + Some(real_card) => println!("{}", real_card), + None => {} + } + } +} + +fn deal(human: usize, trump: Option) { + match trump { + Some(x) => println!("The trump is {:?}", x), + None => println!("There is no trump"), + } + let mut deck: [Card; 52] = (0..52) + .map(numToCard) + .collect::>() + .try_into() + .unwrap(); + deck.shuffle(&mut thread_rng()); + let (half1, half2) = deck.split_at(26); + let (hand0, hand1) = half1.split_at(13); + let (hand2, hand3) = half2.split_at(13); + let the_hands: [&[Card]; 4] = [hand0, hand1, hand2, hand3]; + let mut states: [GameState; 4] = the_hands + .iter() + .enumerate() + .map(|(i, hand)| { + let mut opt_hand: [Option; 13] = [None; 13]; + for (card_i, card) in hand.iter().enumerate() { + opt_hand[card_i] = Some(*card); + } + GameState { + player: 0, + handPlayer: i.try_into().unwrap(), + trump, + hand: opt_hand, + ruffs: bitarr!(0; 16), + played: bitarr!(0; 52), + trick: [None, None, None], + tricksWonBy0: 0, + sizes: [13, 13, 13, 13], + } + }) + .collect::>() + .try_into() + .unwrap(); + let mut player: usize = 0; + let mut ais: [Option; 4] = [None, None, None, None]; + for _turn in 0..52 { + let card_played: Card = if player == human { + // we'll do the other stuff later + printHand(&states[player as usize]); + println!("What do you play? "); + readCard() + } else { + let mut node: Node = match &ais[player] { + None => new_node(states[player].clone()), + Some(nnode) => nnode.clone(), + }; + for _ in 1..10000 { + let mut hands = hands(&node.state); + let pathcur: (Vec, &mut Node) = search(&mut node, &mut hands); //search! + let path = pathcur.0; + let cur = pathcur.1; + let n: i8; + if cur.state.played.count_ones() == 52 { + let tricks0: u8 = cur.state.tricksWonBy0; + n = if cur.state.handPlayer == 0 || cur.state.handPlayer == 2 { + max(tricks0 as i8 - 6, 0) - max(7 - tricks0 as i8, 0) + } else { + max(7 - tricks0 as i8, 0) - max(tricks0 as i8 - 6, 0) + } + } else { + cur.outcomes[path[path.len() - 1]] = Some(Box::new(new_node(state_transit( + &cur.state, + numToCard(path[path.len() - 1] as u8), + )))); //expand! + n = simulate( + &(*cur.outcomes[path[path.len() - 1]].as_ref().unwrap()).state, + &mut hands, + ); + //simulate! + } + propagate(&mut node, path, n); + } + let mut highest_value = -4000.0; + let mut best_move = 100; + for i in 0..52 { + match &node.outcomes[i] { + None => (), + Some(x) => { + if x.value as f64 / x.visited as f64 > highest_value { + highest_value = x.value as f64 / x.visited as f64; + best_move = i; + } + } + } + } + ais[player] = Some(node); + println!("{} played {}!", player, numToCard(best_move as u8)); + numToCard(best_move as u8) + }; + for i in 0..4 { + match &ais[i] { + Some(node) => match &node.outcomes[cardToNum(card_played) as usize] { + None => { + ais[i] = Some(new_node(state_transit(&node.state, card_played))); + } + Some(x) => { + ais[i] = Some((**x).clone()); + } + }, + None => {} + } + states[i] = state_transit(&states[i], card_played); + } + player = states[0].player as usize; + } +} + fn rankOf(c: Card) -> u8 { c.rank } @@ -238,7 +386,7 @@ fn hands(state: &GameState) -> [Vec; 4] { let mut running = 0; while n_to_assign > 0 { let mut any_done = false; - /* for i in 0..52 { + /* for i in 0..52 { if seen[i] { continue; } @@ -260,8 +408,8 @@ fn hands(state: &GameState) -> [Vec; 4] { any_done = true; } } */ - - any_done = false; + + any_done = false; for i in 0..4 { if sizes[i] > 0 && n_assignable_to[i] == sizes[i] { for j in 0..52 { @@ -326,7 +474,7 @@ fn search<'a>(node: &'a mut Node, hands: &mut [Vec; 4]) -> (Vec, &'a cur.visited += 1; if cur.state.played.count_ones() == 52 { // abort - // no need to do anything with hands + // no need to do anything with hands return (seen, cur); } let mut score: f64 = -10000.0; @@ -349,13 +497,13 @@ fn search<'a>(node: &'a mut Node, hands: &mut [Vec; 4]) -> (Vec, &'a match &cur.outcomes[usize::from(*i)] { None => { seen.push((*i).into()); - let mut new : Vec = vec![]; - for k in &hands[usize::from(cur.state.player)] { - if *k != (*i) { - new.push(*k) - } - } - hands[usize::from(cur.state.player)] = new; + let mut new: Vec = vec![]; + for k in &hands[usize::from(cur.state.player)] { + if *k != (*i) { + new.push(*k) + } + } + hands[usize::from(cur.state.player)] = new; return (seen, cur); } Some(x) => { @@ -372,16 +520,16 @@ fn search<'a>(node: &'a mut Node, hands: &mut [Vec; 4]) -> (Vec, &'a None => panic!("This will not happen. SEARCH PANIC KW!#"), Some(x) => { seen.push(idx); - - let mut new : Vec = vec![]; - for i in &hands[usize::from(cur.state.player)] { - if usize::from(*i) != idx { - new.push(*i) - } - } - - hands[usize::from(cur.state.player)] = new; - cur = x; //lol + + let mut new: Vec = vec![]; + for i in &hands[usize::from(cur.state.player)] { + if usize::from(*i) != idx { + new.push(*i) + } + } + + hands[usize::from(cur.state.player)] = new; + cur = x; //lol } } //cur.outcomes[idx].clone().unwrap(); @@ -403,6 +551,37 @@ fn propagate(node: &mut Node, path: Vec, value: i8) { } } } + +fn readCard() -> Card { + let mut n = String::new(); + + io::stdin().read_line(&mut n).expect("Input!"); + let v: Vec<&str> = n.trim().split(" ").collect(); + let suits: HashMap<&str, Suit> = [ + ("H", Suit::Hearts), + ("D", Suit::Diamonds), + ("C", Suit::Clubs), + ("S", Suit::Spades), + ] + .iter() + .cloned() + .collect(); + let suit: Suit = suits[v[1]]; + let rank: u8; + if v[0] == "A" { + rank = 12; + } else if v[0] == "K" { + rank = 11; + } else if v[0] == "Q" { + rank = 10; + } else if v[0] == "J" { + rank = 9; + } else { + rank = v[0].trim().parse::().expect("RIGHT") - 2; + } + Card { suit, rank } +} + fn simulate(state: &GameState, hands: &mut [Vec; 4]) -> i8 { let mut cur: GameState = state.clone(); loop { @@ -445,15 +624,14 @@ fn simulate(state: &GameState, hands: &mut [Vec; 4]) -> i8 { continue; } if random::() % n == 0 { - p = numToCard(*i); - let mut new : Vec = vec![]; - for k in &hands[usize::from(cur.player)] { - if *k != *i { - new.push(*k) - } - } - hands[usize::from(cur.player)] = new; + let mut new: Vec = vec![]; + for k in &hands[usize::from(cur.player)] { + if *k != *i { + new.push(*k) + } + } + hands[usize::from(cur.player)] = new; break; } else { @@ -467,45 +645,43 @@ fn simulate(state: &GameState, hands: &mut [Vec; 4]) -> i8 { } fn main() { + deal(0, Some(Suit::Hearts)); let mut played = bitarr!(0; 52); - played.set(12, true); - played.set(1, true); - played.set(0, true); let mut node = new_node(GameState { player: 0, handPlayer: 0, trump: Some(Suit::Hearts), hand: [ - Some(card(Suit::Hearts, 0)), - Some(card(Suit::Hearts, 2)), - Some(card(Suit::Hearts, 7)), - Some(card(Suit::Hearts, 8)), - Some(card(Suit::Hearts, 9)), - Some(card(Suit::Hearts, 10)), - Some(card(Suit::Spades, 2)), - Some(card(Suit::Spades, 7)), - Some(card(Suit::Spades, 10)), + Some(card(Suit::Hearts, 5)), + Some(card(Suit::Hearts, 6)), + Some(card(Suit::Hearts, 12)), + Some(card(Suit::Spades, 1)), + Some(card(Suit::Spades, 5)), + Some(card(Suit::Spades, 8)), + Some(card(Suit::Spades, 11)), + Some(card(Suit::Diamonds, 1)), Some(card(Suit::Diamonds, 2)), - Some(card(Suit::Clubs, 1)), - Some(card(Suit::Clubs, 3)), + Some(card(Suit::Diamonds, 7)), + Some(card(Suit::Clubs, 0)), Some(card(Suit::Clubs, 7)), + Some(card(Suit::Clubs, 11)), ], ruffs: bitarr!(0; 16), played, - trick: [ - Some(card(Suit::Spades, 12)), - Some(card(Suit::Spades, 1)), - Some(card(Suit::Spades, 0)), - ], + trick: [None, None, None], tricksWonBy0: 0, - sizes: [13, 12, 12, 12], + sizes: [13, 13, 13, 13], }); + + for i in 0..13 { + println!("Give me {i} from your hand"); + node.state.hand[i] = Some(readCard()); + } + loop { if node.state.player != node.state.handPlayer { println!("Input the card played by player {}", node.state.player); - let mut n = String::new(); - io::stdin().read_line(&mut n).expect("Input!"); - let card: usize = n.trim().parse().expect("RIGHT!"); + let card: usize = cardToNum(readCard()).into(); match &node.outcomes[card] { None => { node = new_node(state_transit(&node.state, numToCard(card as u8))); @@ -517,7 +693,7 @@ fn main() { continue; } for _ in 1..10000 { - let mut hands = hands(&node.state); + let mut hands = hands(&node.state); let pathcur: (Vec, &mut Node) = search(&mut node, &mut hands); //search! let path = pathcur.0; let cur = pathcur.1; @@ -534,7 +710,10 @@ fn main() { &cur.state, numToCard(path[path.len() - 1] as u8), )))); //expand! - n = simulate(&(*cur.outcomes[path[path.len() - 1]].as_ref().unwrap()).state, &mut hands); + n = simulate( + &(*cur.outcomes[path[path.len() - 1]].as_ref().unwrap()).state, + &mut hands, + ); //simulate! } propagate(&mut node, path, n);