~ttt/aoc2015

2921abb70f8069d03714c2744e061d53952c582b — Tomasz Kłak 5 years ago
Initial commit
11 files changed, 1267 insertions(+), 0 deletions(-)

A 1/main.rs
A 2/main.rs
A 3/main.rs
A 5/main.rs
A 6/main.rs
A day7/Cargo.toml
A day7/input
A day7/input2
A day7/src/main.rs
A day_4/Cargo.toml
A day_4/src/main.rs
A  => 1/main.rs +47 -0
@@ 1,47 @@
use std::io::Read;

fn solve_a(input: &str) -> i32 {
   input.chars().filter(|c| *c == '(').count() as i32  -
       input.chars().filter(|c| *c == ')').count() as i32
}

fn solve_b(input: &str) -> usize {
    let mut level = 0;
    for (i, c) in input.chars().enumerate() {
        if c == '(' {
            level += 1;
        } else {
            level -= 1;
        }
        if level < 0 {
            return i+1
        }
    }
    unreachable!();
}

fn main() {
    let mut buf = String::new();
    std::io::stdin().read_to_string(&mut buf).unwrap();
    println!("{}", solve_a(buf.trim()));
    println!("{}", solve_b(buf.trim()));
}

#[test]
fn solve_a_test() {
    assert_eq!(0, solve_a("(())"));
    assert_eq!(0, solve_a("()()"));
    assert_eq!(3, solve_a("((("));
    assert_eq!(3, solve_a("(()(()("));
    assert_eq!(3, solve_a("))((((("));
    assert_eq!(-1, solve_a("())"));
    assert_eq!(-1, solve_a("))("));
    assert_eq!(-3, solve_a(")))"));
    assert_eq!(-3, solve_a(")())())"));
}

#[test]
fn solve_b_test() {
    assert_eq!(1, solve_b(")"));
    assert_eq!(5, solve_b("()())"));
}

A  => 2/main.rs +61 -0
@@ 1,61 @@
use std::io::{BufRead,BufReader};

#[derive(PartialEq, Debug)]
struct Present {
    w: i32,
    h: i32,
    l: i32
}

impl Present {

    fn new(w: i32, h: i32, l: i32) -> Present {
        Present{w, h, l}
    }

    fn area(&self) -> i32 {
        let a = 2 * self.l * self.w;
        let b = 2 * self.w * self.h;
        let c = 2 * self.h * self.l;
        let smallest = if a < b { a } else { b };
        let smallest = if smallest < c { smallest } else { c };
        a + b + c + smallest / 2
    }

    fn ribbon(&self) -> i32 {
        let bow = self.w * self.h * self.l;
        let a = (self.l + self.w) * 2;
        let b = (self.w + self.h) * 2;
        let c = (self.h + self.l) * 2;
        let smallest = if a < b { a } else { b };
        let smallest = if smallest < c { smallest } else { c };
        smallest + bow
    }
}

fn parse(input: &str) -> Present {
    let r : Vec<i32> = input.split('x').map(|s| s.parse().unwrap()).collect();
    Present::new(r[0], r[1], r[2])
}

fn main() {
    let r = BufReader::new(std::io::stdin());
    let presents : Vec<Present> = r.lines().map(|r| parse(&r.unwrap())).collect();

    let area : i32 = presents.iter().map(Present::area).sum();
    println!("{}", area);
    let ribbon : i32 =  presents.iter().map(Present::ribbon).sum();
    println!("{}", ribbon);
}

#[test]
fn area_test() {
    assert_eq!(58, Present::new(2,3,4).area());
    assert_eq!(43, Present::new(1,1,10).area());
}

#[test]
fn parse_test() {
    assert_eq!(Present::new(2,3,4), parse("2x3x4"));
    assert_eq!(Present::new(1,1,10), parse("1x1x10"));
}

A  => 3/main.rs +91 -0
@@ 1,91 @@
use std::collections::HashSet;
use std::io::Read;

#[derive(Clone,Hash,PartialEq,Eq,Debug)]
struct Pos {
    x: i32,
    y: i32
}

#[derive(Clone, Copy)]
enum Direction {
    Up, Down, Left, Right
}

impl Pos {
    fn move_by(&self, d: Direction) -> Pos {
        match d {
            Direction::Up       => Pos{x: self.x,   y: self.y+1 },
            Direction::Down     => Pos{x: self.x,   y: self.y-1 },
            Direction::Left     => Pos{x: self.x-1, y: self.y   },
            Direction::Right    => Pos{x: self.x+1, y: self.y   },
        }
    }
}

fn parse(c: char) -> Direction {
    match c {
        '^' => Direction::Up,
        'v' => Direction::Down,
        '>' => Direction::Right,
        '<' => Direction::Left,
        _   => unreachable!(),
    }
}

fn solve_a(directions: &[Direction]) -> usize {
    let mut pos = Pos{x: 0, y: 0};
    solve(directions, |_, d, s| { pos = pos.move_by(d); s.insert(pos.clone()); })
}

