2017/06-07
This commit is contained in:
4
2017/07/Cargo.lock
generated
Normal file
4
2017/07/Cargo.lock
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
[[package]]
|
||||
name = "day-07"
|
||||
version = "0.1.0"
|
||||
|
||||
6
2017/07/Cargo.toml
Normal file
6
2017/07/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "day-07"
|
||||
version = "0.1.0"
|
||||
authors = ["logaritmisk <anders.e.olsson@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
13
2017/07/example.txt
Normal file
13
2017/07/example.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
pbga (66)
|
||||
xhth (57)
|
||||
ebii (61)
|
||||
havc (66)
|
||||
ktlj (57)
|
||||
fwft (72) -> ktlj, cntj, xhth
|
||||
qoyq (66)
|
||||
padx (45) -> pbga, havc, qoyq
|
||||
tknk (41) -> ugml, padx, fwft
|
||||
jptl (61)
|
||||
ugml (68) -> gyxo, ebii, jptl
|
||||
gyxo (61)
|
||||
cntj (57)
|
||||
1292
2017/07/input.txt
Normal file
1292
2017/07/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
197
2017/07/src/main.rs
Normal file
197
2017/07/src/main.rs
Normal file
@@ -0,0 +1,197 @@
|
||||
use std::io::{self, Read};
|
||||
|
||||
|
||||
mod parser {
|
||||
pub type Program<'a> = (&'a str, i64, Vec<&'a str>);
|
||||
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum State {
|
||||
Name,
|
||||
PreWeight,
|
||||
Weight(usize),
|
||||
PreAbove,
|
||||
Above(usize),
|
||||
}
|
||||
|
||||
|
||||
pub fn from_str(input: &str) -> Program {
|
||||
let mut name = None;
|
||||
let mut weight = None;
|
||||
let mut above = Vec::new();
|
||||
|
||||
let mut state = State::Name;
|
||||
|
||||
for (i, c) in input.chars().enumerate() {
|
||||
match (state, c) {
|
||||
(State::Name, ' ') => {
|
||||
name = Some(&input[0..i]);
|
||||
state = State::PreWeight;
|
||||
}
|
||||
|
||||
(State::PreWeight, '(') => {
|
||||
state = State::Weight(i + 1);
|
||||
}
|
||||
|
||||
(State::Weight(start), ')') => {
|
||||
weight = input[start..i].parse::<i64>().ok();
|
||||
state = State::PreAbove;
|
||||
}
|
||||
|
||||
(State::PreAbove, 'a'...'z') => {
|
||||
state = State::Above(i);
|
||||
}
|
||||
|
||||
(State::Above(start), ',') => {
|
||||
above.push(&input[start..i]);
|
||||
state = State::PreAbove;
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let State::Above(start) = state {
|
||||
above.push(&input[start..input.len()]);
|
||||
}
|
||||
|
||||
(name.unwrap(), weight.unwrap(), above)
|
||||
}
|
||||
}
|
||||
|
||||
mod tree {
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use parser::Program;
|
||||
|
||||
|
||||
pub type Tree<'a> = HashMap<&'a str, Info<'a>>;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Info<'a> {
|
||||
weight: i64,
|
||||
above: Tree<'a>,
|
||||
}
|
||||
|
||||
|
||||
pub fn build(programs: Vec<Program>) -> Tree {
|
||||
let mut tree = Tree::new();
|
||||
|
||||
let mut temp = VecDeque::new();
|
||||
|
||||
for (name, weight, above) in programs {
|
||||
if above.is_empty() {
|
||||
tree.insert(
|
||||
name,
|
||||
Info {
|
||||
weight: weight,
|
||||
above: Tree::new(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
temp.push_back((name, weight, above));
|
||||
}
|
||||
}
|
||||
|
||||
while let Some((name, weight, above)) = temp.pop_front() {
|
||||
if above
|
||||
.iter()
|
||||
.any(|name_above| !tree.contains_key(name_above))
|
||||
{
|
||||
temp.push_back((name, weight, above));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let info = Info {
|
||||
weight: weight,
|
||||
above: above
|
||||
.into_iter()
|
||||
.map(|name_above| (name_above, tree.remove(name_above).unwrap()))
|
||||
.collect::<Tree>(),
|
||||
};
|
||||
|
||||
tree.insert(name, info);
|
||||
}
|
||||
|
||||
tree
|
||||
}
|
||||
|
||||
pub fn stacker(name: &str, root: &Info, level: usize) -> i64 {
|
||||
if root.above.is_empty() {
|
||||
root.weight
|
||||
} else {
|
||||
let mut total = 0;
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for (name, stack) in &root.above {
|
||||
let weight = stacker(name, stack, level + 1);
|
||||
|
||||
total += weight;
|
||||
|
||||
map.entry(weight).or_insert_with(Vec::new).push(name);
|
||||
}
|
||||
|
||||
if map.len() > 1 {
|
||||
let (wrong, correct) =
|
||||
map.iter()
|
||||
.fold((0, 0), |(wrong, correct), (weight, programs)| {
|
||||
if programs.len() == 1 {
|
||||
(*weight, correct)
|
||||
} else {
|
||||
(wrong, *weight)
|
||||
}
|
||||
});
|
||||
|
||||
let mut weight = root.above[map[&wrong][0]].weight;
|
||||
|
||||
weight += correct - wrong;
|
||||
|
||||
println!("{}: {} weight should be {}", level, name, weight);
|
||||
}
|
||||
|
||||
root.weight + total
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
|
||||
io::stdin()
|
||||
.read_to_string(&mut input)
|
||||
.expect("failed to read input");
|
||||
|
||||
let programs = input
|
||||
.lines()
|
||||
.filter(|line| !line.is_empty())
|
||||
.map(parser::from_str)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let tree = tree::build(programs);
|
||||
|
||||
let root = tree.keys().nth(0).unwrap();
|
||||
|
||||
println!("part_one={:?}", root);
|
||||
println!("part_two:");
|
||||
|
||||
tree::stacker(root, &tree[root], 0);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
assert_eq!(parser::from_str("pbga (66)"), ("pbga", 66, vec![]));
|
||||
assert_eq!(
|
||||
parser::from_str("fwft (72) -> ktlj, cntj, xhth"),
|
||||
("fwft", 72, vec!["ktlj", "cntj", "xhth"])
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user