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 advent_of_code_2024::{make_main, next, Pair, SResult};
|
||||||
use good_lp::{
|
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,
|
Solution, SolverModel, WithMipGap,
|
||||||
};
|
};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -30,11 +30,7 @@ fn solve(lines: Vec<String>) -> SResult<(usize, usize)> {
|
|||||||
let xpos = caps["xpos"].parse::<usize>().unwrap();
|
let xpos = caps["xpos"].parse::<usize>().unwrap();
|
||||||
let ypos = caps["ypos"].parse::<usize>().unwrap();
|
let ypos = caps["ypos"].parse::<usize>().unwrap();
|
||||||
total += solve2(&buttons, (xpos, ypos));
|
total += solve2(&buttons, (xpos, ypos));
|
||||||
let ans2 = solve2(&buttons, (xpos + 10000000000000, ypos + 10000000000000));
|
total2 += solve2(&buttons, (xpos + 10000000000000, ypos + 10000000000000));
|
||||||
if ans2 > 0 {
|
|
||||||
println!("Solved for pos {}, {}", xpos, ypos);
|
|
||||||
}
|
|
||||||
total2 += ans2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((total, total2))
|
Ok((total, total2))
|
||||||
@@ -51,17 +47,19 @@ fn solve2(buttons: &HashMap<String, Pair>, prize: Pair) -> usize {
|
|||||||
0 <= b (integer) ;
|
0 <= b (integer) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prec = 0.001;
|
||||||
|
|
||||||
let sol = match vars2.minimise(a * 3 + b)
|
let sol = match vars2.minimise(a * 3 + b)
|
||||||
.using(coin_cbc)
|
.using(coin_cbc)
|
||||||
.with(eq(a*ax+b*bx, prize.0 as f64))
|
.with(geq((a+prec)*ax+(b+prec)*bx, prize.0 as f64))
|
||||||
.with(eq(a*ay+b*by, prize.1 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() {
|
.solve() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => return 0,
|
Err(_) => return 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("a {}", sol.value(a));
|
|
||||||
println!("b {}", sol.value(b));
|
|
||||||
let a = sol.value(a).round() as usize;
|
let a = sol.value(a).round() as usize;
|
||||||
let b = sol.value(b).round() as usize;
|
let b = sol.value(b).round() as usize;
|
||||||
|
|
||||||
@@ -84,6 +82,6 @@ mod tests {
|
|||||||
fn lp_solve() {
|
fn lp_solve() {
|
||||||
let strings: Vec<String> = input!("d13p1.txt");
|
let strings: Vec<String> = input!("d13p1.txt");
|
||||||
let got = solve(strings).unwrap();
|
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>> {
|
pub fn nexti64((x, y): Pair<i64>, (xvel, yvel): Pair<i64>, width: usize) -> Option<Pair<i64>> {
|
||||||
let x = x + xvel;
|
let x = x + xvel;
|
||||||
let y = y + yvel;
|
let y = y + yvel;
|
||||||
|
|||||||
Reference in New Issue
Block a user