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}