Skip to main content

Player

Enum Player 

Source
pub enum Player {
    Left,
    Right,
}

Variants§

§

Left

§

Right

Implementations§

Source§

impl Player

Source

pub fn opponent(self) -> Self

Examples found in repository?
crates/competitive/src/algorithm/game_analyzer/partisan.rs (line 307)
305    pub fn winning_moves(&mut self, state: &S, player: Player) -> Vec<Neighbor<S, L>> {
306        partisan_moves(&mut self.game.left, &mut self.game.right, state, player)
307            .filter(|next| !self.game.wins(&next.to, player.opponent(), MISERE))
308            .collect()
309    }
310}
311
312#[allow(clippy::type_complexity)] // Sum states and labels both carry component information.
313impl<S, L, FL, FR, IL, IR, V, const MISERE: bool, E>
314    GameAnalysis<'_, Partisan<S, FL, FR>, [S], V, MISERE, E>
315where
316    S: Clone,
317    FL: FnMut(&S) -> IL,
318    FR: FnMut(&S) -> IR,
319    IL: IntoIterator<Item = Neighbor<S, L>>,
320    IR: IntoIterator<Item = Neighbor<S, L>>,
321    E: FnMut(&mut Partisan<S, FL, FR>, &[S]) -> V,
322{
323    pub fn moves(
324        &mut self,
325        state: &[S],
326        player: Player,
327    ) -> Vec<EvaluatedMove<Vec<S>, (usize, L), V>> {
328        let mut result = Vec::new();
329        for (i, component) in state.iter().enumerate() {
330            for next in partisan_moves(&mut self.game.left, &mut self.game.right, component, player)
331            {
332                let mut to = state.to_vec();
333                to[i] = next.to;
334                let value = self.eval(&to);
335                result.push(EvaluatedMove {
336                    next: Neighbor::new(to, (i, next.label)),
337                    value,
338                });
339            }
340        }
341        result
342    }
343}
344#[allow(clippy::type_complexity)] // Sum states and labels both carry component information.
345impl<S, L, FL, FR, IL, IR, const MISERE: bool>
346    GameAnalysis<'_, Partisan<S, FL, FR>, [S], PartisanOutcome, MISERE>
347where
348    S: Clone + Eq + Hash,
349    FL: FnMut(&S) -> IL,
350    FR: FnMut(&S) -> IR,
351    IL: IntoIterator<Item = Neighbor<S, L>>,
352    IR: IntoIterator<Item = Neighbor<S, L>>,
353{
354    /// Whether the selected starting player can force a win.
355    pub fn wins(&mut self, state: &[S], player: Player) -> bool {
356        self.game.sum_wins(state, player, MISERE)
357    }
358
359    pub fn winning_moves(
360        &mut self,
361        state: &[S],
362        player: Player,
363    ) -> Vec<Neighbor<Vec<S>, (usize, L)>> {
364        let mut result = Vec::new();
365        for (i, component) in state.iter().enumerate() {
366            for next in partisan_moves(&mut self.game.left, &mut self.game.right, component, player)
367            {
368                let mut to = state.to_vec();
369                to[i] = next.to;
370                if !self.game.sum_wins(&to, player.opponent(), MISERE) {
371                    result.push(Neighbor::new(to, (i, next.label)));
372                }
373            }
374        }
375        result
376    }
377}
378
379impl<S, L, FL, FR, IL, IR> Partisan<S, FL, FR>
380where
381    S: Clone + Eq + Hash,
382    FL: FnMut(&S) -> IL,
383    FR: FnMut(&S) -> IR,
384    IL: IntoIterator<Item = Neighbor<S, L>>,
385    IR: IntoIterator<Item = Neighbor<S, L>>,
386{
387    fn value(&mut self, state: &S) -> GameValue {
388        memoized_game(
389            state,
390            &mut self.values,
391            &mut HashSet::new(),
392            &mut |s| {
393                let moves = (self.left)(s)
394                    .into_iter()
395                    .map(|n| (n.to, Player::Left))
396                    .chain((self.right)(s).into_iter().map(|n| (n.to, Player::Right)));
397                ControlFlow::Continue((moves, (Vec::new(), Vec::new())))
398            },
399            &mut |_, moves| moves.next(),
400            &mut |(left, right), player, value| {
401                if player == Player::Left {
402                    left.push(value)
403                } else {
404                    right.push(value)
405                }
406                ControlFlow::Continue(())
407            },
408            &mut |_, (left, right)| GameValue::from_options(left, right),
409        )
410    }
411
412    fn outcome(&mut self, state: &S, misere: bool) -> PartisanOutcome {
413        match (
414            self.wins(state, Player::Left, misere),
415            self.wins(state, Player::Right, misere),
416        ) {
417            (true, true) => PartisanOutcome::Next,
418            (false, false) => PartisanOutcome::Previous,
419            (true, false) => PartisanOutcome::Left,
420            (false, true) => PartisanOutcome::Right,
421        }
422    }
423
424    fn wins(&mut self, state: &S, player: Player, misere: bool) -> bool {
425        let key = (state.clone(), player);
426        memoized_wins(
427            &key,
428            &mut self.outcomes[usize::from(misere)],
429            |(s, p)| {
430                if !misere && let Some(value) = self.values.get(s) {
431                    return ControlFlow::Break(value.wins(*p));
432                }
433                let next_player = p.opponent();
434                let moves = partisan_moves(&mut self.left, &mut self.right, s, *p)
435                    .map(move |n| (n.to, next_player));
436                ControlFlow::Continue(moves)
437            },
438            |_, moves| moves.next(),
439            misere,
440        )
441    }
442
443    fn sum_wins(&mut self, state: &[S], player: Player, misere: bool) -> bool {
444        match state {
445            [] => return misere,
446            [single] => return self.wins(single, player, misere),
447            _ => {}
448        }
449        let mut normalize = |mut state: Vec<S>| {
450            if !misere {
451                state.retain(|s| {
452                    if let Some(value) = self.values.get(s) {
453                        return value.as_nimber() != Some(0);
454                    }
455                    let mut key = (s.clone(), Player::Left);
456                    if self.outcomes[0].get(&key) != Some(&false) {
457                        return true;
458                    }
459                    key.1 = Player::Right;
460                    self.outcomes[0].get(&key) != Some(&false)
461                });
462            }
463            canonical_sum(state, &mut self.sum_ids)
464        };
465        let state = normalize(state.to_vec());
466        match state.as_slice() {
467            [] => return misere,
468            [single] => return self.wins(single, player, misere),
469            _ => {}
470        }
471        let key = (state, player);
472        memoized_wins(
473            &key,
474            &mut self.sums[usize::from(misere)],
475            |(s, p)| {
476                if !misere
477                    && s.iter().all(|s| {
478                        self.values
479                            .get(s)
480                            .is_some_and(|g| g.as_switch_sum().is_some())
481                    })
482                {
483                    let value: GameValue = s.iter().map(|s| self.values[s].clone()).sum();
484                    return ControlFlow::Break(value.wins(*p));
485                }
486                // Losing as starter in every component implies losing in the sum.
487                // One known win is enough if the opponent loses in every other component.
488                if !misere && (!self.values.is_empty() || !self.outcomes[0].is_empty()) {
489                    let mut all_lose = true;
490                    let mut all_opponent_lose = true;
491                    let mut can_win = false;
492                    for s in s {
493                        let (mut win, mut opponent_win) = (None, None);
494                        if !self.outcomes[0].is_empty() {
495                            let mut key = (s.clone(), *p);
496                            win = self.outcomes[0].get(&key).copied();
497                            key.1 = p.opponent();
498                            opponent_win = self.outcomes[0].get(&key).copied();
499                        }
500                        if let Some(value) = self.values.get(s) {
501                            win.get_or_insert_with(|| value.wins(*p));
502                            opponent_win.get_or_insert_with(|| value.wins(p.opponent()));
503                        }
504                        can_win = can_win && opponent_win == Some(false)
505                            || all_opponent_lose && win == Some(true);
506                        all_lose &= win == Some(false);
507                        all_opponent_lose &= opponent_win == Some(false);
508                        if !all_lose && !all_opponent_lose && !can_win {
509                            break;
510                        }
511                    }
512                    if all_lose || can_win {
513                        return ControlFlow::Break(can_win);
514                    }
515                }
516                ControlFlow::Continue((0, None))
517            },
518            |(s, p), (i, moves)| {
519                while *i < s.len() {
520                    if *i != 0 && s[*i - 1] == s[*i] {
521                        *i += 1;
522                        continue;
523                    }
524                    let iterator = moves.get_or_insert_with(|| {
525                        partisan_moves(&mut self.left, &mut self.right, &s[*i], *p)
526                    });
527                    if let Some(next) = iterator.next() {
528                        let mut to = s.clone();
529                        to[*i] = next.to;
530                        return Some((normalize(to), p.opponent()));
531                    }
532                    *i += 1;
533                    *moves = None;
534                }
535                None
536            },
537            misere,
538        )
539    }
More examples
Hide additional examples
crates/competitive/src/algorithm/game_analyzer/value.rs (line 354)
237    fn from_options_memoized(
238        mut left: Vec<Self>,
239        mut right: Vec<Self>,
240        cache: &mut HashMap<GameValueNode, HashMap<GameValueNode, bool>>,
241    ) -> Self {
242        loop {
243            if left.iter().chain(&right).all(|g| g.as_number().is_some()) {
244                let l = left.iter().filter_map(Self::as_number).max();
245                let r = right.iter().filter_map(Self::as_number).min();
246                if let Some(n) = Dyadic::simplest_between(l, r) {
247                    return n.into();
248                }
249                let (l, r) = (l.unwrap(), r.unwrap());
250                if l == r {
251                    return Self::number_up_nimber(l, 0, 1);
252                }
253                let (sum, difference) = (l + r, l - r);
254                let temperature = Dyadic::new(difference.numerator(), difference.exponent() + 1);
255                return Self::from_switches(
256                    Dyadic::new(sum.numerator(), sum.exponent() + 1),
257                    0,
258                    0,
259                    vec![temperature],
260                    Self::temperature_hash(temperature),
261                );
262            }
263            if !right.is_empty()
264                && let Some((number, _)) = left.first().and_then(Self::as_number_nimber)
265            {
266                let nimber = |g: &Self| {
267                    g.as_number_nimber()
268                        .filter(|&(q, _)| q == number)
269                        .map(|(_, n)| n)
270                };
271                let l: Option<Vec<_>> = left.iter().map(nimber).collect();
272                let r: Option<Vec<_>> = right.iter().map(nimber).collect();
273                if let (Some(l), Some(r)) = (l, r) {
274                    let value = game_mex(l);
275                    if value == game_mex(r) {
276                        return Self::number_up_nimber(number, 0, value);
277                    }
278                }
279            }
280            for (moves, replies, sign) in [(&left, &right, 1), (&right, &left, -1)] {
281                if replies.len() != 1 {
282                    continue;
283                }
284                if let Some((q, k, n)) = replies[0].as_number_up_nimber() {
285                    if moves.len() == 1
286                        && moves[0].as_number() == Some(q)
287                        && (k == 0 || k.signum() == sign)
288                    {
289                        return Self::number_up_nimber(q, k + sign, n ^ 1);
290                    }
291                    if k == 0 && n == 0 && moves.len() == 2 {
292                        let a = moves[0].as_number_nimber();
293                        let b = moves[1].as_number_nimber();
294                        if (a == Some((q, 0)) && b == Some((q, 1)))
295                            || (a == Some((q, 1)) && b == Some((q, 0)))
296                        {
297                            return Self::number_up_nimber(q, sign, 1);
298                        }
299                    }
300                }
301            }
302            if left.len() == 1
303                && right.len() == 1
304                && let (Some((a, k, n, ts)), Some((b, l, m, us))) =
305                    (left[0].as_switch_sum(), right[0].as_switch_sum())
306                && k == l
307                && n == m
308                && ts == us
309                && a > b
310            {
311                let (sum, difference) = (a + b, a - b);
312                let temperature = Dyadic::new(difference.numerator(), difference.exponent() + 1);
313                if ts.first().is_none_or(|&t| temperature > t) {
314                    return Self::from_switches(
315                        Dyadic::new(sum.numerator(), sum.exponent() + 1),
316                        k,
317                        n,
318                        std::iter::once(temperature)
319                            .chain(ts.iter().copied())
320                            .collect(),
321                        Self::temperature_hash(temperature) ^ left[0].switch_hash(),
322                    );
323                }
324            }
325            let count = left.len() + right.len();
326            Self::remove_dominated(&mut left, Player::Left, cache);
327            Self::remove_dominated(&mut right, Player::Right, cache);
328            if count != left.len() + right.len() {
329                continue;
330            }
331            let options = Rc::new((left, right));
332            let game = Self(GameValueNode::Options(0.into(), options.clone()));
333            // Bypasses preserve the game, so all checks use the same candidate.
334            let mut reversible = Vec::new();
335            for player in [Player::Left, Player::Right] {
336                let moves = match player {
337                    Player::Left => &options.0,
338                    Player::Right => &options.1,
339                };
340                for (i, g) in moves.iter().enumerate() {
341                    if let Some((q, n)) = g.as_number_nimber()
342                        && n > 1
343                    {
344                        let number = Self::from(q);
345                        let (lower, upper) = match player {
346                            Player::Left => (&game, &number),
347                            Player::Right => (&number, &game),
348                        };
349                        // A strict inequality against q excludes every reply q + *m.
350                        if lower.leq_memoized(upper, cache) && !upper.leq_memoized(lower, cache) {
351                            continue;
352                        }
353                    }
354                    if let Some(reply) = g.options(player.opponent()).find(|r| match player {
355                        Player::Left => r.leq_memoized(&game, cache),
356                        Player::Right => game.leq_memoized(r, cache),
357                    }) {
358                        reversible.push((player, i, reply));
359                    }
360                }
361            }
362            if reversible.is_empty() {
363                return game;
364            }
365            drop(game);
366            (left, right) = Rc::unwrap_or_clone(options);
367            for (player, i, reply) in reversible.into_iter().rev() {
368                let moves = if player == Player::Left {
369                    &mut left
370                } else {
371                    &mut right
372                };
373                moves.remove(i);
374                moves.extend(reply.options(player));
375            }
376        }
377    }

Trait Implementations§

Source§

impl Clone for Player

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Player

Source§

impl Debug for Player

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Player

Source§

impl Hash for Player

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Player

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Player

Auto Trait Implementations§

§

impl Forget for Player

§

impl Freeze for Player

§

impl Move for Player

§

impl RefUnwindSafe for Player

§

impl Send for Player

§

impl Sync for Player

§

impl Unpin for Player

§

impl UnsafeUnpin for Player

§

impl UnwindSafe for Player

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToArrayVecScalar for T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.