summaryrefslogtreecommitdiff
path: root/2018/src/day12.rs
diff options
context:
space:
mode:
Diffstat (limited to '2018/src/day12.rs')
-rw-r--r--2018/src/day12.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/2018/src/day12.rs b/2018/src/day12.rs
new file mode 100644
index 0000000..6ec0772
--- /dev/null
+++ b/2018/src/day12.rs
@@ -0,0 +1,136 @@
+use std::io;
+use std::io::BufRead;
+use std::cmp::min;
+use std::mem::swap;
+
+fn bits_to_u8(bits: &[u8]) -> u8 {
+ (0..min(bits.len(), 8)).map(|i| if bits[i] == '#' as u8 { 1 << i } else { 0 }).sum()
+}
+
+fn getbit(bits: &[u8], idx: usize) -> u8 {
+ (bits[idx / 8] & 1 << idx % 8) >> idx % 8
+}
+
+fn evolve(board: &[u8], out: &mut [u8], patdict: &[u8; 1 << 5]) {
+ assert!(board.len() == out.len());
+
+ let mut pat = board[0] & 0x1f;
+ for i in 2..8*out.len()-2 {
+ let bit = patdict[pat as usize];
+
+ // for i in 0..5 { print!("{}", if (pat & 1 << i) != 0 { '#' } else { '.' }); }
+ // println!(" {}", bit);
+
+ out[i / 8] = out[i / 8] & !(1 << i % 8) | bit << i % 8;
+
+ if i == 8 * out.len() - 3 { break; }
+ pat = pat >> 1 | getbit(board, i + 3) << 4;
+ }
+}
+
+#[allow(dead_code)]
+fn print_board(board: &[u8]) {
+ for i in 0..8*board.len() {
+ let bit = board[i / 8] & (1 << (i % 8));
+ print!("{}", if bit != 0 { '#' } else { '.' });
+ }
+
+ println!("");
+}
+
+fn board_sum(board: &[u8], zeroidx: i64) -> i64 {
+ let mut numsum = 0;
+ for i in 0..8*board.len() {
+ if (board[i / 8] & 1 << i % 8) != 0 {
+ numsum += i as i64 - 8 * zeroidx as i64;
+ }
+ }
+ numsum
+}
+
+fn make_board(init_str: &str, niters: usize) -> (Vec<u8>, usize) {
+ let slack = 2 * niters + 2;
+
+ let zeroidx = (slack + 7) / 8;
+ let mut board = vec![0; zeroidx + (init_str.len() + slack + 7) / 8];
+
+ for i in 0..(init_str.len() + 7) / 8 {
+ board[zeroidx + i] = bits_to_u8(&init_str.as_bytes()[8*i..min(8*i+8, init_str.len())]);
+ }
+
+ (board, zeroidx)
+}
+
+struct Repetition {
+ generation: usize,
+ score: i64,
+ increment: i64,
+}
+
+fn findrep(init_str: &str, patdict: &[u8; 1 << 5]) -> Repetition {
+ let niters = 1000;
+
+ let (mut board, zeroidx) = make_board(init_str, niters);
+ let mut board2 = vec![0; board.len()];
+
+ let mut prevscore = 0;
+ let mut previncr = 0;
+ let mut streak = 0;
+
+ for generation in 1..niters+1 {
+ evolve(&board, &mut board2, &patdict);
+ swap(&mut board, &mut board2);
+
+ let score = board_sum(&board, zeroidx as i64);
+ let increment = score - prevscore;
+ if increment == previncr {
+ streak += 1;
+ if streak > 10 {
+ return Repetition { generation, score, increment };
+ }
+ } else {
+ streak = 0;
+ }
+
+ prevscore = score;
+ previncr = increment;
+ }
+
+ unreachable!();
+}
+
+fn simulate(init_str: &str, niters: usize, patdict: &[u8; 1 << 5]) -> i64 {
+ let (mut board, zeroidx) = make_board(init_str, niters);
+ let mut board2 = vec![0; board.len()];
+
+ for _ in 0..niters {
+ evolve(&board, &mut board2, &patdict);
+ swap(&mut board, &mut board2);
+ }
+
+ board_sum(&board, zeroidx as i64)
+}
+
+pub fn main<T: BufRead>(reader: T) -> io::Result<(String, String)> {
+ let mut lines_iter = reader.lines();
+ let init_str = &lines_iter.next().unwrap().unwrap().clone()[15..];
+
+ let patdict = {
+ let mut patdict = [0; 1 << 5];
+ lines_iter.next();
+ for line in lines_iter {
+ let line = line.unwrap();
+ let pat = bits_to_u8(&line.as_bytes()[0..5]);
+ let res = bits_to_u8(&line.as_bytes()[9..10]);
+ patdict[pat as usize] = res;
+ }
+ patdict
+ };
+
+ let part1 = simulate(&init_str, 20, &patdict).to_string();
+
+ let rep = findrep(&init_str, &patdict);
+ let part2 = (rep.score + (50000000000 - rep.generation as i64) * rep.increment).to_string();
+
+ Ok((part1, part2))
+}