pub enum Player {
Left,
Right,
}Variants§
Implementations§
Source§impl Player
impl Player
Sourcepub fn opponent(self) -> Self
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
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§
impl Copy for Player
impl Eq for Player
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more