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<House>, 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<House>, 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");