fn solve_b(directions: &[Direction]) -> usize {
    let mut pos = Pos{x: 0, y: 0};
    let mut robo = Pos{x: 0, y: 0};
    let f = |i, d, s: &mut HashSet<Pos>| {
        if i % 2 == 0 {
            pos = pos.move_by(d);
            s.insert(pos.clone());
        } else {
            robo = robo.move_by(d);
            s.insert(robo.clone());
        }
    };
    solve(directions, f)
}

fn solve<F>(directions: &[Direction], mut f: F) -> usize
    where F: FnMut(usize, Direction, &mut HashSet<Pos>) -> () {
    let mut seen = HashSet::new();
    seen.insert(Pos{x: 0, y: 0});
    directions.iter().enumerate().for_each(|(i, d)| f(i, *d, &mut seen));
    seen.len()
}

fn main() {
    let mut buf = String::new();
    std::io::stdin().read_to_string(&mut buf).unwrap();
    let directions : Vec<Direction> = buf.trim().chars().map(parse).collect();
    let a = solve_a(&directions);
    println!("{}", a);
    let b = solve_b(&directions);
    println!("{}", b);
}

#[test]
fn solve_a_test() {
    assert_eq!(2, solve_a(&[Direction::Right]));
    assert_eq!(4, solve_a(&[Direction::Up,Direction::Right,Direction::Down,Direction::Left]));
    assert_eq!(2, solve_a(&[
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down,
                          Direction::Up,Direction::Down]));
}

#[test]
fn solve_b_test() {
    assert_eq!(3, solve_b(&[Direction::Up, Direction::Down]));
}

A  => 5/main.rs +65 -0
@@ 1,65 @@
use std::io::BufRead;

static NEEDED_VOVELS : &str = "aeiou";

fn vovels(s: &str) -> bool {
    s.chars().filter(|c| NEEDED_VOVELS.contains(*c)).count() >= 3
}

fn row(s: &str) -> bool {
    s.chars().zip(s.chars().skip(1)).any(|(a,b)| a == b)
}

static FORBIDEN_SUBSTRINGS : &[&str] = &["ab", "cd", "pq", "xy"];

fn forbiden(s: &str) -> bool {
    FORBIDEN_SUBSTRINGS.iter().all(|x| !s.contains(x))
}

fn is_nice_string(s: &str) -> bool {
    vovels(s) && row(s) && forbiden(s)
}

fn three(s: &str) -> bool {
    s.chars().zip(s.chars().skip(2)).any(|(a,b)| a == b)
}

fn pair(s: &str) -> bool {
    let v : Vec<char> = s.chars().collect();
    for w in v.windows(2) {
        let needle : String = w.iter().collect();
        if s.matches(&needle).count() > 1 {
            return true
        }
    }
    false
}

fn is_nice_string_b(s: &str) -> bool {
    three(s) && pair(s)
}

fn main() {
    let lines : Vec<String> = std::io::BufReader::new(std::io::stdin())
        .lines()
        .map(|s| s.unwrap()).collect();
    let nice = lines
        .iter()
        .filter(|s| is_nice_string(s))
        .count();
    println!("{}", nice);
    let nice_b = lines
        .iter()
        .filter(|s| is_nice_string_b(s))
        .count();
    println!("{}", nice_b);
}

#[test]
fn is_nice_string_test() {
    assert!(is_nice_string("ugknbfddgicrmopn"));
    assert!(is_nice_string("aaa"));
    assert!(!is_nice_string("jchzalrnumimnmhp"));
    assert!(!is_nice_string("haegwjzuvuyypxyu"));
    assert!(!is_nice_string("dvszwmarrgswjxmb"));
}

A  => 6/main.rs +94 -0
@@ 1,94 @@
use std::io::BufRead;

const SIZE: usize = 1000;

fn new_board<T: Copy>(default: T) -> [[T; SIZE]; SIZE] {
    [[default; SIZE]; SIZE]
}

fn count<T, F: Fn(&T) -> bool>(b: &[[T; SIZE]; SIZE], f: F) -> usize {
    b.iter().map(|r| r.iter().filter(|x| f(*x)).count()).sum()
}

fn set<T: Copy, F: Fn(&T) -> T>(b: &mut [[T; SIZE]; SIZE], first: (usize, usize), last: (usize, usize), f: F) {
    for x in first.0..(last.0+1) {
        for y in first.1..(last.1+1) {
            b[x][y] = f(&b[x][y]);// value;
        }
    }
}

fn toggle<T, F: Fn(&T) -> T>(b: &mut [[T; SIZE]; SIZE], first: (usize, usize), last: (usize, usize), f: F) {
    for x in first.0..(last.0+1) {
        for y in first.1..(last.1+1) {
            b[x][y] = f(&b[x][y]);// !b[x][y];
        }
    }
}

