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 rand::Rng;
|
||||||
|
use std::num::NonZeroU8;
|
||||||
use crate::{util::Symb, PlayerAgent};
|
|
||||||
|
|
||||||
pub struct RandomAgent {}
|
pub struct RandomAgent {}
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -11,22 +11,16 @@ use termion::{
|
||||||
raw::IntoRawMode,
|
raw::IntoRawMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod agents;
|
||||||
mod board;
|
mod board;
|
||||||
mod random;
|
|
||||||
mod util;
|
mod util;
|
||||||
use board::Board;
|
use board::Board;
|
||||||
use util::{Player, Symb};
|
use util::{Player, Symb};
|
||||||
|
|
||||||
use crate::random::RandomAgent;
|
|
||||||
|
|
||||||
pub trait PlayerAgent {
|
|
||||||
fn step(&mut self, board: &mut Board);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play(
|
fn play(
|
||||||
stdout: &mut StdoutLock,
|
stdout: &mut StdoutLock,
|
||||||
player_max: bool,
|
player_max: bool,
|
||||||
computer: &mut dyn PlayerAgent,
|
computer: &mut dyn agents::PlayerAgent,
|
||||||
) -> Result<Board> {
|
) -> Result<Board> {
|
||||||
let mut cursor = 0usize;
|
let mut cursor = 0usize;
|
||||||
let cursor_offset = 10usize - 1;
|
let cursor_offset = 10usize - 1;
|
||||||
|
@ -88,6 +82,7 @@ fn play(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Player turn
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
for c in stdin.keys() {
|
for c in stdin.keys() {
|
||||||
print_board = match c.unwrap() {
|
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('8') => board.play(cursor, Symb::Number(NonZeroU8::new(8).unwrap())),
|
||||||
Key::Char('9') => board.play(cursor, Symb::Number(NonZeroU8::new(9).unwrap())),
|
Key::Char('9') => board.play(cursor, Symb::Number(NonZeroU8::new(9).unwrap())),
|
||||||
Key::Char('0') => board.play(cursor, Symb::Zero),
|
Key::Char('0') => board.play(cursor, Symb::Zero),
|
||||||
Key::Char('a') => board.play(cursor, Symb::Plus),
|
Key::Char('+') => board.play(cursor, Symb::Plus),
|
||||||
Key::Char('s') => board.play(cursor, Symb::Minus),
|
Key::Char('-') => board.play(cursor, Symb::Minus),
|
||||||
Key::Char('m') => board.play(cursor, Symb::Times),
|
Key::Char('*') => board.play(cursor, Symb::Times),
|
||||||
Key::Char('d') => board.play(cursor, Symb::Div),
|
Key::Char('/') => board.play(cursor, Symb::Div),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
|
@ -129,7 +124,7 @@ fn main() -> Result<()> {
|
||||||
let stdout = HideCursor::from(stdout().into_raw_mode().unwrap());
|
let stdout = HideCursor::from(stdout().into_raw_mode().unwrap());
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
|
|
||||||
let mut agent = RandomAgent {};
|
let mut agent = agents::DiffuseAgent {};
|
||||||
let a = play(&mut stdout, true, &mut agent)?;
|
let a = play(&mut stdout, true, &mut agent)?;
|
||||||
if a.is_done() {
|
if a.is_done() {
|
||||||
println!(
|
println!(
|
||||||
|
@ -147,7 +142,7 @@ fn main() -> Result<()> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut agent = RandomAgent {};
|
let mut agent = agents::RandomAgent {};
|
||||||
let b = play(&mut stdout, false, &mut agent)?;
|
let b = play(&mut stdout, false, &mut agent)?;
|
||||||
if b.is_done() {
|
if b.is_done() {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -59,9 +59,9 @@ impl Display for Symb {
|
||||||
|
|
||||||
impl Symb {
|
impl Symb {
|
||||||
/// Is this symbol a plain binary operator?
|
/// Is this symbol a plain binary operator?
|
||||||
pub fn is_binop(&self) -> bool {
|
pub fn is_op(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Symb::Div | Symb::Plus | Symb::Times => true,
|
Symb::Div | Symb::Plus | Symb::Times | Symb::Minus => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue