add: broken stuff
This commit is contained in:
+9
-11
@@ -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<String>) -> SResult<(usize, usize)> {
|
||||
let xpos = caps["xpos"].parse::<usize>().unwrap();
|
||||
let ypos = caps["ypos"].parse::<usize>().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<String, Pair>, 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<String> = input!("d13p1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (480, 0));
|
||||
assert_eq!(got, (480, 875318608908));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>) -> 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=(?<x>\d+),(?<y>\d+) v=(?<xvel>-?\d+),(?<yvel>-?\d+)").unwrap();
|
||||
let mut robots = vec![];
|
||||
for line in lines {
|
||||
let caps = pos_regex.captures(&line.trim()).unwrap();
|
||||
let x = caps["x"].parse::<usize>().unwrap();
|
||||
let y = caps["y"].parse::<usize>().unwrap();
|
||||
let xvel = caps["xvel"].parse::<i64>().unwrap();
|
||||
let yvel = caps["yvel"].parse::<i64>().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<i64>,
|
||||
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<String> = input!("d14p1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (12, 0));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,21 @@
|
||||
##########
|
||||
#..O..O.O#
|
||||
#......O.#
|
||||
#.OO..O.O#
|
||||
#..O@..O.#
|
||||
#O#..O...#
|
||||
#O..O..O.#
|
||||
#.OO.O.OO#
|
||||
#....O...#
|
||||
##########
|
||||
|
||||
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
|
||||
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
|
||||
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
|
||||
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
|
||||
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
|
||||
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
|
||||
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
|
||||
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
|
||||
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
|
||||
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^
|
||||
@@ -0,0 +1,10 @@
|
||||
########
|
||||
#..O.O.#
|
||||
##@.O..#
|
||||
#...O..#
|
||||
#.#.O..#
|
||||
#...O..#
|
||||
#......#
|
||||
########
|
||||
|
||||
<^^>>>vv<v>>v<<
|
||||
@@ -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<String>) -> SResult<(usize, usize)> {
|
||||
// Read in the grid
|
||||
let mut grid: Vec<Vec<char>> = Vec::with_capacity(lines.len());
|
||||
let mut grid2: Vec<Vec<char>> = 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<i64>, grid: &mut [Vec<char>]) -> Option<Pair> {
|
||||
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<char>]) -> 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<i64> {
|
||||
match m {
|
||||
'>' => (0, 1),
|
||||
'<' => (0, -1),
|
||||
'^' => (-1, 0),
|
||||
'v' => (1, 0),
|
||||
c => panic!("not implemented: {}", c),
|
||||
}
|
||||
}
|
||||
|
||||
fn sum(grid: &[Vec<char>]) -> 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<char>]) {
|
||||
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<String> = input!("d15i1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (10092, 9021));
|
||||
}
|
||||
#[test]
|
||||
fn d15i2() {
|
||||
return;
|
||||
let strings: Vec<String> = input!("d15i2.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (2028, 105));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###.#
|
||||
#.....#.#...#.#
|
||||
#.###.#####.#.#
|
||||
#.#.#.......#.#
|
||||
#.#.#####.###.#
|
||||
#...........#.#
|
||||
###.#.#####.#.#
|
||||
#...#.....#.#.#
|
||||
#.#.#.###.#.#.#
|
||||
#.....#...#.#.#
|
||||
#.###.#.#.#.#.#
|
||||
#S..#.....#...#
|
||||
###############
|
||||
@@ -0,0 +1,17 @@
|
||||
#################
|
||||
#...#...#...#..E#
|
||||
#.#.#.#.#.#.#.#.#
|
||||
#.#.#.#...#...#.#
|
||||
#.#.#.#.###.#.#.#
|
||||
#...#.#.#.....#.#
|
||||
#.#.#.#.#.#####.#
|
||||
#.#...#.#.#.....#
|
||||
#.#.#####.#.###.#
|
||||
#.#.#.......#...#
|
||||
#.#.###.#####.###
|
||||
#.#.#...#.....#.#
|
||||
#.#.#.#####.###.#
|
||||
#.#.#.........#.#
|
||||
#.#.#.#########.#
|
||||
#S#.............#
|
||||
#################
|
||||
@@ -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<String>) -> SResult<(usize, usize)> {
|
||||
// Read in the grid
|
||||
let mut grid: Vec<Vec<char>> = 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<Pair> = 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<char>]) -> 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<i64> {
|
||||
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<char>]) {
|
||||
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<String> = input!("d16i1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (7036, 45));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d16i2() {
|
||||
let strings: Vec<String> = input!("d16i2.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (11048, 64));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,3,5,4,3,0
|
||||
@@ -0,0 +1,5 @@
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
@@ -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<usize> {
|
||||
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<usize> {
|
||||
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<String>) -> SResult<(usize, usize)> {
|
||||
let mut registers: HashMap<String, usize> = 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<usize> = 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<String> = input!("d17i1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (4, 117440));
|
||||
}
|
||||
#[test]
|
||||
fn d17i2() {
|
||||
return;
|
||||
let strings: Vec<String> = input!("d17i2.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (4, 117440));
|
||||
}
|
||||
}
|
||||
+10
@@ -42,6 +42,16 @@ pub fn next((x, y): Pair, (xvel, yvel): Pair<i64>, width: usize) -> Option<Pair>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next2((x, y): Pair, (xvel, yvel): Pair<i64>, (width, height): Pair) -> Option<Pair> {
|
||||
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<i64>, (xvel, yvel): Pair<i64>, width: usize) -> Option<Pair<i64>> {
|
||||
let x = x + xvel;
|
||||
let y = y + yvel;
|
||||
|
||||
Reference in New Issue
Block a user