diff --git a/src/bak_kinda.src b/src/bak_kinda.src deleted file mode 100644 index 2ae4b66..0000000 --- a/src/bak_kinda.src +++ /dev/null @@ -1,514 +0,0 @@ -#![allow(non_snake_case)] - -use bitvec::prelude::*; -use rand::prelude::*; -use std::cmp::max; -use std::io; - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -enum Suit { - Spades, - Hearts, - Diamonds, - Clubs, -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct Card { - suit: Suit, - rank: u8, // 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A <- 2 is 0, ... A is 12 -} - -#[derive(Debug, Clone)] -struct GameState { - player: u8, - handPlayer: u8, - trump: Option, - hand: [Option; 13], // hand of handPlayer - ruffs: bitarr!(for 16), - played: bitarr!(for 52), - trick: [Option; 3], - tricksWonBy0: u8, - sizes: [u8; 4], -} - -#[derive(Debug, Clone)] -struct Node { - visited: u64, - value: i64, - state: GameState, - outcomes: [Option>; 52], -} -fn rankOf(c: Card) -> u8 { - c.rank -} -fn suitOf(c: Card) -> Suit { - c.suit -} -fn toSuit(n: u8) -> Suit { - match n { - 0 => Suit::Spades, - 1 => Suit::Hearts, - 2 => Suit::Diamonds, - 3 => Suit::Clubs, - _ => panic!("ERR in toSuit - it was given too big a number. We don't use 'fairy suits' in Whist, you goddamn idiot!"), - } -} - -fn fromSuit(s: Suit) -> u8 { - match s { - Suit::Spades => 0, - Suit::Hearts => 1, - Suit::Diamonds => 2, - Suit::Clubs => 3, - } -} - -fn numToCard(num: u8) -> Card { - // this assumes the number is legal. - let rank: u8 = num % 13; - let suit: Suit = toSuit(num / 13); - Card { suit, rank } -} - -fn cardToNum(card: Card) -> u8 { - // this assumes card rank is legal. - let suitN: u8 = fromSuit(suitOf(card)); - suitN * 13 + rankOf(card) -} - -fn state_transit(state: &GameState, action: Card) -> GameState { - // this assumes the action is legal. Please don't do illegal action? - let hand: [Option; 13] = if state.player == state.handPlayer { - let mut new: [Option; 13] = state.hand; - for item in &mut new { - // this assumes action is in hand - if let Some(x) = item { - if *x == action { - *item = None; - } - } - } - new - } else { - state.hand - }; - - let mut played: bitarr!(for 52) = state.played; - played.set(cardToNum(action).into(), true); - - let ruffs: bitarr!(for 16) = match state.trick[0] { - Some(firstCard) => { - if suitOf(action) != suitOf(firstCard) { - let mut new: bitarr!(for 16) = state.ruffs; - new.set( - (state.player * 4 + fromSuit(suitOf(firstCard))).into(), - true, - ); - new - } else { - state.ruffs - } - } - None => state.ruffs, - }; - - if state.trick[2] != None { - // Ok, new trick after this. - - let firstCard: Card = state.trick[0].unwrap(); //this assumes that tricks is sane - let mut maxRank: u8 = rankOf(action); - let mut trumped: bool = Some(suitOf(action)) == state.trump; - let mut winner: u8 = state.player; - for (i, card) in state.trick.iter().enumerate() { - match card { - Some(x) => { - if (suitOf(*x) == suitOf(firstCard) && !trumped && rankOf(*x) > maxRank) - || (Some(suitOf(*x)) == state.trump && (!trumped || rankOf(*x) > maxRank)) - { - maxRank = rankOf(*x); - winner = (8 + i as u8 - (3 - state.player)) % 4; - if Some(suitOf(*x)) == state.trump { - trumped = true; - } - } - } - None => (), - } - } - let newWon: u8 = state.tricksWonBy0 + if winner == 0 || winner == 2 { 1 } else { 0 }; - let mut sizes = state.sizes; - sizes[usize::from(state.player)] -= 1; - GameState { - player: winner, - handPlayer: state.handPlayer, - trump: state.trump, - hand, - ruffs, - played, - trick: [None, None, None], - tricksWonBy0: newWon, - sizes, - } - } else { - let mut trick: [Option; 3] = state.trick; - for i in 0..3 { - if trick[i] == None { - trick[i] = Some(action); - break; - } - } - let mut sizes = state.sizes; - sizes[usize::from(state.player)] -= 1; - GameState { - player: (state.player + 1) % 4, - handPlayer: state.handPlayer, - trump: state.trump, - hand, - ruffs, - played, - trick, - tricksWonBy0: state.tricksWonBy0, - sizes, - } - } -} - -fn card(suit: Suit, rank: u8) -> Card { - Card { suit, rank } -} - -fn new_node(state: GameState) -> Node { - Node { - visited: 0, - value: 0, - state, - outcomes: [ - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, None, None, - ], - } -} - -fn hands(state: &GameState) -> [[Option; 13]; 4] { - let mut hand: [[Option; 13] 4] = [vec![], vec![], vec![], vec![]]; - let mut seen = state.played; - for i in state.hand.iter() { - match i { - None => (), - Some(x) => { - hand[usize::from(state.handPlayer)].push(cardToNum(*x)); - seen.set(cardToNum(*x).into(), true); - } - } - } - let mut sizes = state.sizes; - let mut allowed: [[bool; 4]; 52] = [[true, true, true, true]; 52]; - let mut n_to_assign = 52 - seen.count_ones(); - let mut n_assignable_to = [0, 0, 0, 0]; - for i in 0..52 { - if seen[i] { - continue; - } - allowed[i][usize::from(state.handPlayer)] = false; - for j in 0..4 { - if state.ruffs[j * 4 + i / 13] == true { - allowed[i][j] = false; - } - } - let mut n = 0; - let mut last = 0; - for j in 0..4 { - if allowed[i][j] { - n += 1; - last = j; - n_assignable_to[j] += 1; - } - } - if n == 1 { - hand[last].push(i as u8); - n_to_assign -= 1; - n_assignable_to[last] -= 1; - sizes[last] -= 1; - seen.set(i, true); - } - } - let mut running = 0; - while n_to_assign > 0 { - let mut any_done = false; - for i in 0..4 { - if sizes[i] > 0 && n_assignable_to[i] == sizes[i] { - for j in 0..52 { - if allowed[j][i] && !seen[j] { - seen.set(j, true); - hand[i].push(j as u8); - sizes[i] -= 1; - n_to_assign -= 1; - for q in 0..4 { - if allowed[j][q] { - n_assignable_to[q] -= 1; - } - } - } - } - any_done = true; - } - } - if any_done { - continue; - } - while seen[running] { - running += 1; - } - let mut n: usize = allowed[running] - .iter() - .map(|&x| if x { 1 } else { 0 }) - .sum(); - for j in 0..4 { - if sizes[j] == 0 && allowed[running][j] == true { - n -= 1; - } - } - - for j in 0..4 { - if !allowed[running][j] || sizes[j] == 0 { - continue; - } - if random::() % n == 0 { - hand[j].push(running as u8); - for i in 0..4 { - if allowed[running][i] { - n_assignable_to[i] -= 1; - } - } - sizes[j] -= 1; - n_to_assign -= 1; - break; - } else { - n -= 1; - } - } - seen.set(running, true); - } - hand -} - -fn search(node: &mut Node) -> (Vec, &mut Node) { - let mut cur: &mut Node = node; - let mut seen: Vec = vec![]; - loop { - cur.visited += 1; - if cur.state.played.count_ones() == 52 { - // abort - return (seen, cur); - } - let mut score: f64 = -10000.0; - let mut idx: usize = 100000; - let hands = hands(&cur.state); - let mut outin: [bool; 4] = [true; 4]; - for i in hands[usize::from(cur.state.player)].iter() { - outin[usize::from(i / 13)] = false; - } - for i in hands[usize::from(cur.state.player)].iter() { - match cur.state.trick[0] { - None => (), - Some(x) => { - if !(fromSuit(suitOf(x)) == i / 13) - && !(outin[usize::from(fromSuit(suitOf(x)))]) - { - continue; - } - } - } - match &cur.outcomes[usize::from(*i)] { - None => { - seen.push((*i).into()); - return (seen, cur); - } - Some(x) => { - let ourscore: f64 = (x.value as f64 / (x.visited as f64 + 1.0)) - + 6.0 * ((cur.visited as f64).ln() / (x.visited as f64 + 1.0)).sqrt(); - if ourscore > score { - idx = (*i).into(); - score = ourscore; - } - } - } - } - match &mut cur.outcomes[idx] { - None => panic!("This will not happen. SEARCH PANIC KW!#"), - Some(x) => { - seen.push(idx); - cur = x; - } - } - //cur.outcomes[idx].clone().unwrap(); - //cur = *(cur.outcomes[idx].unwrap()); - } -} - -fn propagate(node: &mut Node, path: Vec, value: i8) { - let mut cur: &mut Node = node; - let mut sgn = -1; - for i in path { - cur.value += sgn * i64::from(value); - sgn = -sgn; - match &mut cur.outcomes[i] { - None => panic!("This will not happen. SEARCH PANIC KQ!#"), - Some(x) => { - cur = x; - } - } - } -} -fn simulate(state: &GameState) -> i8 { - let mut cur: GameState = state.clone(); - loop { - let tricks0: u8 = cur.tricksWonBy0; - if cur.played.count_ones() == 52 { - if cur.handPlayer == 0 || cur.handPlayer == 2 { - return max(tricks0 as i8 - 6, 0) - max(7 - tricks0 as i8, 0); - } else { - return max(7 - tricks0 as i8, 0) - max(tricks0 as i8 - 6, 0); - } - } - let card: Card; - // ok. find action - let hands = hands(&cur); - - let mut outin: [u8; 4] = [0; 4]; - for i in hands[usize::from(cur.player)].iter() { - outin[usize::from(i / 13)] += 1; - } - // i fucked up my life on this one - let mut n: u8 = cur.sizes[usize::from(cur.player)]; - let mut follow: bool = false; - let mut led: u8 = 100; - match cur.trick[0] { - None => (), - Some(x) => { - if outin[usize::from(fromSuit(suitOf(x)))] > 0 { - n = outin[usize::from(fromSuit(suitOf(x)))]; - led = fromSuit(suitOf(x)); - follow = true; - } - } - } - let mut p: Card = Card { - suit: Suit::Diamonds, - rank: 105, - }; // see this, something has gone terribly wrong. - for i in hands[usize::from(cur.player)].iter() { - if follow && led != i / 13 { - continue; - } - if random::() % n == 0 { - p = numToCard(*i); - break; - } else { - n -= 1; - } - } - - card = p; - cur = state_transit(&cur, card); - } -} - -fn main() { - 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::Diamonds, 2)), - Some(card(Suit::Clubs, 1)), - Some(card(Suit::Clubs, 3)), - Some(card(Suit::Clubs, 7)), - ], - ruffs: bitarr!(0; 16), - played, - trick: [ - Some(card(Suit::Spades, 12)), - Some(card(Suit::Spades, 1)), - Some(card(Suit::Spades, 0)), - ], - tricksWonBy0: 0, - sizes: [13, 12, 12, 12], - }); - 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!"); - match &node.outcomes[card] { - None => { - node = new_node(state_transit(&node.state, numToCard(card as u8))); - } - Some(x) => { - node = (**x).clone(); - } - } - continue; - } - for _ in 1..10000 { - let pathcur: (Vec, &mut Node) = search(&mut node); //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); - //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; - } - } - } - } - println!("{:?}", numToCard(best_move as u8)); - break; - match &node.outcomes[best_move] { - None => panic!("ok"), - Some(x) => { - node = (**x).clone(); - } - } - } -}