competitive/algorithm/
partisan_game.rs1use std::{collections::HashMap, hash::Hash, marker::PhantomData};
2
3type Marker<T> = PhantomData<fn() -> T>;
4
5pub trait PartisanGame {
6 type State;
7 type LIter: Iterator<Item = Self::State>;
8 type RIter: Iterator<Item = Self::State>;
9 fn next_left(&mut self, s: &Self::State) -> Self::LIter;
10 fn next_right(&mut self, s: &Self::State) -> Self::RIter;
11}
12
13pub struct PartisanGamer<S, F, G, L, R>
14where
15 F: FnMut(&S) -> L,
16 L: Iterator<Item = S>,
17 G: FnMut(&S) -> R,
18 R: Iterator<Item = S>,
19{
20 f: F,
21 g: G,
22 _marker: Marker<(S, L, R)>,
23}
24
25impl<S, F, G, L, R> PartisanGamer<S, F, G, L, R>
26where
27 F: FnMut(&S) -> L,
28 L: Iterator<Item = S>,
29 G: FnMut(&S) -> R,
30 R: Iterator<Item = S>,
31{
32 pub fn new(f: F, g: G) -> Self {
33 Self {
34 f,
35 g,
36 _marker: PhantomData,
37 }
38 }
39}
40
41impl<S, F, G, L, R> PartisanGame for PartisanGamer<S, F, G, L, R>
42where
43 F: FnMut(&S) -> L,
44 L: Iterator<Item = S>,
45 G: FnMut(&S) -> R,
46 R: Iterator<Item = S>,
47{
48 type State = S;
49 type LIter = L;
50 type RIter = R;
51 fn next_left(&mut self, s: &Self::State) -> Self::LIter {
52 (self.f)(s)
53 }
54 fn next_right(&mut self, s: &Self::State) -> Self::RIter {
55 (self.g)(s)
56 }
57}
58
59#[derive(Debug, Clone)]
60pub struct PartisanGameAnalyzer<G>
61where
62 G: PartisanGame<State: Eq + Hash>,
63{
64 game: G,
65 number: HashMap<G::State, i64>,
66}
67
68impl<G> PartisanGameAnalyzer<G>
69where
70 G: PartisanGame<State: Eq + Hash + Clone>,
71{
72 pub fn new(game: G) -> Self {
73 Self {
74 game,
75 number: Default::default(),
76 }
77 }
78 pub fn eval(&mut self, s: &G::State) -> i64 {
79 if let Some(n) = self.number.get(s).cloned() {
80 n
81 } else {
82 let lmax = self
83 .game
84 .next_left(s)
85 .map(|ns| self.eval(&ns))
86 .fold(i64::MIN, Ord::max);
87 let rmin = self
88 .game
89 .next_right(s)
90 .map(|ns| self.eval(&ns))
91 .fold(i64::MAX, Ord::min);
92 let res = Self::simple_number(lmax, rmin);
93 self.number.insert(s.clone(), res);
94 res
95 }
96 }
97 fn simple_number(lmax: i64, rmin: i64) -> i64 {
98 const FIX: u32 = 50;
99 assert!(lmax < rmin);
100 assert!(lmax + 1 != rmin);
101 if lmax < 0 && 0 < rmin {
102 0
103 } else {
104 let c = 63 - ((rmin - 1) ^ lmax).leading_zeros();
105 if c <= FIX {
106 (rmin - 1) >> c << c
107 } else if lmax >= 0 {
108 ((lmax >> FIX) + 1) << FIX
109 } else {
110 (rmin - 1) >> FIX << FIX
111 }
112 }
113 }
114}