added day 17/18

This commit is contained in:
Ishan Jain 2024-12-18 17:50:54 +05:30
parent 527b156882
commit 1e2bf54958
6 changed files with 508 additions and 1 deletions

View File

@ -4,6 +4,9 @@ version = "0.1.0"
edition = "2021" edition = "2021"
default-run = "main" default-run = "main"
[profile.release]
debug = true
[dependencies] [dependencies]
fxhash = "0.2.1" fxhash = "0.2.1"
rayon = "1.10.0" rayon = "1.10.0"

View File

@ -267,7 +267,6 @@ impl Bitmap {
self.inner[index] &= !(1 << bit_offset); self.inner[index] &= !(1 << bit_offset);
self.left_bracket[index] &= !(1 << bit_offset); self.left_bracket[index] &= !(1 << bit_offset);
} }
} }
fn main() { fn main() {

125
src/day17/1.rs Normal file
View File

@ -0,0 +1,125 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 7] = [
"Register A: 0
Register B: 0
Register C: 9
Program: 2,6",
"Register A: 10
Register B: 0
Register C: 0
Program: 5,0,5,1,5,4",
"Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0",
"Register A: 2024
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0",
"Register A: 0
Register B: 29
Register C: 0
Program: 1,7",
"Register A: 0
Register B: 2024
Register C: 43690
Program: 4,0",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> String {
let (p, q) = input.split_once("\n\n").unwrap();
let (_, q) = q.split_once(' ').unwrap();
let program = q.trim().split(',').map(|x| x.parse::<u32>().unwrap()).collect::<Vec<u32>>();
let mut p = p.lines();
let mut a = p.next().unwrap().chars().filter(|x| x.is_digit(10)).collect::<String>().parse::<u32>().unwrap();
let mut b = p.next().unwrap().chars().filter(|x| x.is_digit(10)).collect::<String>().parse::<u32>().unwrap();
let mut c = p.next().unwrap().chars().filter(|x| x.is_digit(10)).collect::<String>().parse::<u32>().unwrap();
let mut out = vec![];
let mut ip = 0;
while ip < program.len() {
let opcode = program[ip];
let operand = program[ip+1];
ip += 2;
let combo = |op: u32| {
match op {
0..=3 => op,
4 => a,
5 => b,
6 => c,
7 => unreachable!(),
_ => unreachable!(),
}
};
match opcode {
0 => {
let denom = 2u32.pow(combo(operand));
a /= denom;
}
1 => {
b ^= operand;
}
2 => {
b = combo(operand) % 8;
}
3 => {
if a != 0 {
ip = operand as usize;
}
}
4 => {
b = b ^ c;
}
5 => {
out.push(combo(operand)%8);
}
6 => {
let denom = 2u32.pow(combo(operand));
b = a / denom;
}
7 => {
let denom = 2u32.pow(combo(operand));
c = a / denom;
}
_ => unreachable!()
}
}
out.into_iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",")
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[6]);
test::black_box(v);
});
}

131
src/day17/2.rs Normal file
View File

@ -0,0 +1,131 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 1] = [
include_str!("./input.txt"),
];
pub fn run(input: &str) -> u64 {
let (_, q) = input.split_once("\n\n").unwrap();
let (_, q) = q.split_once(' ').unwrap();
let program = q.trim().split(',').map(|x| x.parse::<u64>().unwrap()).collect::<Vec<u64>>();
let mut a;
let b = 0;
let c = 0;
let mut out = Vec::new();
// Digits in program change in multiples of 8 so [1, 8, 64, 512, ...].
// instead of checking every value of a, check the values where all digits will change
let mut factors = vec![0; program.len()];
loop {
a = 0;
for (i, f) in factors.iter().enumerate() {
a += 8u64.pow(i as u32) * f;
}
test(a, b, c, &mut out);
// general_eval(a, b, c, &program, &mut out);
if out == program {
return a;
}
for i in (0..program.len()).rev() {
if out.len() < i {
factors[i] += 1;
break;
}
if out[i] != program[i] {
factors[i] += 1;
break;
}
}
out.clear();
}
}
// 2,4,1,4,7,5,4,1,1,4,5,5,0,3,3,0
fn test(mut a: u64, mut b: u64, mut c: u64, out: &mut Vec<u64>) {
while a != 0 {
b = a % 8;
b ^= 4;
c = a / (1 << b);
b ^= c;
b ^= 4;
out.push(b%8);
a = a / (1 << 3);
}
}
#[allow(unused)]
fn general_eval(mut a: u64, mut b: u64, mut c: u64, input: &[u64], out: &mut Vec<u64>) {
let mut ip = 0;
while ip < input.len() {
let opcode = input[ip];
let operand = input[ip+1];
ip += 2;
let combo = |op: u64| {
match op {
0..=3 => op,
4 => a,
5 => b,
6 => c,
7 => unreachable!(),
_ => unreachable!(),
}
};
match opcode {
0 => {
let denom = 2u64.pow(combo(operand) as u32);
a /= denom;
}
1 => {
b ^= operand;
}
2 => {
b = combo(operand) % 8;
}
3 => {
if a != 0 {
ip = operand as usize;
}
}
4 => {
b = b ^ c;
}
5 => {
out.push(combo(operand)%8);
}
6 => {
let denom = 2u64.pow(combo(operand) as u32);
b = a / denom;
}
7 => {
let denom = 2u64.pow(combo(operand) as u32);
c = a / denom;
}
_ => unreachable!()
}
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[0]);
test::black_box(v);
});
}