fn parse_pair(s: &str) -> (usize, usize) {
    let s : Vec<&str> = s.split(',').collect();
    (s[0].parse::<usize>().unwrap(), s[1].parse::<usize>().unwrap())
}

fn exec<T: Copy, F1: Fn(&T) -> T, F2: Fn(&T) -> T, F3: Fn(&T) -> T>(mut b: &mut [[T; SIZE]; SIZE], s: &str, on: F1, off: F2, tog: F3) {
    if s.starts_with("turn on ") {
        let tmp : Vec<&str> = s.split(" ").collect();
        let start = parse_pair(tmp[2]);
        let last = parse_pair(tmp[4]);
        set(&mut b, start, last, on);
    } else if s.starts_with("turn off ") {
        let tmp : Vec<&str> = s.split(" ").collect();
        let start = parse_pair(tmp[2]);
        let last = parse_pair(tmp[4]);
        set(&mut b, start, last, off);
    } else if s.starts_with("toggle ") {
        let tmp : Vec<&str> = s.split(" ").collect();
        let start = parse_pair(tmp[1]);
        let last = parse_pair(tmp[3]);
        toggle(&mut b, start, last, tog);
    }
}

fn main() {
    let lines : Result<Vec<String>,_> = std::io::BufReader::new(std::io::stdin()).lines().collect();
    let lines = lines.unwrap();
    let mut b = new_board::<bool>(false);
    for l in &lines {
        exec(&mut b, &l, |_| true, |_| false, |x| !x);
    }
    println!("{}", count(&b, |b| *b));
    let mut b = new_board::<u32>(0);
    for l in lines {
        exec(&mut b, &l, |v| v+1, |v| v.saturating_sub(1), |v| v+2);
    }
    let sum : u32 = b.iter().map(|r| r.iter().sum::<u32>()).sum();
    println!("{}", sum);
}

#[test]
fn test_empty_board() {
    assert_eq!(0, count(&new_board::<bool>(false)));
}

#[test]
fn test_1() {
    let mut b = new_board::<bool>(false);
    set(&mut b, (0, 0), (999, 999), true);
    assert_eq!(1000*1000, count(&b));
}

#[test]
fn test_2() {
    let mut b = new_board::<bool>(false);
    toggle(&mut b, (0, 0), (999, 0), |b| !b);
    assert_eq!(1000, count(&b));
}

#[test]
fn test_3() {
    let mut b = new_board::<bool>(false);
    set(&mut b, (0, 0), (999, 999), true);
    set(&mut b, (499,499), (500, 500), false);
    assert_eq!(1000*1000-4, count(&b));
}

