add toml config file parsing to tidepool
This commit is contained in:
parent
e64b11cefe
commit
14024f63ff
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[game]
|
||||
goal = 100
|
||||
rules = "jstris"
|
||||
|
||||
[bot]
|
||||
iters = 9000
|
|
@ -0,0 +1,2 @@
|
|||
game.goal = 18
|
||||
bot.iters = 5000
|
|
@ -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()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod config;
|
||||
pub mod garbage;
|
||||
pub mod queue;
|
||||
pub mod sim;
|
||||
|
|
|
@ -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}");
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue