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}