added day 17/18
This commit is contained in:
parent
527b156882
commit
1e2bf54958
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
default-run = "main"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
fxhash = "0.2.1"
|
||||
rayon = "1.10.0"
|
||||
|
|
|
@ -267,7 +267,6 @@ impl Bitmap {
|
|||
self.inner[index] &= !(1 << bit_offset);
|
||||
self.left_bracket[index] &= !(1 << bit_offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
125
src/day17/1.rs
Normal file
125
src/day17/1.rs
Normal 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
131
src/day17/2.rs
Normal 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
114
src/day18/1.rs
Normal 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
135
src/day18/2.rs
Normal 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);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user