|
|
@ -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<Box<Node>>; 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<Suit>) { |
|
|
|
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::<Vec<Card>>() |
|
|
|
.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<Card>; 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::<Vec<GameState>>() |
|
|
|
.try_into() |
|
|
|
.unwrap(); |
|
|
|
let mut player: usize = 0; |
|
|
|
let mut ais: [Option<Node>; 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<usize>, &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<u8>; 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; |
|
|
|
} |
|
|
@ -261,7 +409,7 @@ fn hands(state: &GameState) -> [Vec<u8>; 4] { |
|
|
|
} |
|
|
|
} */ |
|
|
|
|
|
|
|
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<u8>; 4]) -> (Vec<usize>, &'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<u8>; 4]) -> (Vec<usize>, &'a |
|
|
|
match &cur.outcomes[usize::from(*i)] { |
|
|
|
None => { |
|
|
|
seen.push((*i).into()); |
|
|
|
let mut new : Vec<u8> = 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<u8> = 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) => { |
|
|
@ -373,15 +521,15 @@ fn search<'a>(node: &'a mut Node, hands: &mut [Vec<u8>; 4]) -> (Vec<usize>, &'a |
|
|
|
Some(x) => { |
|
|
|
seen.push(idx); |
|
|
|
|
|
|
|
let mut new : Vec<u8> = vec![]; |
|
|
|
for i in &hands[usize::from(cur.state.player)] { |
|
|
|
if usize::from(*i) != idx { |
|
|
|
new.push(*i) |
|
|
|
} |
|
|
|
} |
|
|
|
let mut new: Vec<u8> = 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
|
|
|
|
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<usize>, 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::<u8>().expect("RIGHT") - 2; |
|
|
|
} |
|
|
|
Card { suit, rank } |
|
|
|
} |
|
|
|
|
|
|
|
fn simulate(state: &GameState, hands: &mut [Vec<u8>; 4]) -> i8 { |
|
|
|
let mut cur: GameState = state.clone(); |
|
|
|
loop { |
|
|
@ -445,15 +624,14 @@ fn simulate(state: &GameState, hands: &mut [Vec<u8>; 4]) -> i8 { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if random::<u8>() % n == 0 { |
|
|
|
|
|
|
|
p = numToCard(*i); |
|
|
|
let mut new : Vec<u8> = 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<u8> = 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<u8>; 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<usize>, &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); |
|
|
|