add toml config file parsing to tidepool

This commit is contained in:
tali 2023-04-11 20:43:32 -04:00
parent e64b11cefe
commit 14024f63ff
8 changed files with 299 additions and 18 deletions

84
Cargo.lock generated
View File

@ -20,6 +20,12 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -110,7 +116,7 @@ dependencies = [
"anyhow",
"bumpalo",
"clap",
"hashbrown",
"hashbrown 0.13.1",
"mino",
"serde",
"serde_json",
@ -129,6 +135,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.1"
@ -153,6 +165,16 @@ dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "io-lifetimes"
version = "1.0.3"
@ -217,6 +239,12 @@ dependencies = [
"regex-automata",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mino"
version = "0.1.0"
@ -429,6 +457,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
@ -488,10 +525,46 @@ dependencies = [
"mino",
"rand",
"rand_xoshiro",
"serde",
"toml",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "toml"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.37"
@ -665,3 +738,12 @@ name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "winnow"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"memchr",
]

View File

@ -8,8 +8,15 @@ edition = "2021"
mino = { path = "../mino" }
fish = { path = "../fish" }
# lib
rand = "0.8"
rand_xoshiro = "0.6"
serde = { version = "1.0", features = ["derive"] }
tracing = { version = "0.1" }
# cli
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"]}
toml = { version = "0.7" }
# anyhow = { version = "1.0" }
# clap = { version = "4.0", features = ["derive"] }

View File

@ -0,0 +1,6 @@
[game]
goal = 100
rules = "jstris"
[bot]
iters = 9000

View File

@ -0,0 +1,2 @@
game.goal = 18
bot.iters = 5000

177
tidepool/src/config.rs Normal file
View File

@ -0,0 +1,177 @@
//! Config file schema (serde) for tidepool. See `example-configs/` for usage samples.
use serde::Deserialize;
#[derive(Deserialize, PartialEq, Debug)]
pub struct Config {
pub game: GameConfig,
#[serde(default)]
pub bot: BotConfig,
}
#[derive(Deserialize, PartialEq, Debug)]
pub struct GameConfig {
pub goal: usize,
#[serde(default = "defaults::rules", deserialize_with = "game_rules_config")]
pub rules: GameRulesConfig,
}
#[derive(Deserialize, PartialEq, Debug)]
pub struct GameRulesConfig {
#[serde(default = "defaults::min_garbage")]
pub min: usize,
#[serde(default = "defaults::max_garbage")]
pub max: usize,
#[serde(default = "defaults::previews")]
pub previews: usize,
}
impl GameRulesConfig {
pub const JSTRIS: Self = Self {
min: 3,
max: 9,
previews: 5,
};
}
fn game_rules_config<'de, D>(deserializer: D) -> Result<GameRulesConfig, D::Error>
where
D: serde::Deserializer<'de>,
{
// all this nonsense is to support `rules = "jstris"` as an entry
#[derive(Deserialize)]
#[serde(untagged)]
enum Variant {
Jstris(Jstris),
Custom(GameRulesConfig),
}
#[derive(Deserialize)]
enum Jstris {
#[serde(rename = "jstris")]
Tag,
}
Variant::deserialize(deserializer).map(|var| match var {
Variant::Jstris(_) => GameRulesConfig::JSTRIS,
Variant::Custom(c) => c,
})
}
#[derive(Deserialize, PartialEq, Debug)]
pub struct BotConfig {
// TODO: weights
// TODO: algorithm
// TODO: capabililties
#[serde(default = "defaults::iters")]
pub iters: usize,
}
impl BotConfig {
pub const DEFAULT: Self = Self { iters: 10_000 };
}
impl Default for BotConfig {
fn default() -> Self {
Self::DEFAULT
}
}
mod defaults {
use super::*;
pub const fn min_garbage() -> usize {
GameRulesConfig::JSTRIS.min
}
pub const fn max_garbage() -> usize {
GameRulesConfig::JSTRIS.max
}
pub const fn previews() -> usize {
GameRulesConfig::JSTRIS.previews
}
pub const fn rules() -> GameRulesConfig {
GameRulesConfig::JSTRIS
}
pub const fn iters() -> usize {
BotConfig::DEFAULT.iters
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_de_1() {
assert_eq!(
toml::from_str::<Config>(
"
[game]
goal = 100
[bot]
iters = 5_000
"
)
.unwrap(),
Config {
game: GameConfig {
goal: 100,
rules: GameRulesConfig::JSTRIS,
},
bot: BotConfig { iters: 5_000 }
}
);
}
#[test]
fn test_de_2() {
assert_eq!(
toml::from_str::<Config>(
"
game.goal = 100
game.rules = { min = 4, previews = 8 }
bot = {}
"
)
.unwrap(),
Config {
game: GameConfig {
goal: 100,
rules: GameRulesConfig {
min: 4,
max: 9,
previews: 8,
},
},
bot: BotConfig::default(),
}
);
}
#[test]
fn test_de_3() {
assert_eq!(
toml::from_str::<Config>(
"
[game]
goal = 18
rules = \"jstris\"
"
)
.unwrap(),
Config {
game: GameConfig {
goal: 18,
rules: GameRulesConfig::JSTRIS,
},
bot: BotConfig::default()
}
);
}
}

View File

@ -1,3 +1,4 @@
pub mod config;
pub mod garbage;
pub mod queue;
pub mod sim;

View File

@ -1,12 +1,10 @@
use fish::bot::Bot;
use mino::srs::Queue;
use rand::RngCore as _;
use tidepool::sim;
use std::io::Read as _;
use tidepool::{config, sim};
pub fn main() -> std::io::Result<()> {
const THINK_CYCLES: usize = 5_000;
const GOAL: usize = 18;
tracing_subscriber::fmt::fmt()
.with_writer(std::io::stderr)
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
@ -15,7 +13,25 @@ pub fn main() -> std::io::Result<()> {
let seed = rand::thread_rng().next_u64();
println!("using seed: {seed}");
let mut sim = sim::Simul::new(seed, sim::Options::jstris(GOAL));
let mut config_file = match std::env::args().nth(1) {
Some(f) => std::fs::File::open(f)?,
None => {
eprintln!("usage: tidepool <CONFIG_FILE>");
return Ok(());
}
};
let mut config = String::new();
config_file.read_to_string(&mut config)?;
let config = toml::from_str::<config::Config>(&config).unwrap();
let opts = sim::Options {
goal: config.game.goal,
garbage: config.game.rules.min..=config.game.rules.max,
previews: config.game.rules.previews,
};
let mut sim = sim::Simul::new(seed, opts);
let mut ds = 0;
let mut ps = 0;
@ -38,7 +54,7 @@ pub fn main() -> std::io::Result<()> {
let queue = Queue::new(hold, &next);
let mut bot = Bot::new(mat, queue);
for i in 0..THINK_CYCLES {
for i in 0..config.bot.iters {
if i > 0 && i % 1000 == 0 {
tracing::debug!("iteration {i}");
}

View File

@ -15,16 +15,6 @@ pub struct Options {
pub previews: usize,
}
impl Options {
pub const fn jstris(goal: usize) -> Self {
Self {
goal,
garbage: 3..=9,
previews: 5,
}
}
}
type Rng = rand_xoshiro::Xoshiro256StarStar;
pub struct Simul {