UI cleanup
parent
76a1bd423c
commit
7394e9db0b
|
@ -2,6 +2,54 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.80"
|
version = "1.0.80"
|
||||||
|
@ -27,29 +75,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "clap"
|
||||||
version = "0.8.5"
|
version = "4.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-epoch",
|
"clap_builder",
|
||||||
"crossbeam-utils",
|
"clap_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "clap_builder"
|
||||||
version = "0.9.18"
|
version = "4.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "clap_derive"
|
||||||
version = "0.8.19"
|
version = "4.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
|
@ -68,6 +137,12 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -105,9 +180,9 @@ name = "ops"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"clap",
|
||||||
"itertools",
|
"itertools",
|
||||||
"rand",
|
"rand",
|
||||||
"rayon",
|
|
||||||
"termion",
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -117,6 +192,24 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -147,26 +240,6 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -182,6 +255,23 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.52"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termion"
|
name = "termion"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
|
@ -194,8 +284,86 @@ dependencies = [
|
||||||
"redox_termios",
|
"redox_termios",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.80"
|
anyhow = "1.0.80"
|
||||||
|
clap = { version = "4.5.1", features = ["derive"] }
|
||||||
itertools = "0.12.1"
|
itertools = "0.12.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rayon = "1.9.0"
|
|
||||||
termion = "3.0.0"
|
termion = "3.0.0"
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
mod diffuse;
|
mod diffuse;
|
||||||
|
mod human;
|
||||||
mod minimax;
|
mod minimax;
|
||||||
mod player;
|
|
||||||
mod random;
|
mod random;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use diffuse::Diffuse;
|
pub use diffuse::Diffuse;
|
||||||
|
pub use human::Human;
|
||||||
pub use minimax::SimpleMinimax;
|
pub use minimax::SimpleMinimax;
|
||||||
pub use player::PlayerAgent;
|
pub use random::Random;
|
||||||
pub use random::RandomAgent;
|
|
||||||
|
|
||||||
use crate::board::{Board, PlayerAction};
|
use crate::{
|
||||||
|
board::{Board, PlayerAction},
|
||||||
|
util::Player,
|
||||||
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub trait Agent {
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
fn player(&self) -> Player;
|
||||||
|
}
|
||||||
|
|
||||||
/// An agent that tries to minimize the value of a board.
|
/// An agent that tries to minimize the value of a board.
|
||||||
pub trait MinimizerAgent {
|
pub trait MinimizerAgent: Agent {
|
||||||
fn step_min(&mut self, board: &Board) -> Result<PlayerAction>;
|
fn step_min(&mut self, board: &Board) -> Result<PlayerAction>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An agent that tries to maximize the value of a board.
|
/// An agent that tries to maximize the value of a board.
|
||||||
pub trait MaximizerAgent {
|
pub trait MaximizerAgent: Agent {
|
||||||
fn step_max(&mut self, board: &Board) -> Result<PlayerAction>;
|
fn step_max(&mut self, board: &Board) -> Result<PlayerAction>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
agents::{Diffuse, Human, MaximizerAgent, MinimizerAgent, Random, SimpleMinimax},
|
||||||
|
util::Player,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(version, about)]
|
||||||
|
pub struct Cli {
|
||||||
|
pub red: AgentSelector,
|
||||||
|
pub blue: AgentSelector,
|
||||||
|
|
||||||
|
#[arg(long, short, default_value = "0")]
|
||||||
|
pub repeat: usize,
|
||||||
|
|
||||||
|
#[arg(long, short, default_value = "false")]
|
||||||
|
pub silent: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||||
|
pub enum AgentSelector {
|
||||||
|
Random,
|
||||||
|
Diffuse,
|
||||||
|
Minimax,
|
||||||
|
Human,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AgentSelector {
|
||||||
|
pub fn to_maxi(&self, player: Player) -> Box<dyn MaximizerAgent> {
|
||||||
|
match self {
|
||||||
|
Self::Random => Box::new(Random::new(player)),
|
||||||
|
Self::Minimax => Box::new(SimpleMinimax::new(player)),
|
||||||
|
Self::Diffuse => Box::new(Diffuse::new(player)),
|
||||||
|
Self::Human => Box::new(Human::new(player)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_mini(&self, player: Player) -> Box<dyn MinimizerAgent> {
|
||||||
|
match self {
|
||||||
|
Self::Random => Box::new(Random::new(player)),
|
||||||
|
Self::Minimax => Box::new(SimpleMinimax::new(player)),
|
||||||
|
Self::Diffuse => Box::new(Diffuse::new(player)),
|
||||||
|
Self::Human => Box::new(Human::new(player)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for AgentSelector {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Random => "random",
|
||||||
|
Self::Diffuse => "diffuse",
|
||||||
|
Self::Minimax => "minimax",
|
||||||
|
Self::Human => "human",
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
235
src/main.rs
235
src/main.rs
|
@ -1,19 +1,59 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
use clap::Parser;
|
||||||
use termion::color::{self};
|
use termion::color::{self};
|
||||||
|
|
||||||
mod agents;
|
mod agents;
|
||||||
mod board;
|
mod board;
|
||||||
|
mod cli;
|
||||||
mod util;
|
mod util;
|
||||||
use board::Board;
|
use board::Board;
|
||||||
use util::{Player, Symb};
|
use util::{Player, Symb};
|
||||||
|
|
||||||
|
fn play_silent(
|
||||||
|
maxi: &mut dyn agents::MaximizerAgent,
|
||||||
|
mini: &mut dyn agents::MinimizerAgent,
|
||||||
|
) -> Result<Board> {
|
||||||
|
let mut board = Board::new();
|
||||||
|
let mut is_maxi_turn = true;
|
||||||
|
|
||||||
|
while !board.is_done() {
|
||||||
|
// Take action
|
||||||
|
let action = if is_maxi_turn {
|
||||||
|
maxi.step_max(&board)?
|
||||||
|
} else {
|
||||||
|
mini.step_min(&board)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if !board.play(
|
||||||
|
action,
|
||||||
|
if is_maxi_turn {
|
||||||
|
maxi.player()
|
||||||
|
} else {
|
||||||
|
mini.player()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
bail!(
|
||||||
|
"agent {} made an invalid move {}!",
|
||||||
|
if is_maxi_turn {
|
||||||
|
maxi.name()
|
||||||
|
} else {
|
||||||
|
mini.name()
|
||||||
|
},
|
||||||
|
action
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_maxi_turn = !is_maxi_turn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(board)
|
||||||
|
}
|
||||||
|
|
||||||
fn play(
|
fn play(
|
||||||
maxi: &mut dyn agents::MaximizerAgent,
|
maxi: &mut dyn agents::MaximizerAgent,
|
||||||
maxi_player: Player,
|
|
||||||
mini: &mut dyn agents::MinimizerAgent,
|
mini: &mut dyn agents::MinimizerAgent,
|
||||||
mini_player: Player,
|
|
||||||
) -> Result<Board> {
|
) -> Result<Board> {
|
||||||
let mut board = Board::new();
|
let mut board = Board::new();
|
||||||
let mut is_first_turn = true;
|
let mut is_first_turn = true;
|
||||||
|
@ -40,12 +80,20 @@ fn play(
|
||||||
if !board.play(
|
if !board.play(
|
||||||
action,
|
action,
|
||||||
if is_maxi_turn {
|
if is_maxi_turn {
|
||||||
maxi_player
|
maxi.player()
|
||||||
} else {
|
} else {
|
||||||
mini_player
|
mini.player()
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
bail!("agent made invalid move")
|
bail!(
|
||||||
|
"agent {} made an invalid move {}!",
|
||||||
|
if is_maxi_turn {
|
||||||
|
maxi.name()
|
||||||
|
} else {
|
||||||
|
mini.name()
|
||||||
|
},
|
||||||
|
action
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is_maxi_turn = !is_maxi_turn;
|
is_maxi_turn = !is_maxi_turn;
|
||||||
|
@ -57,75 +105,140 @@ fn play(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
rayon::ThreadPoolBuilder::new()
|
let cli = cli::Cli::parse();
|
||||||
.num_threads(4)
|
|
||||||
.build_global()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut maxi = agents::PlayerAgent::new(Player::Human);
|
if cli.repeat > 1 {
|
||||||
let mut mini = agents::Diffuse {};
|
let mut red_wins = 0f32;
|
||||||
|
let mut blue_wins = 0f32;
|
||||||
|
|
||||||
let a = play(&mut maxi, Player::Human, &mut mini, Player::Computer)?;
|
for _ in 0..cli.repeat {
|
||||||
if a.is_done() {
|
let mut maxi = cli.red.to_maxi(Player::Red);
|
||||||
|
let mut mini = cli.blue.to_mini(Player::Blue);
|
||||||
|
let red_board = match if cli.silent {
|
||||||
|
play_silent(&mut *maxi, &mut *mini)
|
||||||
|
} else {
|
||||||
|
play(&mut *maxi, &mut *mini)
|
||||||
|
} {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut maxi = cli.blue.to_maxi(Player::Blue);
|
||||||
|
let mut mini = cli.red.to_mini(Player::Red);
|
||||||
|
let blue_board = match if cli.silent {
|
||||||
|
play_silent(&mut *maxi, &mut *mini)
|
||||||
|
} else {
|
||||||
|
play(&mut *maxi, &mut *mini)
|
||||||
|
} {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match red_board.evaluate().partial_cmp(&blue_board.evaluate()) {
|
||||||
|
Some(Ordering::Equal) => {}
|
||||||
|
Some(Ordering::Greater) => red_wins += 1.0,
|
||||||
|
Some(Ordering::Less) => blue_wins += 1.0,
|
||||||
|
None => {
|
||||||
|
println!("Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Played {} rounds\n", cli.repeat);
|
||||||
println!(
|
println!(
|
||||||
"\r\n{}Your score:{} {:.2}\n\n",
|
"Red win rate: {:.2} ({})",
|
||||||
color::Fg(Player::Human.color()),
|
red_wins / cli.repeat as f32,
|
||||||
color::Fg(color::Reset),
|
cli.red.to_string(),
|
||||||
a.evaluate().unwrap()
|
);
|
||||||
|
println!(
|
||||||
|
"Blue win rate: {:.2} ({}) ",
|
||||||
|
blue_wins / cli.repeat as f32,
|
||||||
|
cli.blue.to_string(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
println!(
|
let mut maxi = cli.red.to_maxi(Player::Red);
|
||||||
"\r\n{}Quitting{}\r\n",
|
let mut mini = cli.blue.to_mini(Player::Blue);
|
||||||
color::Fg(color::Red),
|
let red_board = if cli.silent {
|
||||||
color::Fg(color::Reset),
|
play_silent(&mut *maxi, &mut *mini)
|
||||||
);
|
} else {
|
||||||
return Ok(());
|
play(&mut *maxi, &mut *mini)
|
||||||
}
|
}?;
|
||||||
|
|
||||||
let mut mini = agents::PlayerAgent::new(Player::Human);
|
if red_board.is_done() {
|
||||||
let mut maxi = agents::Diffuse {};
|
|
||||||
|
|
||||||
let b = play(&mut maxi, Player::Computer, &mut mini, Player::Human)?;
|
|
||||||
if b.is_done() {
|
|
||||||
println!(
|
|
||||||
"\r\n{}Computer score:{} {:.2}\n\n",
|
|
||||||
color::Fg(Player::Human.color()),
|
|
||||||
color::Fg(color::Reset),
|
|
||||||
b.evaluate().unwrap()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!(
|
|
||||||
"\r\n{}Quitting{}\r\n",
|
|
||||||
color::Fg(color::Red),
|
|
||||||
color::Fg(color::Reset),
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
match a.evaluate().partial_cmp(&b.evaluate()) {
|
|
||||||
Some(Ordering::Equal) => {
|
|
||||||
println!("\r\nTie");
|
|
||||||
}
|
|
||||||
Some(Ordering::Greater) => {
|
|
||||||
println!(
|
println!(
|
||||||
"\r\n{}Human wins{}",
|
"\r\n{}{} score:{} {:.2}\n\n",
|
||||||
color::Fg(Player::Human.color()),
|
color::Fg(maxi.player().color()),
|
||||||
|
maxi.name(),
|
||||||
color::Fg(color::Reset),
|
color::Fg(color::Reset),
|
||||||
|
red_board.evaluate().unwrap()
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
Some(Ordering::Less) => {
|
|
||||||
println!(
|
println!(
|
||||||
"\r\n{}Computer wins{}",
|
"\r\n{}Quitting{}\r\n",
|
||||||
color::Fg(Player::Computer.color()),
|
|
||||||
color::Fg(color::Reset),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
println!(
|
|
||||||
"\r\n{}Error{}",
|
|
||||||
color::Fg(color::Red),
|
color::Fg(color::Red),
|
||||||
color::Fg(color::Reset),
|
color::Fg(color::Reset),
|
||||||
);
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut maxi = cli.blue.to_maxi(Player::Blue);
|
||||||
|
let mut mini = cli.red.to_mini(Player::Red);
|
||||||
|
let blue_board = if cli.silent {
|
||||||
|
play_silent(&mut *maxi, &mut *mini)
|
||||||
|
} else {
|
||||||
|
play(&mut *maxi, &mut *mini)
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if blue_board.is_done() {
|
||||||
|
println!(
|
||||||
|
"\r\n{}{} score:{} {:.2}\n\n",
|
||||||
|
color::Fg(maxi.player().color()),
|
||||||
|
maxi.name(),
|
||||||
|
color::Fg(color::Reset),
|
||||||
|
blue_board.evaluate().unwrap()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"\r\n{}Quitting{}\r\n",
|
||||||
|
color::Fg(color::Red),
|
||||||
|
color::Fg(color::Reset),
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
match red_board.evaluate().partial_cmp(&blue_board.evaluate()) {
|
||||||
|
Some(Ordering::Equal) => {
|
||||||
|
println!("\r\nTie");
|
||||||
|
}
|
||||||
|
Some(Ordering::Greater) => {
|
||||||
|
println!(
|
||||||
|
"\r\n{}Red ({}){} wins!",
|
||||||
|
color::Fg(Player::Red.color()),
|
||||||
|
cli.red.to_string(),
|
||||||
|
color::Fg(color::Reset),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some(Ordering::Less) => {
|
||||||
|
println!(
|
||||||
|
"\r\n{}Blue ({}){} wins!",
|
||||||
|
color::Fg(Player::Blue.color()),
|
||||||
|
cli.blue.to_string(),
|
||||||
|
color::Fg(color::Reset),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!(
|
||||||
|
"\r\n{}Error{}",
|
||||||
|
color::Fg(color::Red),
|
||||||
|
color::Fg(color::Reset),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/util.rs
12
src/util.rs
|
@ -7,15 +7,15 @@ use termion::color::{self, Color};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum Player {
|
pub enum Player {
|
||||||
Human,
|
Red,
|
||||||
Computer,
|
Blue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
pub fn color(&self) -> &dyn Color {
|
pub fn color(&self) -> &dyn Color {
|
||||||
match self {
|
match self {
|
||||||
Player::Computer => &color::LightBlack,
|
Player::Red => &color::LightRed,
|
||||||
Player::Human => &color::Magenta,
|
Player::Blue => &color::LightBlue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ impl Player {
|
||||||
impl Display for Player {
|
impl Display for Player {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
Self::Computer => "Max",
|
Self::Red => "Red ",
|
||||||
Self::Human => "Min",
|
Self::Blue => "Blue",
|
||||||
};
|
};
|
||||||
write!(f, "{s}")
|
write!(f, "{s}")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue