-
Notifications
You must be signed in to change notification settings - Fork 99
/
Copy pathnode_locking.rs
93 lines (77 loc) · 3.42 KB
/
node_locking.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use postflop_solver::*;
fn main() {
normal_node_locking();
partial_node_locking();
}
fn normal_node_locking() {
let card_config = CardConfig {
range: ["AsAh,QsQh".parse().unwrap(), "KsKh".parse().unwrap()],
flop: flop_from_str("2s3h4d").unwrap(),
turn: card_from_str("6c").unwrap(),
river: card_from_str("7c").unwrap(),
};
let tree_config = TreeConfig {
initial_state: BoardState::River,
starting_pot: 20,
effective_stack: 10,
river_bet_sizes: [("a", "").try_into().unwrap(), ("a", "").try_into().unwrap()],
..Default::default()
};
let action_tree = ActionTree::new(tree_config).unwrap();
let mut game = PostFlopGame::with_config(card_config, action_tree).unwrap();
game.allocate_memory(false);
// node locking must be performed after allocating memory and before solving
game.play(1); // OOP all-in
game.lock_current_strategy(&[0.25, 0.75]); // lock IP's strategy: 25% fold, 75% call
game.back_to_root();
solve(&mut game, 1000, 0.001, false);
game.cache_normalized_weights();
// check OOP's strategy
let strategy_oop = game.strategy();
assert!((strategy_oop[0] - 1.0).abs() < 1e-3); // QQ always check
assert!((strategy_oop[1] - 0.0).abs() < 1e-3); // AA never check
assert!((strategy_oop[2] - 0.0).abs() < 1e-3); // QQ never all-in
assert!((strategy_oop[3] - 1.0).abs() < 1e-3); // AA always all-in
game.allocate_memory(false);
game.play(1);
game.lock_current_strategy(&[0.5, 0.5]); // lock IP's strategy: 50% fold, 50% call
game.back_to_root();
solve(&mut game, 1000, 0.001, false);
game.cache_normalized_weights();
// check OOP's strategy
let strategy_oop = game.strategy();
assert!((strategy_oop[0] - 0.0).abs() < 1e-3); // QQ never check
assert!((strategy_oop[1] - 0.0).abs() < 1e-3); // AA never check
assert!((strategy_oop[2] - 1.0).abs() < 1e-3); // QQ always bet
assert!((strategy_oop[3] - 1.0).abs() < 1e-3); // AA always bet
}
fn partial_node_locking() {
let card_config = CardConfig {
range: ["AsAh,QsQh,JsJh".parse().unwrap(), "KsKh".parse().unwrap()],
flop: flop_from_str("2s3h4d").unwrap(),
turn: card_from_str("6c").unwrap(),
river: card_from_str("7c").unwrap(),
};
let tree_config = TreeConfig {
initial_state: BoardState::River,
starting_pot: 10,
effective_stack: 10,
river_bet_sizes: [("a", "").try_into().unwrap(), ("a", "").try_into().unwrap()],
..Default::default()
};
let action_tree = ActionTree::new(tree_config).unwrap();
let mut game = PostFlopGame::with_config(card_config, action_tree).unwrap();
game.allocate_memory(false);
// lock OOP's strategy: only JJ is locked and the rest is not
game.lock_current_strategy(&[0.8, 0.0, 0.0, 0.2, 0.0, 0.0]); // JJ: 80% check, 20% all-in
solve(&mut game, 1000, 0.001, false);
game.cache_normalized_weights();
// check OOP's strategy
let strategy_oop = game.strategy();
assert!((strategy_oop[0] - 0.8).abs() < 1e-3); // JJ check 80% (locked)
assert!((strategy_oop[1] - 0.7).abs() < 1e-3); // QQ check 70%
assert!((strategy_oop[2] - 0.0).abs() < 1e-3); // AA never check
assert!((strategy_oop[3] - 0.2).abs() < 1e-3); // JJ bet 20% (locked)
assert!((strategy_oop[4] - 0.3).abs() < 1e-3); // QQ bet 30%
assert!((strategy_oop[5] - 1.0).abs() < 1e-3); // AA always bet
}