From eec91476dc9129ba72b4da4ba999ea6c3902082b Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 16 Dec 2024 22:48:56 -0800 Subject: [PATCH] add: broken stuff --- src/bin/d13p1.rs | 20 +++-- src/bin/d14p1.rs | 135 +++++++++++++++++++++++++++++++ src/bin/d14p1.txt | 12 +++ src/bin/d15i1.txt | 21 +++++ src/bin/d15i2.txt | 10 +++ src/bin/d15p1.rs | 189 +++++++++++++++++++++++++++++++++++++++++++ src/bin/d16i1.txt | 15 ++++ src/bin/d16i2.txt | 17 ++++ src/bin/d16p1.rs | 202 ++++++++++++++++++++++++++++++++++++++++++++++ src/bin/d17i1.txt | 5 ++ src/bin/d17i2.txt | 5 ++ src/bin/d17p1.rs | 172 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 10 +++ 13 files changed, 802 insertions(+), 11 deletions(-) create mode 100644 src/bin/d14p1.rs create mode 100644 src/bin/d14p1.txt create mode 100644 src/bin/d15i1.txt create mode 100644 src/bin/d15i2.txt create mode 100644 src/bin/d15p1.rs create mode 100644 src/bin/d16i1.txt create mode 100644 src/bin/d16i2.txt create mode 100644 src/bin/d16p1.rs create mode 100644 src/bin/d17i1.txt create mode 100644 src/bin/d17i2.txt create mode 100644 src/bin/d17p1.rs diff --git a/src/bin/d13p1.rs b/src/bin/d13p1.rs index 449b3fa..427d818 100644 --- a/src/bin/d13p1.rs +++ b/src/bin/d13p1.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use advent_of_code_2024::{make_main, next, Pair, SResult}; use good_lp::{ - coin_cbc, constraint::{self, eq}, variable, variables, Constraint, Expression, ProblemVariables, + coin_cbc, constraint::{self, eq, geq, leq}, variable, variables, Constraint, Expression, ProblemVariables, Solution, SolverModel, WithMipGap, }; use regex::Regex; @@ -30,11 +30,7 @@ fn solve(lines: Vec) -> SResult<(usize, usize)> { let xpos = caps["xpos"].parse::().unwrap(); let ypos = caps["ypos"].parse::().unwrap(); total += solve2(&buttons, (xpos, ypos)); - let ans2 = solve2(&buttons, (xpos + 10000000000000, ypos + 10000000000000)); - if ans2 > 0 { - println!("Solved for pos {}, {}", xpos, ypos); - } - total2 += ans2; + total2 += solve2(&buttons, (xpos + 10000000000000, ypos + 10000000000000)); } } Ok((total, total2)) @@ -51,17 +47,19 @@ fn solve2(buttons: &HashMap, prize: Pair) -> usize { 0 <= b (integer) ; } + let prec = 0.001; + let sol = match vars2.minimise(a * 3 + b) .using(coin_cbc) - .with(eq(a*ax+b*bx, prize.0 as f64)) - .with(eq(a*ay+b*by, prize.1 as f64)) + .with(geq((a+prec)*ax+(b+prec)*bx, prize.0 as f64)) + .with(leq((a-prec)*ax+(b-prec)*bx, prize.0 as f64)) + .with(geq((a+prec)*ay+(b+prec)*by, prize.1 as f64)) + .with(leq((a-prec)*ay+(b-prec)*by, prize.1 as f64)) .solve() { Ok(s) => s, Err(_) => return 0, }; - println!("a {}", sol.value(a)); - println!("b {}", sol.value(b)); let a = sol.value(a).round() as usize; let b = sol.value(b).round() as usize; @@ -84,6 +82,6 @@ mod tests { fn lp_solve() { let strings: Vec = input!("d13p1.txt"); let got = solve(strings).unwrap(); - assert_eq!(got, (480, 0)); + assert_eq!(got, (480, 875318608908)); } } diff --git a/src/bin/d14p1.rs b/src/bin/d14p1.rs new file mode 100644 index 0000000..fa2b367 --- /dev/null +++ b/src/bin/d14p1.rs @@ -0,0 +1,135 @@ +use std::{ + collections::{HashMap, HashSet}, + thread, + time::Duration, +}; + +use advent_of_code_2024::{make_main, next, Pair, SResult}; +use regex::Regex; + +make_main!(); + +fn solve(lines: Vec) -> SResult<(usize, usize)> { + // NOTE: this needs to be adjusted for the size of the grid + let dims = (101, 103); + let pos_regex = Regex::new(r"p=(?\d+),(?\d+) v=(?-?\d+),(?-?\d+)").unwrap(); + let mut robots = vec![]; + for line in lines { + let caps = pos_regex.captures(&line.trim()).unwrap(); + let x = caps["x"].parse::().unwrap(); + let y = caps["y"].parse::().unwrap(); + let xvel = caps["xvel"].parse::().unwrap(); + let yvel = caps["yvel"].parse::().unwrap(); + robots.push(Robot { + vel: (xvel, yvel), + pos: (x, y), + }) + } + + // Simulation GO + // 79, 388, 491, 697, 800, 903, 1006, 1109, 1212, 1315 + let millis = Duration::from_millis(10); + let mut n = 0; + let mut tens = 11usize; + let mut ones = 24usize; + loop { + if (n / 100 == tens && n % 100 == ones) || (n >= 800 && (n - 800) % 103 == 0) { + print!("{}[2J", 27 as char); + println!("{}", n); + print_grid(&robots, dims); + if (n / 100 == tens && n % 100 == ones) { + tens += 1; + ones += 1; + } + thread::sleep(millis); + } + n += 1; + for robot in robots.iter_mut() { + robot.advance(dims); + } + } + //Ok((calc_safety(&robots, dims).iter().fold(1, |x, y| x * y), 0)) +} + +#[derive(Debug)] +struct Robot { + vel: Pair, + pos: Pair, +} + +impl Robot { + fn advance(&mut self, dims: Pair) { + self.pos.0 = roll(self.pos.0, self.vel.0, dims.0); + self.pos.1 = roll(self.pos.1, self.vel.1, dims.1); + } +} + +fn roll(pos: usize, vel: i64, dim: usize) -> usize { + let ipos = pos as i64; + if ipos + vel >= 0 { + ((ipos + vel) as usize) % dim + } else { + ((ipos + vel) + dim as i64) as usize + } +} + +fn calc_safety(robots: &[Robot], dims: Pair) -> [usize; 4] { + let mut scores = [0usize; 4]; + for robot in robots { + let xhalf = part(robot.pos.0, dims.0); + let yhalf = part(robot.pos.1, dims.1); + match (xhalf, yhalf) { + (0, 0) => scores[0] += 1, + (0, 1) => scores[1] += 1, + (1, 0) => scores[2] += 1, + (1, 1) => scores[3] += 1, + _ => { + // Do nothing; this is expected + } + } + } + scores +} + +fn part(pos: usize, dim: usize) -> usize { + if pos < dim / 2 { + 0 + } else if pos > dim / 2 { + 1 + } else { + 2 + } +} + +fn print_grid(robots: &[Robot], dims: Pair) { + println!(""); + let mut pos = HashMap::new(); + for rob in robots { + *pos.entry(rob.pos).or_insert(0) += 1; + } + for j in 0..dims.1 { + for i in 0..dims.0 { + if let Some(count) = pos.get(&(i, j)) { + print!("{}", count); + } else { + print!(" "); + } + } + println!(""); + } + println!(""); +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn d14p1() { + return; + let strings: Vec = input!("d14p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (12, 0)); + } +} diff --git a/src/bin/d14p1.txt b/src/bin/d14p1.txt new file mode 100644 index 0000000..72a324a --- /dev/null +++ b/src/bin/d14p1.txt @@ -0,0 +1,12 @@ +p=0,4 v=3,-3 +p=6,3 v=-1,-3 +p=10,3 v=-1,2 +p=2,0 v=2,-1 +p=0,0 v=1,3 +p=3,0 v=-2,-2 +p=7,6 v=-1,-3 +p=3,0 v=-1,-2 +p=9,3 v=2,3 +p=7,3 v=-1,2 +p=2,4 v=2,-3 +p=9,5 v=-3,-3 \ No newline at end of file diff --git a/src/bin/d15i1.txt b/src/bin/d15i1.txt new file mode 100644 index 0000000..b2bce78 --- /dev/null +++ b/src/bin/d15i1.txt @@ -0,0 +1,21 @@ +########## +#..O..O.O# +#......O.# +#.OO..O.O# +#..O@..O.# +#O#..O...# +#O..O..O.# +#.OO.O.OO# +#....O...# +########## + +^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^ +vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv< +<>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ +^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^>< +^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ +<><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> +^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<>< +v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^ \ No newline at end of file diff --git a/src/bin/d15i2.txt b/src/bin/d15i2.txt new file mode 100644 index 0000000..c6138ff --- /dev/null +++ b/src/bin/d15i2.txt @@ -0,0 +1,10 @@ +######## +#..O.O.# +##@.O..# +#...O..# +#.#.O..# +#...O..# +#......# +######## + +<^^>>>vv>v<< \ No newline at end of file diff --git a/src/bin/d15p1.rs b/src/bin/d15p1.rs new file mode 100644 index 0000000..a1d3d38 --- /dev/null +++ b/src/bin/d15p1.rs @@ -0,0 +1,189 @@ +use std::{ + collections::{HashMap, HashSet}, + thread, + time::Duration, +}; + +use advent_of_code_2024::{make_main, next, next2, Pair, SResult}; +use regex::Regex; + +make_main!(); + +fn solve(lines: Vec) -> SResult<(usize, usize)> { + // Read in the grid + let mut grid: Vec> = Vec::with_capacity(lines.len()); + let mut grid2: Vec> = Vec::with_capacity(lines.len()); + for line in &lines { + if line.trim() == "" { + break; + } + let mut row = Vec::with_capacity(line.len()); + let mut row2 = Vec::with_capacity(2 * line.len()); + for c in line.trim().chars() { + row.push(c); + match c { + '#' => { + row2.push('#'); + row2.push('#'); + } + 'O' => { + row2.push('['); + row2.push(']'); + } + '.' => { + row2.push('.'); + row2.push('.'); + } + '@' => { + row2.push('@'); + row2.push('.'); + } + c => panic!("unknown char: {}", c), + } + } + grid.push(row); + grid2.push(row2); + } + assert_eq!(grid.len(), grid[0].len()); + + // Read in the rest of the puzzle + let mut actions = Vec::new(); + for line in &lines[grid.len() + 1..] { + for char in line.trim().chars() { + actions.push(char); + } + } + + // Find starting position + let mut pos = find_pos(&grid); + let mut pos2 = find_pos(&grid2); + + for action in actions { + let mut temp_grid = grid.clone(); + if let Some(new_pos) = mov(pos, vel(action), &mut temp_grid) { + grid = temp_grid; + grid[pos.0][pos.1] = '.'; + pos = new_pos; + grid[pos.0][pos.1] = '@'; + } + let mut temp_grid = grid2.clone(); + if let Some(new_pos) = mov(pos2, vel(action), &mut temp_grid) { + grid2 = temp_grid; + grid2[pos2.0][pos2.1] = '.'; + pos2 = new_pos; + grid2[pos2.0][pos2.1] = '@'; + } + } + Ok((sum(&grid), sum(&grid2))) +} + +// attempts to move; returns false if it can't be done +fn mov(pos: Pair, vel: Pair, grid: &mut [Vec]) -> Option { + if grid[pos.0][pos.1] == '.' { + return Some(pos); + } + if grid[pos.0][pos.1] == '#' { + return None; + } + let mut to_move = vec![(pos, grid[pos.0][pos.1])]; + if grid[pos.0][pos.1] == '[' && vel.0 != 0 { + assert_eq!(grid[pos.0][pos.1+1], ']'); + let pos = (pos.0, pos.1 + 1); + to_move.push((pos, grid[pos.0][pos.1])); + } else if grid[pos.0][pos.1] == ']' && vel.0 != 0 { + assert_eq!(grid[pos.0][pos.1-1], '['); + let pos = (pos.0, pos.1 - 1); + to_move.push((pos, grid[pos.0][pos.1])); + } + let mut valid = true; + let mut moved_pos = pos; + for pos in to_move { + let next = if let Some(n) = next2(pos.0, vel, (grid.len(), grid[0].len())) { + n + } else { + valid = false; + break; + }; + if let Some(_) = mov(next, vel, grid) { + let old_char = pos.1; + let pos = pos.0; + grid[next.0][next.1] = grid[pos.0][pos.1]; + // assert that the previous position did not change; + // in case of a stack that somehow cycles (not sure how this could happen?) + assert_eq!(old_char, grid[pos.0][pos.1]); + grid[pos.0][pos.1] = '.'; + moved_pos = next; + } else { + valid = false; + break; + } + } + if valid { + Some(moved_pos) + } else { + None + } +} + +fn find_pos(grid: &[Vec]) -> Pair { + for i in 0..grid.len() { + for j in 0..grid[i].len() { + if grid[i][j] == '@' { + return (i, j); + } + } + } + panic!("No @ found"); +} + +fn vel(m: char) -> Pair { + match m { + '>' => (0, 1), + '<' => (0, -1), + '^' => (-1, 0), + 'v' => (1, 0), + c => panic!("not implemented: {}", c), + } +} + +fn sum(grid: &[Vec]) -> usize { + let mut sum = 0; + for i in 0..grid.len() { + for j in 0..grid[i].len() { + if grid[i][j] == 'O' || grid[i][j] == '[' { + sum += 100 * i + j; + } + } + } + sum +} + +fn print_grid(grid: &[Vec]) { + println!(""); + for i in 0..grid.len() { + for j in 0..grid[i].len() { + print!("{}", grid[i][j]); + } + println!(""); + } +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn d15i1() { + let strings: Vec = input!("d15i1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (10092, 9021)); + } + #[test] + fn d15i2() { + return; + let strings: Vec = input!("d15i2.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (2028, 105)); + } +} diff --git a/src/bin/d16i1.txt b/src/bin/d16i1.txt new file mode 100644 index 0000000..6a5bb85 --- /dev/null +++ b/src/bin/d16i1.txt @@ -0,0 +1,15 @@ +############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +############### \ No newline at end of file diff --git a/src/bin/d16i2.txt b/src/bin/d16i2.txt new file mode 100644 index 0000000..54f4cd7 --- /dev/null +++ b/src/bin/d16i2.txt @@ -0,0 +1,17 @@ +################# +#...#...#...#..E# +#.#.#.#.#.#.#.#.# +#.#.#.#...#...#.# +#.#.#.#.###.#.#.# +#...#.#.#.....#.# +#.#.#.#.#.#####.# +#.#...#.#.#.....# +#.#.#####.#.###.# +#.#.#.......#...# +#.#.###.#####.### +#.#.#...#.....#.# +#.#.#.#####.###.# +#.#.#.........#.# +#.#.#.#########.# +#S#.............# +################# \ No newline at end of file diff --git a/src/bin/d16p1.rs b/src/bin/d16p1.rs new file mode 100644 index 0000000..1ad58e9 --- /dev/null +++ b/src/bin/d16p1.rs @@ -0,0 +1,202 @@ +use std::{ + cmp::min, + collections::{HashMap, HashSet, VecDeque}, + thread, + time::Duration, + usize, +}; + +use advent_of_code_2024::{make_main, mul_pair, next, next2, Pair, SResult}; +use regex::Regex; + +make_main!(); + +fn solve(lines: Vec) -> SResult<(usize, usize)> { + // Read in the grid + let mut grid: Vec> = Vec::with_capacity(lines.len()); + let mut start = (0, 0); + let mut end = (0, 0); + for (i, line) in lines.iter().enumerate() { + let mut row = Vec::with_capacity(lines[i].len()); + for (j, c) in line.chars().enumerate() { + row.push(c); + if c == 'S' { + start = (i, j); + } + if c == 'E' { + end = (i, j); + } + } + grid.push(row); + } + + assert_eq!(grid.len(), grid[0].len()); + let width = grid.len(); + + // Create a map of the cells we visited, and how long it took to get there + let visited: HashMap<(char, Pair), usize> = make_visited(start, end, &grid); + + // Find the best answer for end + let ans = min_score(end, &visited); + + // We will walk backward through the tiles to find all paths + let mut best_tiles: HashSet = HashSet::new(); + best_tiles.insert(end); + // Find all 'angles' of the starting pos which had the best score + let mut stack: Vec<(char, (usize, usize))> = vec![ + ('>', end), + ('<', end), + ('v', end), + ('^', end), + ] + .into_iter() + .filter(|(angle, pos)| *visited.get(&(*angle, *pos)).unwrap_or(&usize::MAX) == ans) + .collect(); + + // Loop through the stack + while let Some((old_angle, pos)) = stack.pop() { + if pos == start { + continue; + } + // Find the best score + let mut best_score = usize::MAX; + for angle in angles() { + let vel = mul_pair(vel(angle), -1); + if let Some(pos) = next(pos, vel, width) { + let mut score = *visited.get(&(angle, pos)).unwrap_or(&usize::MAX); + if angle != old_angle && score != usize::MAX { + if next_angle(angle).contains(&old_angle) { + score += 1000; + } else { + score += 2000; + } + } + if score < best_score { + best_score = score; + } + } + } + // Find the 'angles' of this tile that had the best score + for angle in angles() { + let vel = mul_pair(vel(angle), -1); + if let Some(pos) = next(pos, vel, width) { + let mut score = *visited.get(&(angle, pos)).unwrap_or(&usize::MAX); + if angle != old_angle && score != usize::MAX { + if next_angle(angle).contains(&old_angle) { + score += 1000; + } else { + score += 2000; + } + } + if score == best_score && !best_tiles.contains(&pos) { + stack.push((angle, pos)); + best_tiles.insert(pos); + grid[pos.0][pos.1] = 'O'; + } + } + } + } + + Ok((ans, best_tiles.len())) +} + +fn angles() -> [char; 4] { + ['<', '>', '^', 'v'] +} + +fn min_score(end: Pair, visited: &HashMap<(char, Pair), usize>) -> usize { + *min( + visited.get(&('<', end)).unwrap_or(&usize::MAX), + min( + visited.get(&('>', end)).unwrap_or(&usize::MAX), + min( + visited.get(&('^', end)).unwrap_or(&usize::MAX), + visited.get(&('v', end)).unwrap_or(&usize::MAX), + ), + ), + ) +} + +fn make_visited(start: Pair, end: Pair, grid: &[Vec]) -> HashMap<(char, (usize, usize)), usize> { + let width = grid.len(); + let mut visited: HashMap<(char, Pair), usize> = HashMap::default(); + let mut stack = vec![('>', 0, start)]; + while let Some((angle, score, pos)) = stack.pop() { + if pos == end { + let entry = visited.entry((angle, pos)).or_insert(usize::MAX); + if *entry > score { + *entry = score; + } + continue; + } + + // Try going forward + if let Some(next) = next(pos, vel(angle), width) { + let prev_score = visited.get(&(angle, next)).unwrap_or(&usize::MAX); + let new_score = score + 1; + if grid[next.0][next.1] != '#' && *prev_score >= new_score { + stack.push((angle, new_score, next)); + visited.insert((angle, next), new_score); + } + } + + // Try rotation left, right + for angle in next_angle(angle) { + let prev_score = visited.get(&(angle, pos)).unwrap_or(&usize::MAX); + let new_score = score + 1000; + if *prev_score >= new_score { + stack.push((angle, new_score, pos)); + visited.insert((angle, pos), new_score); + } + } + } + visited +} + +fn vel(m: char) -> Pair { + match m { + '>' => (0, 1), + '<' => (0, -1), + '^' => (-1, 0), + 'v' => (1, 0), + c => panic!("not implemented: {}", c), + } +} + +fn next_angle(m: char) -> [char; 2] { + match m { + '<' | '>' => ['^', 'v'], + 'v' | '^' => ['<', '>'], + c => panic!("not implemented: {}", c), + } +} + +fn print_grid(grid: &[Vec]) { + println!(""); + for i in 0..grid.len() { + for j in 0..grid[i].len() { + print!("{}", grid[i][j]); + } + println!(""); + } +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn d16i1() { + let strings: Vec = input!("d16i1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (7036, 45)); + } + + #[test] + fn d16i2() { + let strings: Vec = input!("d16i2.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (11048, 64)); + } +} diff --git a/src/bin/d17i1.txt b/src/bin/d17i1.txt new file mode 100644 index 0000000..4a91c26 --- /dev/null +++ b/src/bin/d17i1.txt @@ -0,0 +1,5 @@ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,3,5,4,3,0 diff --git a/src/bin/d17i2.txt b/src/bin/d17i2.txt new file mode 100644 index 0000000..36fbf8d --- /dev/null +++ b/src/bin/d17i2.txt @@ -0,0 +1,5 @@ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 \ No newline at end of file diff --git a/src/bin/d17p1.rs b/src/bin/d17p1.rs new file mode 100644 index 0000000..aa51bba --- /dev/null +++ b/src/bin/d17p1.rs @@ -0,0 +1,172 @@ +use std::{collections::{HashMap, HashSet}, process::exit, thread, time::Duration}; + +use advent_of_code_2024::{make_main, SResult}; +use regex::Regex; +use threadpool::ThreadPool; + +make_main!(); + +struct State<'a> { + registers: [usize; 3], + pointer: usize, + program: &'a [usize], +} + +impl<'a> State<'a> { + fn new(program: &'a [usize], registers: [usize; 3]) -> Self { + Self { + registers, + pointer: 0, + program, + } + } + + fn run_to_end(&mut self) -> Vec { + let mut results = vec![]; + let mut i = 0; + while self.pointer < self.program.len() { + if let Some(val) = self.opcode() { + if val != self.program[i] { + break; + } + results.push(val); + i += 1; + if i == self.program.len() { + break; + } + } + } + results + } + + // Processes opcode and returns the program pointer + fn opcode(&mut self) -> Option { + let opcode = self.program[self.pointer]; + let operand = self.program[self.pointer + 1]; + match opcode { + 0 => { + self.registers[0] = self.registers[0] / (usize::pow(2, self.combo(operand) as u32)); + self.pointer += 2 + } + 1 => { + self.registers[1] = self.registers[1] ^ operand; + self.pointer += 2 + } + 2 => { + self.registers[1] = self.combo(operand) % 8; + self.pointer += 2 + } + 3 => { + if self.registers[0] == 0 { + self.pointer += 2 + } else { + self.pointer = operand; + } + } + 4 => { + self.registers[1] = self.registers[1] ^ self.registers[2]; + self.pointer += 2 + } + 5 => { + self.pointer += 2; + return Some(self.combo(operand) % 8); + } + 6 => { + self.registers[1] = self.registers[0] / (usize::pow(2, self.combo(operand) as u32)); + self.pointer += 2 + } + 7 => { + self.registers[2] = self.registers[0] / (usize::pow(2, self.combo(operand) as u32)); + self.pointer += 2 + } + _ => unimplemented!(), + }; + None + } + fn combo(&self, val: usize) -> usize { + match val { + 0..4 => val, + 4 => self.registers[0], + 5 => self.registers[1], + 6 => self.registers[2], + _ => unimplemented!(), + } + } +} + +fn solve(lines: Vec) -> SResult<(usize, usize)> { + let mut registers: HashMap = HashMap::default(); + + let regex = Regex::new(r"Register (\w+): (\d+)").unwrap(); + let mut i = 0; + while i < lines.len() && lines[i].trim() != "" { + let caps = regex.captures(&lines[i]).unwrap(); + i += 1; + registers.insert(caps[1].into(), caps[2].parse().unwrap()); + } + i += 1; + let program: Vec = lines[i] + .strip_prefix("Program: ") + .unwrap() + .split(",") + .map(|s| s.parse().unwrap()) + .collect(); + let values = + State::new(&program, [registers["A"], registers["B"], registers["C"]]).run_to_end(); + for (i, n) in values.iter().enumerate() { + if i > 0 { + print!(","); + } + print!("{}", n); + } + println!(); + + let pool = ThreadPool::new(20); + //let mut n = 3536000000; + let mut n = 0; + let program: &'static mut [usize] = program.leak(); + loop { + { + let n = n; + let program: &'static [usize] = program; + pool.execute(move || { + let values = State::new(&program, [n, 0, 0]).run_to_end(); + if values.len() > 4 { + println!("{} => {:?}", n, values); + } + while &values == program { + println!("finished at {}", n); + //exit(n as i32); + } + }); + } + n += 1; + if n % 1000000 == 0 { + println!("n = {}", n); + } + while pool.queued_count() > 10000 { + thread::sleep(Duration::from_millis(10)); + } + } + Ok((values.len(), n)) +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn d17i1() { + let strings: Vec = input!("d17i1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (4, 117440)); + } + #[test] + fn d17i2() { + return; + let strings: Vec = input!("d17i2.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (4, 117440)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 7f4e45f..f484062 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,16 @@ pub fn next((x, y): Pair, (xvel, yvel): Pair, width: usize) -> Option } } +pub fn next2((x, y): Pair, (xvel, yvel): Pair, (width, height): Pair) -> Option { + let x = x as i64 + xvel; + let y = y as i64 + yvel; + if x < 0 || y < 0 || x >= width as i64 || y >= height as i64 { + None + } else { + Some((x as usize, y as usize)) + } +} + pub fn nexti64((x, y): Pair, (xvel, yvel): Pair, width: usize) -> Option> { let x = x + xvel; let y = y + yvel;