114
src/day18/1.rs Normal file
View File

@ -0,0 +1,114 @@
#![feature(slice_split_once)]
#![feature(test)]
extern crate test;
use std::collections::VecDeque;
const INPUTS: [&str; 1] = [
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let parse = |x: &[u8]| {
(match x.len() {
1 => x[0] - b'0',
2 => (x[0] - b'0') * 10 + x[1] - b'0',
_ => 0
}) as i64
};
let mut visited = Bitmap::new();
let mut obstacles = Bitmap::new();
input.split(|&x| x == b'\n').take(1024).for_each(|x| {
let (a,b) = x.split_once(|&x| x == b',').unwrap();
let a = parse(a);
let b = parse(b);
obstacles.set(a,b);
});
let best = bfs(&obstacles, &mut visited, (0,0), (70,70));
best
}
fn bfs(obstacles: &Bitmap, visited: &mut Bitmap, (x,y): (i64, i64), (ex, ey): (i64, i64)) -> i64 {
let mut q = VecDeque::new();
q.push_back((x,y,0));
while let Some((x,y,steps)) = q.pop_front() {
if x == ex && y == ey {
return steps;
}
if visited.get(x,y) {
continue;
}
visited.set(x,y);
for (i,j) in [(0,1), (1,0), (0,-1), (-1,0)].iter() {
let x = i + x;
let y = j + y;
if x < 0 || y < 0 || x > ex || y > ey {
continue;
}
if obstacles.get(x,y) || visited.get(x,y) {
continue;
}
q.push_back((x,y,steps+1));
}
}
-1
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: [u64; (71 * 71) / WORD_SIZE + 1],
size: i64,
}
impl Bitmap {
fn new() -> Self {
Self { inner: [0; (71 * 71) / WORD_SIZE + 1], size: 71 }
}
const fn get(&self, x: i64, y: i64) -> bool {
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
unsafe {
(*self.inner.as_ptr().add(index) >> bit_offset & 1) == 1
}
}
fn set(&mut self, x: i64, y: i64) {
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
unsafe {
*self.inner.get_unchecked_mut(index) |= 1 << bit_offset;
}
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {:?}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[0]);
test::black_box(v);
});
}

135
src/day18/2.rs Normal file
View File

@ -0,0 +1,135 @@
#![feature(slice_split_once)]
#![feature(test)]
extern crate test;
const INPUTS: [&str; 1] = [
include_str!("./input.txt"),
];
pub fn run(input: &str) -> (i64, i64) {
let input = input.as_bytes();
let parse = |x: &[u8]| {
(match x.len() {
1 => x[0] - b'0',
2 => (x[0] - b'0') * 10 + x[1] - b'0',
_ => 0
}) as i64
};
let bytes = input.split(|&x| x == b'\n').filter(|x| !x.is_empty()).map(|x| {
let (a,b) = x.split_once(|&x| x == b',').unwrap();
let a = parse(a);
let b = parse(b);
(a,b)
}).collect::<Vec<(i64, i64)>>();
let mut visited = Bitmap::new();
let mut obstacles = Bitmap::new();
let mut l = 0;
let mut r = bytes.len()-1;
while l <= r {
let mid = (l + r) / 2;
for b in bytes[0..mid].iter() {
obstacles.set(b.0, b.1);
}
if dfs(&obstacles, &mut visited, (0,0), (70,70)) {
l = mid + 1;
} else {
r = mid - 1;
}
obstacles.clear();
visited.clear();
}
bytes[r]
}
fn dfs(obstacles: &Bitmap, visited: &mut Bitmap, (x,y): (i64, i64), (ex, ey): (i64, i64)) -> bool {
let mut stack = vec![];
stack.push((x,y));
while let Some((x,y)) = stack.pop() {
if x == ex && y == ey {
return true;
}
if visited.get(x,y) {
continue;
}
visited.set(x,y);
for (i,j) in [(0,1), (1,0), (0,-1), (-1,0)].iter() {
let x = i + x;
let y = j + y;
if x < 0 || y < 0 || x > ex || y > ex {
continue;
}
if obstacles.get(x,y) || visited.get(x,y) {
continue;
}
stack.push((x,y));
}
}
false
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: [u64; (71 * 71) / WORD_SIZE + 1],
size: i64,
}
impl Bitmap {
fn new() -> Self {
Self { inner: [0; (71 * 71) / WORD_SIZE + 1], size: 71 }
}
const fn get(&self, x: i64, y: i64) -> bool {
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
unsafe {
(*self.inner.as_ptr().add(index) >> bit_offset & 1) == 1
}
}
fn set(&mut self, x: i64, y: i64) {
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
unsafe {
*self.inner.get_unchecked_mut(index) |= 1 << bit_offset;
}
}
fn clear(&mut self) {
self.inner.fill(0);
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {:?}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[0]);
test::black_box(v);
});
}