diff --git a/Cargo.lock b/Cargo.lock index 66ac287..1e45f74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,15 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -168,6 +177,7 @@ dependencies = [ "indicatif", "itertools", "rand", + "regex", "rusqlite", ] @@ -213,18 +223,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "rusqlite" @@ -257,6 +270,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "thread_local" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" +dependencies = [ + "lazy_static", +] + [[package]] name = "unicode-width" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index b22e49e..decc041 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,12 @@ rand = "0.8.0" indicatif = "0.15.0" itertools = "0.10.0" rusqlite = "0.24.2" +regex = "1.4.3" [[bin]] name = "prague" path = "src/main.rs" + +[[bin]] +name = "import-logs" +path = "src/import-logs.rs" diff --git a/src/db.rs b/src/db.rs index 533dbeb..b496d09 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,5 +1,5 @@ use crate::city::House; -use rusqlite::{Connection, NO_PARAMS, params, Result}; +use rusqlite::{Connection, NO_PARAMS, params, Result, Transaction}; use std::collections::HashMap; pub struct LayoutDB { @@ -45,15 +45,16 @@ impl LayoutDB { &self.layouts } - pub fn add_layout(&self, houses: &Vec, fully_optimized: bool) -> Result<()> { - self.connection.execute("INSERT INTO layouts (is_fully_optimized) VALUES (?1)", - params![fully_optimized])?; - let layout_id = self.connection.last_insert_rowid(); + pub fn add_layout(&mut self, houses: &Vec, fully_optimized: bool) -> Result<()> { + let transaction = self.connection.transaction()?; + transaction.execute("INSERT INTO layouts (is_fully_optimized) VALUES (?1)", + params![fully_optimized])?; + let layout_id = transaction.last_insert_rowid(); for house in houses { - self.connection.execute("INSERT INTO houses (layout_id, x, y) VALUES (?1, ?2, ?3)", - params![layout_id, house.x as u32, house.y as u32])?; + transaction.execute("INSERT INTO houses (layout_id, x, y) VALUES (?1, ?2, ?3)", + params![layout_id, house.x as u32, house.y as u32])?; } - + transaction.commit()?; Ok(()) } } diff --git a/src/import-logs.rs b/src/import-logs.rs new file mode 100644 index 0000000..512d577 --- /dev/null +++ b/src/import-logs.rs @@ -0,0 +1,72 @@ +use std::io; +use std::io::BufRead; +use regex::Regex; +use crate::city::House; +use crate::db::LayoutDB; + +mod city; +mod db; + +enum State { + Out, + ReadPrice, + In(usize), +} + +fn main() { + let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); + let stdin = io::stdin(); + + let price_regex = Regex::new("^Price ([0-9]*), seed ([0-9]*)$").unwrap(); + + let mut state = State::Out; + let mut current_price = String::new(); + let mut current_seed = String::new(); + let mut houses = Vec::new(); + for line in stdin.lock().lines() { + let line = line.unwrap(); + state = match state { + State::Out => { + if let Some(captures) = price_regex.captures(&line) { + let price = captures.get(1).unwrap().as_str().to_string(); + let seed = captures.get(2).unwrap().as_str().to_string(); + + // Ensure we only save the last layout for a seed + if seed != current_seed && !houses.is_empty() { + eprintln!("Saved house with seed {}, price {}", current_seed, current_price); + db.add_layout(&houses, true); + } else { + houses.clear(); + } + + current_seed = seed; + current_price = price; + State::ReadPrice + } else { + State::Out + } + }, + State::ReadPrice => { + let count: usize = line.parse().expect("Failed to read house count"); + State::In(count) + }, + State::In(count) => { + let mut parts = line.split_whitespace(); + let x: usize = parts.next().unwrap().parse().expect("Failed to read x"); + let y: usize = parts.next().unwrap().parse().expect("Failed to read y"); + houses.push(House {x, y}); + + if count == 1 { + State::Out + } else { + State::In(count - 1) + } + } + } + } + + if !houses.is_empty() { + eprintln!("Saved house with seed {}, price {}", current_seed, current_price); + db.add_layout(&houses, true); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c4e33ed..5dc7cf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ mod city; mod db; fn main() { - let db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); + let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); let city = City::read_from_file("01.in");