brutus tweaks

master
Mark 2024-03-06 10:38:02 -08:00
parent 00270569db
commit 786e70fe9a
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
1 changed files with 27 additions and 8 deletions

View File

@ -2,6 +2,7 @@ use std::{cmp::Ordering, iter};
use anyhow::Result; use anyhow::Result;
use itertools::Itertools; use itertools::Itertools;
use rand::{seq::SliceRandom, thread_rng};
use rayon::iter::{ParallelBridge, ParallelIterator}; use rayon::iter::{ParallelBridge, ParallelIterator};
use super::{Agent, Chase, MaximizerAgent, MinimizerAgent}; use super::{Agent, Chase, MaximizerAgent, MinimizerAgent};
@ -27,14 +28,20 @@ impl Brutus {
.collect_vec(); .collect_vec();
if symbols.is_empty() { if symbols.is_empty() {
return Chase::new(self.player).step_max(board); return if minimize {
Chase::new(self.player).step_min(board)
} else {
Chase::new(self.player).step_max(board)
};
} }
// Number of free slots // Number of free slots
let n_free = board.get_board().iter().filter(|x| x.is_none()).count(); let n_free = board.get_board().iter().filter(|x| x.is_none()).count();
// Number of slots we need to fill with numbers // Number of slots we need to fill with numbers
let n_fill = n_free - symbols.len(); // Add one if we have two or fewer symbols available, so that we can
// account for one unused symbol while keeping a reasonable runtime
let n_fill = n_free - symbols.len() + if symbols.len() <= 2 { 1 } else { 0 };
let mut items = iter::repeat(None) let mut items = iter::repeat(None)
.take(n_fill) .take(n_fill)
@ -70,7 +77,7 @@ impl Brutus {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if minimize { if minimize {
// Sort from smallest midpoint to biggest midpoint // Sort from smallest to biggest midpoint
items.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal)); items.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal));
} else { } else {
items.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal)); items.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
@ -88,15 +95,27 @@ impl Brutus {
let (t, _) = items.first().unwrap(); let (t, _) = items.first().unwrap();
for (i, s) in t.get_board().iter().enumerate() { let mut symbols = symbols.clone();
if let Some(s) = s { symbols.shuffle(&mut thread_rng());
if s.is_op() && board.get_board()[i].is_none() {
return Ok(PlayerAction { pos: i, symb: *s }); // Place a random unused symbol
for target_s in symbols {
for (i, s) in t.get_board().iter().enumerate() {
if let Some(s) = s {
if board.get_board()[i].is_none() && target_s == *s {
return Ok(PlayerAction { pos: i, symb: *s });
}
} }
} }
} }
unreachable!() // Final escape hatch, if we didn't decide to place any symbols
// (which is possible, since we add one to free_spots above!)
if minimize {
Chase::new(self.player).step_min(board)
} else {
Chase::new(self.player).step_max(board)
}
} }
} }