open_pql/vm/
mod.rs

1use std::{cmp::Ordering, collections::VecDeque, ops::*};
2
3use derive_more::derive::{Display, From, TryInto};
4
5use crate::{
6    Board, Card, Flop, FlopHandCategory, Hand, HandType, InternalError,
7    LocInfo, PQLBoardRange, PQLBoolean, PQLCard, PQLCardCount, PQLDouble,
8    PQLGame, PQLHiRating, PQLInteger, PQLLong, PQLPlayer, PQLRange, PQLRank,
9    PQLRankSet, PQLStreet, PQLString, PQLType, TypeError,
10    error::PQLError,
11    functions::PQLFn,
12    pql_parser::ast::{self, Selector},
13    *,
14};
15
16mod bin_op;
17mod buffer;
18pub mod instruction;
19mod push_expr;
20mod push_fncall;
21mod push_ident;
22mod push_num;
23mod push_selector;
24mod push_str;
25mod rng;
26mod stack;
27mod stack_value;
28mod stack_value_num;
29mod store;
30mod store_var_idx;
31mod value;
32
33use bin_op::*;
34pub(crate) use buffer::*;
35pub use instruction::VmInstruction;
36use push_expr::push_expr;
37use push_selector::push_selector;
38pub use rng::*;
39pub use stack::VmStack;
40pub use stack_value::*;
41pub use stack_value_num::VmStackValueNum;
42pub use store::VmStore;
43pub use store_var_idx::*;
44pub use value::*;
45
46pub type VmInstructions = Vec<VmInstruction>;
47
48#[derive(Debug, Clone, Default)]
49pub struct Vm {
50    pub(crate) board_range: PQLRange,
51    pub(crate) player_ranges: Vec<PQLRange>,
52    pub(crate) instructions: VmInstructions,
53    pub(crate) store: VmStore,
54    pub(crate) buffer: VmBuffer,
55    pub(crate) stack: VmStack,
56    pub(crate) rng: Rng,
57    pub n_trials: usize,
58    pub n_failed: usize,
59}
60
61impl Vm {
62    fn sample_next_frame(&mut self) -> Option<()> {
63        self.rng.reset();
64
65        for (i, range) in self.player_ranges.iter_mut().enumerate() {
66            self.rng.deal(range)?;
67
68            self.buffer.player_hands[i].clone_from(&self.rng.mem);
69        }
70
71        self.rng.deal(&mut self.board_range)?;
72
73        let cards = &self.rng.mem;
74        self.buffer.board = Board::from_slice(&cards[..5]);
75
76        Some(())
77    }
78
79    fn compute(&mut self) -> Result<(), PQLError> {
80        let stack = &mut self.stack;
81
82        for ins in &self.instructions {
83            ins.execute(&mut self.buffer, &mut self.store, stack)?;
84        }
85
86        Ok(())
87    }
88
89    pub fn try_run(mut self) -> Result<Self, PQLError> {
90        let mut n = self.n_trials;
91
92        while n > 0 && self.n_failed < self.n_trials {
93            if self.sample_next_frame() == Some(()) {
94                self.compute()?;
95
96                n -= 1;
97            } else {
98                self.n_failed += 1;
99            }
100        }
101
102        Ok(self)
103    }
104}
105
106#[derive(Debug, Clone, Default)]
107struct InitDeps<'init, 'input> {
108    pub game: PQLGame,
109    pub player_names: &'init [&'input str],
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    use crate::*;
116
117    impl Vm {
118        pub fn new_test_vm() -> Self {
119            let mut buffer = VmBuffer::default();
120            buffer.player_hands.push(Vec::new());
121
122            Self {
123                board_range: PQLBoardRange::default().into(),
124                player_ranges: [PQLRange::default()].into(),
125                instructions: [].into(),
126                store: VmStore::default(),
127                buffer,
128                stack: VmStack::default(),
129                rng: Rng::default(),
130                n_trials: 1,
131                n_failed: 0,
132            }
133        }
134    }
135
136    fn create_vm_shortdeck_cards() -> Vm {
137        let mut vm = Vm::new_test_vm();
138
139        vm.rng = Rng::new(Card::ARR_ALL_SHORT.into());
140
141        vm
142    }
143
144    #[test]
145    fn test_sample_next_frame() {
146        fastrand::seed(0);
147
148        let mut vm = create_vm_shortdeck_cards();
149
150        let g = (&vm.buffer).into();
151
152        vm.sample_next_frame().unwrap();
153        assert_eq!(Some(flop!("6d6c8d")), vm.buffer.board.flop);
154
155        vm.board_range = PQLBoardRange::from_src("222").unwrap().into();
156        assert!(vm.sample_next_frame().is_none());
157
158        vm.player_ranges[0] = PQLRange::from_src("22", g).unwrap();
159        assert!(vm.sample_next_frame().is_none());
160    }
161
162    #[test]
163    fn test_sample_try_run() {
164        fastrand::seed(0);
165
166        let mut vm = create_vm_shortdeck_cards();
167
168        vm.instructions =
169            vec![VmInstruction::Call(&(functions::turn_card as fn(_) -> _))];
170
171        let mut vm = vm.try_run().unwrap();
172
173        assert_eq!(card!("8h"), vm.stack.downcast_pop::<PQLCard>().unwrap());
174    }
175
176    #[test]
177    fn test_sample_try_run_error() {
178        let mut vm = create_vm_shortdeck_cards();
179        let g = (&vm.buffer).into();
180
181        vm.player_ranges[0] = PQLRange::from_src("22", g).unwrap();
182
183        let vm = vm.try_run().unwrap();
184        assert_eq!(vm.n_failed, vm.n_trials);
185
186        let mut vm = create_vm_shortdeck_cards();
187        vm.store.try_push(PQLString::from("").into()).unwrap();
188        vm.instructions = vec![
189            VmStackValue::from(VmStoreVarIdx::from(0)).into(),
190            VmInstruction::Call(&(functions::rate_hi_hand as fn(&_, _) -> _)),
191        ];
192        assert!(vm.try_run().is_err());
193    }
194}