Added diffuse agent
parent
2d7432c228
commit
a5e3998727
|
@ -0,0 +1,105 @@
|
|||
use super::PlayerAgent;
|
||||
use crate::util::Symb;
|
||||
use rand::Rng;
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
/// A simple "operator diffusion" MINIMIZER agent.
|
||||
///
|
||||
/// Tries to keep operators as far apart as possible, denying large numbers.
|
||||
pub struct DiffuseAgent {}
|
||||
|
||||
impl DiffuseAgent {
|
||||
/// Place a symbol on the board.
|
||||
/// Assumes `symb` is not already on the board
|
||||
fn step_symb(&self, board: &mut crate::board::Board, symb: Symb) {
|
||||
if board.contains(symb) {
|
||||
panic!("Called `step_symb` with a symbol that's already on the board!")
|
||||
}
|
||||
|
||||
// Fill distance array with largest possible value
|
||||
let mut dist = [board.size() + 1; 11];
|
||||
|
||||
// Set up initial distances
|
||||
dist[0] = 1;
|
||||
*dist.last_mut().unwrap() = 1;
|
||||
for (i, o) in board.iter().enumerate() {
|
||||
if let Some((s, _)) = o {
|
||||
if s.is_op() {
|
||||
dist[i] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut did_something = true;
|
||||
while did_something {
|
||||
did_something = false;
|
||||
for i in 1..(dist.len() - 1) {
|
||||
let l = dist[i - 1];
|
||||
let r = dist[i + 1];
|
||||
|
||||
let new = (l + 1).min(r + 1);
|
||||
if new < dist[i] {
|
||||
did_something = true;
|
||||
dist[i] = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut max_dist = *dist.iter().max().unwrap();
|
||||
println!("{:?}", dist);
|
||||
|
||||
'outer: loop {
|
||||
for i in 0..11 {
|
||||
if dist[i] >= max_dist {
|
||||
if board.play(i, symb) {
|
||||
break 'outer;
|
||||
};
|
||||
}
|
||||
}
|
||||
max_dist -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when we're out of symbols
|
||||
fn step_number(&self, board: &mut crate::board::Board) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let n = board.size();
|
||||
|
||||
let mut c = rng.gen_range(0..n);
|
||||
let mut s = {
|
||||
let n = rng.gen_range(0..=9);
|
||||
if n == 0 {
|
||||
Symb::Zero
|
||||
} else {
|
||||
Symb::Number(NonZeroU8::new(n).unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
while !board.play(c, s) {
|
||||
c = rng.gen_range(0..n);
|
||||
s = {
|
||||
let n = rng.gen_range(0..=9);
|
||||
if n == 0 {
|
||||
Symb::Zero
|
||||
} else {
|
||||
Symb::Number(NonZeroU8::new(n).unwrap())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerAgent for DiffuseAgent {
|
||||
fn step(&mut self, board: &mut crate::board::Board) {
|
||||
let symb = [Symb::Minus, Symb::Times, Symb::Plus, Symb::Div]
|
||||
.iter()
|
||||
.filter(|x| !board.contains(**x))
|
||||
.next();
|
||||
|
||||
// No symbols available, play a random number
|
||||
if symb.is_none() {
|
||||
self.step_number(board)
|
||||
} else {
|
||||
self.step_symb(board, *symb.unwrap())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
mod diffuse;
|
||||
mod random;
|
||||
|
||||
pub use diffuse::DiffuseAgent;
|
||||
pub use random::RandomAgent;
|
||||
|
||||
use crate::board::Board;
|
||||
|
||||
pub trait PlayerAgent {
|
||||
fn step(&mut self, board: &mut Board);
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
use std::num::NonZeroU8;
|
||||
|
||||
use super::PlayerAgent;
|
||||
use crate::util::Symb;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{util::Symb, PlayerAgent};
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
pub struct RandomAgent {}
|
||||
|
23
src/main.rs
23
src/main.rs
|
@ -11,22 +11,16 @@ use termion::{
|
|||
raw::IntoRawMode,
|
||||
};
|
||||
|
||||
mod agents;
|
||||
mod board;
|
||||
mod random;
|
||||
mod util;
|
||||
use board::Board;
|
||||
use util::{Player, Symb};
|
||||
|
||||
use crate::random::RandomAgent;
|
||||
|
||||
pub trait PlayerAgent {
|
||||
fn step(&mut self, board: &mut Board);
|
||||
}
|
||||
|
||||
fn play(
|
||||
stdout: &mut StdoutLock,
|
||||
player_max: bool,
|
||||
computer: &mut dyn PlayerAgent,
|
||||
computer: &mut dyn agents::PlayerAgent,
|
||||
) -> Result<Board> {
|
||||
let mut cursor = 0usize;
|
||||
let cursor_offset = 10usize - 1;
|
||||
|
@ -88,6 +82,7 @@ fn play(
|
|||
break;
|
||||
}
|
||||
|
||||
// Player turn
|
||||
let stdin = stdin();
|
||||
for c in stdin.keys() {
|
||||
print_board = match c.unwrap() {
|
||||
|
@ -112,10 +107,10 @@ fn play(
|
|||
Key::Char('8') => board.play(cursor, Symb::Number(NonZeroU8::new(8).unwrap())),
|
||||
Key::Char('9') => board.play(cursor, Symb::Number(NonZeroU8::new(9).unwrap())),
|
||||
Key::Char('0') => board.play(cursor, Symb::Zero),
|
||||
Key::Char('a') => board.play(cursor, Symb::Plus),
|
||||
Key::Char('s') => board.play(cursor, Symb::Minus),
|
||||
Key::Char('m') => board.play(cursor, Symb::Times),
|
||||
Key::Char('d') => board.play(cursor, Symb::Div),
|
||||
Key::Char('+') => board.play(cursor, Symb::Plus),
|
||||
Key::Char('-') => board.play(cursor, Symb::Minus),
|
||||
Key::Char('*') => board.play(cursor, Symb::Times),
|
||||
Key::Char('/') => board.play(cursor, Symb::Div),
|
||||
_ => false,
|
||||
};
|
||||
continue 'outer;
|
||||
|
@ -129,7 +124,7 @@ fn main() -> Result<()> {
|
|||
let stdout = HideCursor::from(stdout().into_raw_mode().unwrap());
|
||||
let mut stdout = stdout.lock();
|
||||
|
||||
let mut agent = RandomAgent {};
|
||||
let mut agent = agents::DiffuseAgent {};
|
||||
let a = play(&mut stdout, true, &mut agent)?;
|
||||
if a.is_done() {
|
||||
println!(
|
||||
|
@ -147,7 +142,7 @@ fn main() -> Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let mut agent = RandomAgent {};
|
||||
let mut agent = agents::RandomAgent {};
|
||||
let b = play(&mut stdout, false, &mut agent)?;
|
||||
if b.is_done() {
|
||||
println!(
|
||||
|
|
|
@ -59,9 +59,9 @@ impl Display for Symb {
|
|||
|
||||
impl Symb {
|
||||
/// Is this symbol a plain binary operator?
|
||||
pub fn is_binop(&self) -> bool {
|
||||
pub fn is_op(&self) -> bool {
|
||||
match self {
|
||||
Symb::Div | Symb::Plus | Symb::Times => true,
|
||||
Symb::Div | Symb::Plus | Symb::Times | Symb::Minus => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue