Skip to content

Commit

Permalink
2024_16 and 2024_17
Browse files Browse the repository at this point in the history
  • Loading branch information
hsaikia committed Dec 17, 2024
1 parent ca56592 commit 7fd19b7
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/bin/2024_16/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use std::collections::{HashMap, HashSet, VecDeque};

use aoc::{common, grid::Grid};
use num::abs;

const DIRS: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];

fn solve<const PART: usize>(input: &str) -> usize {
let map = Grid::from_str(input, |c| c);
let spos = map.positions('S')[0];
let epos = map.positions('E')[0];

let mut q = VecDeque::new();
q.push_back((vec![spos], 3, 0));

let mut lowest_cost = usize::MAX;
let mut visited: HashMap<((usize, usize), usize), usize> = HashMap::new();
let mut best_seats: HashSet<(usize, usize)> = HashSet::new();

while let Some((tp, di, s)) = q.pop_front() {
if *tp.last().unwrap() == epos {
if lowest_cost >= s {
if PART == 2 {
if lowest_cost > s {
best_seats.clear();
}

for x in tp.iter() {
best_seats.insert(*x);
}
}
lowest_cost = s;
}
continue;
}

if let Some(v) = visited.get_mut(&(*tp.last().unwrap(), di)) {
if *v < s {
continue;
} else {
*v = s;
}
} else {
visited.insert((*tp.last().unwrap(), di), s);
}

for (i, d) in DIRS.iter().enumerate() {
let ss = if i == di {
1
} else if abs(i as i32 - di as i32) == 2 {
2001
} else {
1001
};
let nx: Vec<(usize, usize)> = map
.adjacent_in_dir(tp.last().unwrap(), &[*d])
.into_iter()
.filter(|x| map.get(x) == '.' || map.get(x) == 'E')
.collect();
if nx.is_empty() {
continue;
}

let mut tmp = tp.clone();
tmp.push(nx[0]);
q.push_back((tmp, i, ss + s));
}
}

if PART == 1 {
lowest_cost
} else {
best_seats.len()
}
}

fn main() {
let input = common::get_input();
println!("{input:?}");
common::timed(&input, solve::<1>, true);
common::timed(&input, solve::<2>, false);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_samples() {
let sample_input = "###############\n#.......#....E#\n#.#.###.#.###.#\n#.....#.#...#.#\n#.###.#####.#.#\n#.#.#.......#.#\n#.#.#####.###.#\n#...........#.#\n###.#.#####.#.#\n#...#.....#.#.#\n#.#.#.###.#.#.#\n#.....#...#.#.#\n#.###.#.#.#.#.#\n#S..#.....#...#\n###############";
assert_eq!(solve::<1>(sample_input), 7036);
assert_eq!(solve::<2>(sample_input), 45);
let sample_input = "#################\n#...#...#...#..E#\n#.#.#.#.#.#.#.#.#\n#.#.#.#...#...#.#\n#.#.#.#.###.#.#.#\n#...#.#.#.....#.#\n#.#.#.#.#.#####.#\n#.#...#.#.#.....#\n#.#.#####.#.###.#\n#.#.#.......#...#\n#.#.###.#####.###\n#.#.#...#.....#.#\n#.#.#.#####.###.#\n#.#.#.........#.#\n#.#.#.#########.#\n#S#.............#\n#################";
assert_eq!(solve::<1>(sample_input), 11048);
assert_eq!(solve::<2>(sample_input), 64);
}
}
179 changes: 179 additions & 0 deletions src/bin/2024_17/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
use std::ops::BitXor;

use aoc::{common, io};
use itertools::Itertools;
use num::pow;

#[derive(Clone, Copy, Debug)]
enum Op {
Adv,
Bxl,
Bst,
Jnz,
Bxc,
Out,
Bdv,
Cdv,
}

const OPCODES: [Op; 8] = [
Op::Adv,
Op::Bxl,
Op::Bst,
Op::Jnz,
Op::Bxc,
Op::Out,
Op::Bdv,
Op::Cdv,
];

fn combo_operand(a: usize, b: usize, c: usize, op: usize) -> usize {
if op == 0 || op == 1 || op == 2 || op == 3 {
return op;
}
if op == 4 {
return a;
}

if op == 5 {
return b;
}

if op == 6 {
return c;
}
panic!("{} is not a valid combo operator", op);
}

fn literal_operand(op: usize) -> usize {
op
}

fn generate(instructions: &[(Op, usize)], a: usize, b: usize, c: usize) -> Vec<usize> {
let mut a = a;
let mut b = b;
let mut c = c;
let mut output = Vec::new();
let mut idx = 0;
loop {
if idx >= instructions.len() {
break;
}

let opcode = instructions[idx].0;
let operand = instructions[idx].1;

// operand
match opcode {
Op::Adv => {
a = a / pow(2, combo_operand(a, b, c, operand));
idx += 1
}
Op::Bxl => {
b = b.bitxor(literal_operand(operand));
idx += 1
}
Op::Bst => {
b = combo_operand(a, b, c, operand) % 8;
idx += 1
}
Op::Jnz => {
if a != 0 {
idx = literal_operand(operand) / 2;
} else {
idx += 1
}
}
Op::Bxc => {
b = b.bitxor(c);
idx += 1
}
Op::Out => {
output.push(combo_operand(a, b, c, operand) % 8);
idx += 1
}
Op::Bdv => {
b = a / pow(2, combo_operand(a, b, c, operand));
idx += 1
}
Op::Cdv => {
c = a / pow(2, combo_operand(a, b, c, operand));
idx += 1
}
}
}
output
}

fn solve<const PART: usize>(input: &str) -> String {
let batches: Vec<&str> = input.split("\n\n").collect();
let registers: Vec<&str> = batches[0].split("\n").collect();
let a_s = io::tokenize(registers[0], " ");
let a: usize = io::parse_num(a_s[2]);
let b_s = io::tokenize(registers[1], " ");
let b: usize = io::parse_num(b_s[2]);
let c_s = io::tokenize(registers[2], " ");
let c: usize = io::parse_num(c_s[2]);

let ins_s: Vec<&str> = batches[1].split(" ").collect();
let ins: Vec<usize> = io::tokenize_nums(ins_s[1], ",");

let mut instructions: Vec<(Op, usize)> = Vec::new();
let mut ptr = 0;
loop {
if ptr >= ins.len() {
break;
}
instructions.push((OPCODES[ins[ptr]], ins[ptr + 1]));
ptr += 2;
}

if PART == 1 {
let output = generate(&instructions, a, b, c);
output.iter().join(",")
} else {
let mut candidates = vec![0];
for d in (0..ins.len()).rev() {
let mut new_candidates: Vec<usize> = Vec::new();

for candidate in candidates {
for test in candidate * 8..candidate * 8 + 8 {
let output: Vec<usize> = generate(&instructions, test, b, c);
if output == ins[d..] {
new_candidates.push(test);
}
}
}

new_candidates.sort();
new_candidates.dedup();
candidates = new_candidates;
}

candidates[0].to_string()
}
}

fn main() {
let input = common::get_input();
println!("{input:?}");
common::timed(&input, solve::<1>, true);
common::timed(&input, solve::<2>, false);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_samples() {
let sample_input1 = "Register A: 729\nRegister B: 0\nRegister C: 0\n\nProgram: 0,1,5,4,3,0";
assert_eq!(solve::<1>(sample_input1), "4,6,3,5,6,3,5,2,1,0");
let sample_input2 =
"Register A: 2024\nRegister B: 0\nRegister C: 0\n\nProgram: 0,3,5,4,3,0";
assert_eq!(solve::<2>(sample_input2), "117440");
let sample_input3 =
"Register A: 117440\nRegister B: 0\nRegister C: 0\n\nProgram: 0,3,5,4,3,0";
assert_eq!(solve::<1>(sample_input3), "0,3,5,4,3,0");
}
}

0 comments on commit 7fd19b7

Please sign in to comment.