2017/06-07

This commit is contained in:
2017-12-07 11:08:39 +01:00
parent 6fc08571bf
commit 413c80b41b
9 changed files with 1624 additions and 0 deletions

4
2017/07/Cargo.lock generated Normal file
View File

@@ -0,0 +1,4 @@
[[package]]
name = "day-07"
version = "0.1.0"

6
2017/07/Cargo.toml Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

197
2017/07/src/main.rs Normal file
View 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"])
);
}
}