Ethan du Toit 1 year ago
parent
commit
de2c0557d1
  1. 281
      src/main.rs

281
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<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);

Loading…
Cancel
Save