open_pql/vm/
mod.rs

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