A  => day7/Cargo.toml +11 -0
@@ 1,11 @@
[package]
name = "day7"
version = "0.1.0"
authors = ["Tomasz Kłak <tomasz@tomaszklak.pl>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
regex = "1"
lazy_static = "1.4"

A  => day7/input +339 -0
@@ 1,339 @@
bn RSHIFT 2 -> bo
lf RSHIFT 1 -> ly
fo RSHIFT 3 -> fq
cj OR cp -> cq
fo OR fz -> ga
t OR s -> u
lx -> a
NOT ax -> ay
he RSHIFT 2 -> hf
lf OR lq -> lr
lr AND lt -> lu
dy OR ej -> ek
1 AND cx -> cy
hb LSHIFT 1 -> hv
1 AND bh -> bi
ih AND ij -> ik
c LSHIFT 1 -> t
ea AND eb -> ed
km OR kn -> ko
NOT bw -> bx
ci OR ct -> cu
NOT p -> q
lw OR lv -> lx
NOT lo -> lp
fp OR fv -> fw
o AND q -> r
dh AND dj -> dk
ap LSHIFT 1 -> bj
bk LSHIFT 1 -> ce
NOT ii -> ij
gh OR gi -> gj
kk RSHIFT 1 -> ld
lc LSHIFT 1 -> lw
lb OR la -> lc
1 AND am -> an
gn AND gp -> gq
lf RSHIFT 3 -> lh
e OR f -> g
lg AND lm -> lo
ci RSHIFT 1 -> db
cf LSHIFT 1 -> cz
bn RSHIFT 1 -> cg
et AND fe -> fg
is OR it -> iu
kw AND ky -> kz
ck AND cl -> cn
bj OR bi -> bk
gj RSHIFT 1 -> hc
iu AND jf -> jh
NOT bs -> bt
kk OR kv -> kw
ks AND ku -> kv
hz OR ik -> il
b RSHIFT 1 -> v
iu RSHIFT 1 -> jn
fo RSHIFT 5 -> fr
be AND bg -> bh
ga AND gc -> gd
hf OR hl -> hm
ld OR le -> lf
as RSHIFT 5 -> av
fm OR fn -> fo
hm AND ho -> hp
lg OR lm -> ln
NOT kx -> ky
kk RSHIFT 3 -> km
ek AND em -> en
NOT ft -> fu
NOT jh -> ji
jn OR jo -> jp
gj AND gu -> gw
d AND j -> l
et RSHIFT 1 -> fm
jq OR jw -> jx
ep OR eo -> eq
lv LSHIFT 15 -> lz
NOT ey -> ez
jp RSHIFT 2 -> jq
eg AND ei -> ej
NOT dm -> dn
jp AND ka -> kc
as AND bd -> bf
fk OR fj -> fl
dw OR dx -> dy
lj AND ll -> lm
ec AND ee -> ef
fq AND fr -> ft
NOT kp -> kq
ki OR kj -> kk
cz OR cy -> da
as RSHIFT 3 -> au
an LSHIFT 15 -> ar
fj LSHIFT 15 -> fn
1 AND fi -> fj
he RSHIFT 1 -> hx
lf RSHIFT 2 -> lg
kf LSHIFT 15 -> kj
dz AND ef -> eh
ib OR ic -> id
lf RSHIFT 5 -> li
bp OR bq -> br
NOT gs -> gt
fo RSHIFT 1 -> gh
bz AND cb -> cc
ea OR eb -> ec
lf AND lq -> ls
NOT l -> m
hz RSHIFT 3 -> ib
NOT di -> dj
NOT lk -> ll
jp RSHIFT 3 -> jr
jp RSHIFT 5 -> js
NOT bf -> bg
s LSHIFT 15 -> w
eq LSHIFT 1 -> fk
jl OR jk -> jm
hz AND ik -> im
dz OR ef -> eg
1 AND gy -> gz
la LSHIFT 15 -> le
br AND bt -> bu
NOT cn -> co
v OR w -> x
d OR j -> k
1 AND gd -> ge
ia OR ig -> ih
NOT go -> gp
NOT ed -> ee
jq AND jw -> jy
et OR fe -> ff
aw AND ay -> az
ff AND fh -> fi
ir LSHIFT 1 -> jl
gg LSHIFT 1 -> ha
x RSHIFT 2 -> y
db OR dc -> dd
bl OR bm -> bn
ib AND ic -> ie
x RSHIFT 3 -> z
lh AND li -> lk
ce OR cd -> cf
NOT bb -> bc
hi AND hk -> hl
NOT gb -> gc
1 AND r -> s
fw AND fy -> fz
fb AND fd -> fe
1 AND en -> eo
z OR aa -> ab
bi LSHIFT 15 -> bm
hg OR hh -> hi
kh LSHIFT 1 -> lb
cg OR ch -> ci
1 AND kz -> la
gf OR ge -> gg
gj RSHIFT 2 -> gk
dd RSHIFT 2 -> de
NOT ls -> lt
lh OR li -> lj
jr OR js -> jt
au AND av -> ax
0 -> c
he AND hp -> hr
id AND if -> ig
et RSHIFT 5 -> ew
bp AND bq -> bs
e AND f -> h
ly OR lz -> ma
1 AND lu -> lv
NOT jd -> je
ha OR gz -> hb
dy RSHIFT 1 -> er
iu RSHIFT 2 -> iv
NOT hr -> hs
as RSHIFT 1 -> bl
kk RSHIFT 2 -> kl
b AND n -> p
ln AND lp -> lq
cj AND cp -> cr
dl AND dn -> do
ci RSHIFT 2 -> cj
as OR bd -> be
ge LSHIFT 15 -> gi
hz RSHIFT 5 -> ic
dv LSHIFT 1 -> ep
kl OR kr -> ks
gj OR gu -> gv
he RSHIFT 5 -> hh
NOT fg -> fh
hg AND hh -> hj
b OR n -> o
jk LSHIFT 15 -> jo
gz LSHIFT 15 -> hd
cy LSHIFT 15 -> dc
kk RSHIFT 5 -> kn
ci RSHIFT 3 -> ck
at OR az -> ba
iu RSHIFT 3 -> iw
ko AND kq -> kr
NOT eh -> ei
aq OR ar -> as
iy AND ja -> jb
dd RSHIFT 3 -> df
bn RSHIFT 3 -> bp
1 AND cc -> cd
at AND az -> bb
x OR ai -> aj
kk AND kv -> kx
ao OR an -> ap
dy RSHIFT 3 -> ea
x RSHIFT 1 -> aq
eu AND fa -> fc
kl AND kr -> kt
ia AND ig -> ii
df AND dg -> di
NOT fx -> fy
k AND m -> n
bn RSHIFT 5 -> bq
km AND kn -> kp
dt LSHIFT 15 -> dx
hz RSHIFT 2 -> ia
aj AND al -> am
cd LSHIFT 15 -> ch
hc OR hd -> he
he RSHIFT 3 -> hg
bn OR by -> bz
NOT kt -> ku
z AND aa -> ac
NOT ak -> al
cu AND cw -> cx
NOT ie -> if
dy RSHIFT 2 -> dz
ip LSHIFT 15 -> it
de OR dk -> dl
au OR av -> aw
jg AND ji -> jj
ci AND ct -> cv
dy RSHIFT 5 -> eb
hx OR hy -> hz
eu OR fa -> fb
gj RSHIFT 3 -> gl
fo AND fz -> gb
1 AND jj -> jk
jp OR ka -> kb
de AND dk -> dm
ex AND ez -> fa
df OR dg -> dh
iv OR jb -> jc
x RSHIFT 5 -> aa
NOT hj -> hk
NOT im -> in
fl LSHIFT 1 -> gf
hu LSHIFT 15 -> hy
iq OR ip -> ir
iu RSHIFT 5 -> ix
NOT fc -> fd
NOT el -> em
ck OR cl -> cm
et RSHIFT 3 -> ev
hw LSHIFT 1 -> iq
ci RSHIFT 5 -> cl
iv AND jb -> jd
dd RSHIFT 5 -> dg
as RSHIFT 2 -> at
NOT jy -> jz
af AND ah -> ai
1 AND ds -> dt
jx AND jz -> ka
da LSHIFT 1 -> du
fs AND fu -> fv
jp RSHIFT 1 -> ki
iw AND ix -> iz
iw OR ix -> iy
eo LSHIFT 15 -> es
ev AND ew -> ey
ba AND bc -> bd
fp AND fv -> fx
jc AND je -> jf
et RSHIFT 2 -> eu
kg OR kf -> kh
iu OR jf -> jg
er OR es -> et
fo RSHIFT 2 -> fp
NOT ca -> cb
bv AND bx -> by
u LSHIFT 1 -> ao
cm AND co -> cp
y OR ae -> af
bn AND by -> ca
1 AND ke -> kf
jt AND jv -> jw
fq OR fr -> fs
dy AND ej -> el
NOT kc -> kd
ev OR ew -> ex
dd OR do -> dp
NOT cv -> cw
gr AND gt -> gu
dd RSHIFT 1 -> dw
NOT gw -> gx
NOT iz -> ja
1 AND io -> ip
NOT ag -> ah
b RSHIFT 5 -> f
NOT cr -> cs
kb AND kd -> ke
jr AND js -> ju
cq AND cs -> ct
il AND in -> io
NOT ju -> jv
du OR dt -> dv
dd AND do -> dq
b RSHIFT 2 -> d
jm LSHIFT 1 -> kg
NOT dq -> dr
bo OR bu -> bv
gk OR gq -> gr
he OR hp -> hq
NOT h -> i
hf AND hl -> hn
gv AND gx -> gy
x AND ai -> ak
bo AND bu -> bw
hq AND hs -> ht
hz RSHIFT 1 -> is
gj RSHIFT 5 -> gm
g AND i -> j
gk AND gq -> gs
dp AND dr -> ds
b RSHIFT 3 -> e
gl AND gm -> go
gl OR gm -> gn
y AND ae -> ag
hv OR hu -> hw
1674 -> b
ab AND ad -> ae
NOT ac -> ad
1 AND ht -> hu
NOT hn -> ho

A  => day7/input2 +339 -0
@@ 1,339 @@
bn RSHIFT 2 -> bo
lf RSHIFT 1 -> ly
fo RSHIFT 3 -> fq
cj OR cp -> cq
fo OR fz -> ga
t OR s -> u
lx -> a
NOT ax -> ay
he RSHIFT 2 -> hf
lf OR lq -> lr
lr AND lt -> lu
dy OR ej -> ek
1 AND cx -> cy
hb LSHIFT 1 -> hv
1 AND bh -> bi
ih AND ij -> ik
c LSHIFT 1 -> t
ea AND eb -> ed
km OR kn -> ko
NOT bw -> bx
ci OR ct -> cu
NOT p -> q
lw OR lv -> lx
NOT lo -> lp
fp OR fv -> fw
o AND q -> r
dh AND dj -> dk
ap LSHIFT 1 -> bj
bk LSHIFT 1 -> ce
NOT ii -> ij
gh OR gi -> gj
kk RSHIFT 1 -> ld
lc LSHIFT 1 -> lw
lb OR la -> lc
1 AND am -> an
gn AND gp -> gq
lf RSHIFT 3 -> lh
e OR f -> g
lg AND lm -> lo
ci RSHIFT 1 -> db
cf LSHIFT 1 -> cz
bn RSHIFT 1 -> cg
et AND fe -> fg
is OR it -> iu
kw AND ky -> kz
ck AND cl -> cn
bj OR bi -> bk
gj RSHIFT 1 -> hc
iu AND jf -> jh
NOT bs -> bt
kk OR kv -> kw
ks AND ku -> kv
hz OR ik -> il
b RSHIFT 1 -> v
iu RSHIFT 1 -> jn
fo RSHIFT 5 -> fr
be AND bg -> bh
ga AND gc -> gd
hf OR hl -> hm
ld OR le -> lf
as RSHIFT 5 -> av
fm OR fn -> fo
hm AND ho -> hp
lg OR lm -> ln
NOT kx -> ky
kk RSHIFT 3 -> km
ek AND em -> en
NOT ft -> fu
NOT jh -> ji
jn OR jo -> jp
gj AND gu -> gw
d AND j -> l
et RSHIFT 1 -> fm
jq OR jw -> jx
ep OR eo -> eq
lv LSHIFT 15 -> lz
NOT ey -> ez
jp RSHIFT 2 -> jq
eg AND ei -> ej
NOT dm -> dn
jp AND ka -> kc
as AND bd -> bf
fk OR fj -> fl
dw OR dx -> dy
lj AND ll -> lm
ec AND ee -> ef
fq AND fr -> ft
NOT kp -> kq
ki OR kj -> kk
cz OR cy -> da
as RSHIFT 3 -> au
an LSHIFT 15 -> ar
fj LSHIFT 15 -> fn
1 AND fi -> fj
he RSHIFT 1 -> hx
lf RSHIFT 2 -> lg
kf LSHIFT 15 -> kj
dz AND ef -> eh
ib OR ic -> id
lf RSHIFT 5 -> li
bp OR bq -> br
NOT gs -> gt
fo RSHIFT 1 -> gh
bz AND cb -> cc
ea OR eb -> ec
lf AND lq -> ls
NOT l -> m
hz RSHIFT 3 -> ib
NOT di -> dj
NOT lk -> ll
jp RSHIFT 3 -> jr
jp RSHIFT 5 -> js
NOT bf -> bg
s LSHIFT 15 -> w
eq LSHIFT 1 -> fk
jl OR jk -> jm
hz AND ik -> im
dz OR ef -> eg
1 AND gy -> gz
la LSHIFT 15 -> le
br AND bt -> bu
NOT cn -> co
v OR w -> x
d OR j -> k
1 AND gd -> ge
ia OR ig -> ih
NOT go -> gp
NOT ed -> ee
jq AND jw -> jy
et OR fe -> ff
aw AND ay -> az
ff AND fh -> fi
ir LSHIFT 1 -> jl
gg LSHIFT 1 -> ha
x RSHIFT 2 -> y
db OR dc -> dd
bl OR bm -> bn
ib AND ic -> ie
x RSHIFT 3 -> z
lh AND li -> lk
ce OR cd -> cf
NOT bb -> bc
hi AND hk -> hl
NOT gb -> gc
1 AND r -> s
fw AND fy -> fz
fb AND fd -> fe
1 AND en -> eo
z OR aa -> ab
bi LSHIFT 15 -> bm
hg OR hh -> hi
kh LSHIFT 1 -> lb
cg OR ch -> ci
1 AND kz -> la
gf OR ge -> gg
gj RSHIFT 2 -> gk
dd RSHIFT 2 -> de
NOT ls -> lt
lh OR li -> lj
jr OR js -> jt
au AND av -> ax
0 -> c
he AND hp -> hr
id AND if -> ig
et RSHIFT 5 -> ew
bp AND bq -> bs
e AND f -> h
ly OR lz -> ma
1 AND lu -> lv
NOT jd -> je
ha OR gz -> hb
dy RSHIFT 1 -> er
iu RSHIFT 2 -> iv
NOT hr -> hs
as RSHIFT 1 -> bl
kk RSHIFT 2 -> kl
b AND n -> p
ln AND lp -> lq
cj AND cp -> cr
dl AND dn -> do
ci RSHIFT 2 -> cj
as OR bd -> be
ge LSHIFT 15 -> gi
hz RSHIFT 5 -> ic
dv LSHIFT 1 -> ep
kl OR kr -> ks
gj OR gu -> gv
he RSHIFT 5 -> hh
NOT fg -> fh
hg AND hh -> hj
b OR n -> o
jk LSHIFT 15 -> jo
gz LSHIFT 15 -> hd
cy LSHIFT 15 -> dc
kk RSHIFT 5 -> kn
ci RSHIFT 3 -> ck
at OR az -> ba
iu RSHIFT 3 -> iw
ko AND kq -> kr
NOT eh -> ei
aq OR ar -> as
iy AND ja -> jb
dd RSHIFT 3 -> df
bn RSHIFT 3 -> bp
1 AND cc -> cd
at AND az -> bb
x OR ai -> aj
kk AND kv -> kx
ao OR an -> ap
dy RSHIFT 3 -> ea
x RSHIFT 1 -> aq
eu AND fa -> fc
kl AND kr -> kt
ia AND ig -> ii
df AND dg -> di
NOT fx -> fy
k AND m -> n
bn RSHIFT 5 -> bq
km AND kn -> kp
dt LSHIFT 15 -> dx
hz RSHIFT 2 -> ia
aj AND al -> am
cd LSHIFT 15 -> ch
hc OR hd -> he
he RSHIFT 3 -> hg
bn OR by -> bz
NOT kt -> ku
z AND aa -> ac
NOT ak -> al
cu AND cw -> cx
NOT ie -> if
dy RSHIFT 2 -> dz
ip LSHIFT 15 -> it
de OR dk -> dl
au OR av -> aw
jg AND ji -> jj
ci AND ct -> cv
dy RSHIFT 5 -> eb
hx OR hy -> hz
eu OR fa -> fb
gj RSHIFT 3 -> gl
fo AND fz -> gb
1 AND jj -> jk
jp OR ka -> kb
de AND dk -> dm
ex AND ez -> fa
df OR dg -> dh
iv OR jb -> jc
x RSHIFT 5 -> aa
NOT hj -> hk
NOT im -> in
fl LSHIFT 1 -> gf
hu LSHIFT 15 -> hy
iq OR ip -> ir
iu RSHIFT 5 -> ix
NOT fc -> fd
NOT el -> em
ck OR cl -> cm
et RSHIFT 3 -> ev
hw LSHIFT 1 -> iq
ci RSHIFT 5 -> cl
iv AND jb -> jd
dd RSHIFT 5 -> dg
as RSHIFT 2 -> at
NOT jy -> jz
af AND ah -> ai
1 AND ds -> dt
jx AND jz -> ka
da LSHIFT 1 -> du
fs AND fu -> fv
jp RSHIFT 1 -> ki
iw AND ix -> iz
iw OR ix -> iy
eo LSHIFT 15 -> es
ev AND ew -> ey
ba AND bc -> bd
fp AND fv -> fx
jc AND je -> jf
et RSHIFT 2 -> eu
kg OR kf -> kh
iu OR jf -> jg
er OR es -> et
fo RSHIFT 2 -> fp
NOT ca -> cb
bv AND bx -> by
u LSHIFT 1 -> ao
cm AND co -> cp
y OR ae -> af
bn AND by -> ca
1 AND ke -> kf
jt AND jv -> jw
fq OR fr -> fs
dy AND ej -> el
NOT kc -> kd
ev OR ew -> ex
dd OR do -> dp
NOT cv -> cw
gr AND gt -> gu
dd RSHIFT 1 -> dw
NOT gw -> gx
NOT iz -> ja
1 AND io -> ip
NOT ag -> ah
b RSHIFT 5 -> f
NOT cr -> cs
kb AND kd -> ke
jr AND js -> ju
cq AND cs -> ct
il AND in -> io
NOT ju -> jv
du OR dt -> dv
dd AND do -> dq
b RSHIFT 2 -> d
jm LSHIFT 1 -> kg
NOT dq -> dr
bo OR bu -> bv
gk OR gq -> gr
he OR hp -> hq
NOT h -> i
hf AND hl -> hn
gv AND gx -> gy
x AND ai -> ak
bo AND bu -> bw
hq AND hs -> ht
hz RSHIFT 1 -> is
gj RSHIFT 5 -> gm
g AND i -> j
gk AND gq -> gs
dp AND dr -> ds
b RSHIFT 3 -> e
gl AND gm -> go
gl OR gm -> gn
y AND ae -> ag
hv OR hu -> hw
46065 -> b
ab AND ad -> ae
NOT ac -> ad
1 AND ht -> hu
NOT hn -> ho

A  => day7/src/main.rs +196 -0
@@ 1,196 @@
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use regex::Regex;
use std::io::BufRead;
use std::ops::Deref;

#[derive(Clone, Debug, PartialEq, Hash, Eq)]
enum Wire {
    Name(String),
    Value(u16),
}
/// struct Wire(String);

impl From<&str> for Wire {
    fn from(s: &str) -> Wire {
        match s.parse::<u16>() {
            Ok(v) => Wire::Value(v),
            Err(_) => Wire::Name(s.into()),
        }
    }
}

lazy_static! {
    static ref LIT : Regex =
        Regex::new(r"(\d+)").unwrap();
    static ref LIT_WIRE : Regex =
        Regex::new(r"([a-z]+)").unwrap();
    static ref BIN_OP : Regex =
        Regex::new(r"(.+) ([A-Z]+) (.+)").unwrap();
    static ref NOT : Regex =
        Regex::new(r"NOT ([a-z]+)").unwrap();
    static ref INST : Regex =
        Regex::new(r"(.+) -> (.+)").unwrap();
}

#[derive(Clone, Debug, PartialEq, Hash, Eq)]
enum Expr {
    Lit(u16),
    Wire(Wire),
    And(Wire, Wire),
    Or(Wire, Wire),
    LShift(Wire, u16),
    RShift(Wire, u16),
    Not(Wire),
}

impl From<&str> for Expr {
    fn from(s: &str) -> Expr {
        if let Some(c) = BIN_OP.captures(s) {
            match &c[2] {
                "AND" => {
                    return Expr::And(c[1].into(), c[3].into());
                },
                "OR" => {
                    return Expr::Or(c[1].into(), c[3].into());
                },
                "LSHIFT" => {
                    return Expr::LShift(c[1].into(), c[3].parse().unwrap());
                },
                "RSHIFT" => {
                    return Expr::RShift(c[1].into(), c[3].parse().unwrap());
                },
                s => {
                    dbg!(s);
                    unimplemented!()
                }
            }
        }
        if let Some(c) = NOT.captures(s) {
            return Expr::Not(c[1].into());
        }
        if let Some(c) = LIT.captures(s) {
            return Expr::Lit(c[1].parse().unwrap())
        }
        if let Some(c) = LIT_WIRE.captures(s) {
            return Expr::Wire(c[1].into());
        }
        dbg!(s);
        unimplemented!()
    }
}

#[test]
fn expr_from() {
    assert_eq!(Expr::Lit(123), "123".into());
    assert_eq!(Expr::And(Wire("ab".into()), Wire("b".into())), "ab AND b".into());
    assert_eq!(Expr::Or(Wire("c".into()), Wire("d".into())), "c OR d".into());
    assert_eq!(Expr::LShift(Wire("e".into()), 4), "e LSHIFT 4".into());
    assert_eq!(Expr::RShift(Wire("f".into()), 8), "f RSHIFT 8".into());
    assert_eq!(Expr::Not(Wire("g".into())), "NOT g".into());
}

#[derive(Clone, Debug, PartialEq, Hash, Eq)]
struct Instruction {
    expr: Expr,
    dest: Wire,
}

impl From<&str> for Instruction {
    fn from(s: &str) -> Instruction {
        let cap = INST.captures(s).unwrap();
        Instruction{expr: cap[1].into(), dest: cap[2].into()}
    }
}

#[test]
fn inst_from() {
    assert_eq!(Instruction{expr: Expr::And(Wire("a".into()), Wire("b".into())), dest: Wire("c".into())},
        "a AND b -> c".into());
}

#[derive(Clone, Debug, PartialEq, Hash, Eq)]
enum Either {
    Expr(Expr),
    Value(u16),
}

fn eval(mut state: &mut HashMap<Wire, Either>, start: &Wire) -> u16 {
    if let Wire::Value(n) = start {
        return *n;
    }
    let value : Either = state.get(start).unwrap().clone();
    match value {
        Either::Value(n) => { 
            state.insert(start.clone(), Either::Value(n));
            return n;
        }
        Either::Expr(e) => {
            use Expr::*;
            match e {
                Lit(n) => { 
                    state.insert(start.clone(), Either::Value(n));
                    return n;
                }
                Wire(w) => {
                    let val = eval(&mut state, &w);
                    state.insert(start.clone(), Either::Value(val));
                    return val;
                }
                And(l, r) => {
                    let lv = eval(&mut state, &l);
                    let rv = eval(&mut state, &r);
                    let val = lv & rv;
                    state.insert(start.clone(), Either::Value(val));
                    return val
                }
                Or(l, r) => {
                    let lv = eval(&mut state, &l);
                    let rv = eval(&mut state, &r);
                    let val = lv | rv;
                    state.insert(start.clone(), Either::Value(val));
                    return val
                }
                LShift(l, r) => {
                    let lv = eval(&mut state, &l);
                    let val = lv << r;
                    state.insert(start.clone(), Either::Value(val));
                    return val
                }
                RShift(l, r) => {
                    let lv = eval(&mut state, &l);
                    let val = lv >> r;
                    state.insert(start.clone(), Either::Value(val));
                    return val
                }
                Not(w) => {
                    let wv = eval(&mut state, &w);
                    let val = !wv;
                    state.insert(start.clone(), Either::Value(val));
                    return val
                }
                _ => unimplemented!()
            }
        },
    };
    println!("{:?}", state);
    unimplemented!()
}

fn main() {
    let all : Vec<Instruction> = std::io::BufReader::new(std::io::stdin())
        .lines()
        .map(|s| s.unwrap())
        .map(|s| s.deref().into())
        .collect();
    let mut map = HashMap::new();
    for inst in all {
        map.insert(inst.dest, Either::Expr(inst.expr));
    }
    let mut state = map.clone();
    let aval = dbg!(eval(&mut state, &Wire::Name("a".into())));
    map.insert(Wire::Name("b".into()), Either::Value(aval));
    let mut state = map.clone();
    let aval = dbg!(eval(&mut state, &Wire::Name("a".into())));
}

A  => day_4/Cargo.toml +7 -0
@@ 1,7 @@
[package]
name = "day_4"
version = "0.1.0"
authors = ["Tomasz Kłak <tomasz@tomaszklak.pl>"]

[dependencies]
md5 = "0.3.6"

A  => day_4/src/main.rs +17 -0
@@ 1,17 @@
extern crate md5;

fn solve(prefix: &str, dificulty: &str) -> i32 {
    for i in 1.. {
        let candidate = format!("{}{}", prefix, i);
        let dig = md5::compute(candidate);
        if format!("{:x}", dig).starts_with(dificulty) {
            return i
        }
    }
    unreachable!();
}

fn main() {
    println!("{}", solve("bgvyzdsv", "00000"));
    println!("{}", solve("bgvyzdsv", "000000"));
}