added solutions until day 15

This commit is contained in:
Ishan Jain
2024-12-15 16:03:42 +05:30
commit e7d2780827
33 changed files with 3648 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
/target
.aoc_token
todo
.DS_Store
**/input.txt
Generated
+380
View File
@@ -0,0 +1,380 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aoc2024"
version = "0.1.0"
dependencies = [
"fxhash",
"rayon",
"ureq",
]
[[package]]
name = "base64"
version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "flate2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "ring"
version = "0.17.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866"
dependencies = [
"cc",
"getrandom",
"libc",
"spin",
"untrusted",
"windows-sys",
]
[[package]]
name = "rustls"
version = "0.21.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9"
dependencies = [
"log",
"ring",
"rustls-webpki",
"sct",
]
[[package]]
name = "rustls-webpki"
version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "sct"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "unicode-bidi"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97"
dependencies = [
"base64",
"flate2",
"log",
"once_cell",
"rustls",
"rustls-webpki",
"url",
"webpki-roots",
]
[[package]]
name = "url"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "webpki-roots"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+263
View File
@@ -0,0 +1,263 @@
[package]
name = "aoc2024"
version = "0.1.0"
edition = "2021"
default-run = "main"
[dependencies]
fxhash = "0.2.1"
rayon = "1.10.0"
ureq = { version = "2.9.1" }
[[bin]]
name = "main"
path = "src/main.rs"
[[bin]]
name = "d1-1"
path = "src/day1/1.rs"
[[bin]]
name = "d1-2"
path = "src/day1/2.rs"
[[bin]]
name = "d2-1"
path = "src/day2/1.rs"
[[bin]]
name = "d2-2"
path = "src/day2/2.rs"
[[bin]]
name = "d3-1"
path = "src/day3/1.rs"
[[bin]]
name = "d3-2"
path = "src/day3/2.rs"
[[bin]]
name = "d4-1"
path = "src/day4/1.rs"
[[bin]]
name = "d4-2"
path = "src/day4/2.rs"
[[bin]]
name = "d5-1"
path = "src/day5/1.rs"
[[bin]]
name = "d5-2"
path = "src/day5/2.rs"
[[bin]]
name = "d6-1"
path = "src/day6/1.rs"
[[bin]]
name = "d6-2"
path = "src/day6/2.rs"
[[bin]]
name = "d7-1"
path = "src/day7/1.rs"
[[bin]]
name = "d7-2"
path = "src/day7/2.rs"
[[bin]]
name = "d8-1"
path = "src/day8/1.rs"
[[bin]]
name = "d8-2"
path = "src/day8/2.rs"
[[bin]]
name = "d9-1"
path = "src/day9/1.rs"
[[bin]]
name = "d9-2"
path = "src/day9/2.rs"
[[bin]]
name = "d10-1"
path = "src/day10/1.rs"
[[bin]]
name = "d10-2"
path = "src/day10/2.rs"
[[bin]]
name = "d11-1"
path = "src/day11/1.rs"
[[bin]]
name = "d11-2"
path = "src/day11/2.rs"
[[bin]]
name = "d12-1"
path = "src/day12/1.rs"
[[bin]]
name = "d12-2"
path = "src/day12/2.rs"
[[bin]]
name = "d13-1"
path = "src/day13/1.rs"
[[bin]]
name = "d13-2"
path = "src/day13/2.rs"
[[bin]]
name = "d14-1"
path = "src/day14/1.rs"
[[bin]]
name = "d14-2"
path = "src/day14/2.rs"
[[bin]]
name = "d15-1"
path = "src/day15/1.rs"
[[bin]]
name = "d15-2"
path = "src/day15/2.rs"
[[bin]]
name = "d16-1"
path = "src/day16/1.rs"
[[bin]]
name = "d16-2"
path = "src/day16/2.rs"
[[bin]]
name = "d17-1"
path = "src/day17/1.rs"
[[bin]]
name = "d17-2"
path = "src/day17/2.rs"
[[bin]]
name = "d18-1"
path = "src/day18/1.rs"
[[bin]]
name = "d18-2"
path = "src/day18/2.rs"
[[bin]]
name = "d19-1"
path = "src/day19/1.rs"
[[bin]]
name = "d19-2"
path = "src/day19/2.rs"
[[bin]]
name = "d20-1"
path = "src/day20/1.rs"
[[bin]]
name = "d20-2"
path = "src/day20/2.rs"
[[bin]]
name = "d21-1"
path = "src/day21/1.rs"
[[bin]]
name = "d21-2"
path = "src/day21/2.rs"
[[bin]]
name = "d22-1"
path = "src/day22/1.rs"
[[bin]]
name = "d22-2"
path = "src/day22/2.rs"
[[bin]]
name = "d23-1"
path = "src/day23/1.rs"
[[bin]]
name = "d23-2"
path = "src/day23/2.rs"
[[bin]]
name = "d24-1"
path = "src/day24/1.rs"
[[bin]]
name = "d24-2"
path = "src/day24/2.rs"
[[bin]]
name = "d25-1"
path = "src/day25/1.rs"
[[bin]]
name = "d25-2"
path = "src/day25/2.rs"
+9
View File
@@ -0,0 +1,9 @@
# AOC 2024
My solutions for [Advent of Code](https://adventofcode.com) 2024!
### How to run?
Run `cargo r --release --bin d1-1` to run day 1 part 1.
+55
View File
@@ -0,0 +1,55 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"3 4
4 3
2 5
1 3
3 9
3 3",
include_str!("./input.txt"),
];
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
pub fn run(input: &str) -> i64 {
let mut left = vec![];
let mut right = vec![];
for line in input.lines() {
let line = line.trim();
let line: Vec<i64> = line.split(' ').filter(|x| !x.is_empty()).map(|x| x.parse::<i64>().unwrap()).collect();
if line.is_empty() {
continue;
}
left.push(line[0]);
right.push(line[1]);
}
left.sort_unstable();
right.sort_unstable();
let mut sum = 0;
for (a,b) in left.into_iter().zip(right.into_iter()) {
sum += (a - b).abs();
}
sum
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+57
View File
@@ -0,0 +1,57 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashMap;
const INPUTS: [&str; 2] = [
"3 4
4 3
2 5
1 3
3 9
3 3",
include_str!("./input.txt"),
];
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
pub fn run(input: &str) -> i64 {
let mut left = vec![];
let mut right = FxHashMap::default();
for line in input.lines() {
let line = line.trim();
let line: Vec<i64> = line.split(' ').filter(|x| !x.is_empty()).map(|x| x.parse::<i64>().unwrap()).collect();
if line.is_empty() {
continue;
}
left.push(line[0]);
*right.entry(line[1]).or_insert(0) += 1;
}
left.sort_unstable();
let mut sum = 0;
for a in left.into_iter() {
let count = right.get(&a).unwrap_or(&0);
sum += a * count;
}
sum
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+108
View File
@@ -0,0 +1,108 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> u32 {
let input = input.as_bytes();
let size = input.iter().position(|&x| x == b'\n').unwrap() as i32;
let mut answer = 0;
assert!(size > 0);
for (p,&q) in input.iter().filter(|&&x| x != b'\n').enumerate() {
if q != b'9' {
continue;
}
let i = p as i32 / size;
let j = p as i32 % size;
answer += count_trails(&input, i, j, size);
}
answer
}
fn count_trails(grid: &[u8], i: i32, j: i32, size: i32) -> u32 {
let mut seen = Bitmap::new(size);
let mut stack = vec![];
stack.push((i,j, b'9'));
while let Some((x,y,lh)) = stack.pop() {
if lh == b'0' {
seen.set(x,y);
continue;
}
for (dx,dy) in [(0,1), (1,0), (-1,0), (0,-1)].iter() {
let i = x + dx;
let j = y + dy;
if i < 0 || j < 0 || i >= size || j >= size {
continue;
}
let c = unsafe { *grid.get_unchecked((i*size+j+i) as usize) };
if c == lh - 1 {
stack.push((i,j,c));
}
}
}
seen.count()
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: Vec<u64>,
size: i32,
}
impl Bitmap {
fn new(size: i32) -> Self {
Self { inner: vec![0; ((size * size) as usize / WORD_SIZE) + 1], size }
}
fn set(&mut self, x: i32, y: i32) {
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
self.inner[index] |= 1 << bit_offset;
}
fn count(self) -> u32 {
let mut count = 0;
for c in self.inner {
count += c.count_ones();
}
count
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+77
View File
@@ -0,0 +1,77 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> u32 {
let input = input.as_bytes();
let size = input.iter().position(|&x| x == b'\n').unwrap() as i32;
let mut answer = 0;
assert!(size > 0);
for (p,&q) in input.iter().filter(|&&x| x != b'\n').enumerate() {
if q != b'0' {
continue;
}
let i = p as i32 / size;
let j = p as i32 % size;
answer += count_trails(&input, i, j, size);
}
answer
}
fn count_trails(grid: &[u8], i: i32, j: i32, size: i32) -> u32 {
let mut sum = 0;
let mut stack = vec![];
stack.push((i,j, b'0'));
while let Some((x,y,lh)) = stack.pop() {
if lh == b'9' {
sum += 1;
continue;
}
for (dx,dy) in [(0,1), (1,0), (-1,0), (0,-1)].iter() {
let i = x + dx;
let j = y + dy;
if i < 0 || j < 0 || i >= size || j >= size {
continue;
}
let c = unsafe { *grid.get_unchecked((i*size+j+i) as usize) };
if c == lh + 1 {
stack.push((i,j,lh + 1));
}
}
}
sum
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+68
View File
@@ -0,0 +1,68 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashMap;
const INPUTS: [&str; 2] = [
"125 17",
include_str!("./input.txt"),
];
const STEPS: u64 = 25;
pub fn run(input: &str) -> i64 {
let mut answer = 0;
let mut m = FxHashMap::default();
for num in input.split(' ').filter(|x| !x.is_empty()).map(|x| x.trim().parse::<u64>().unwrap()) {
answer += solve(&mut m, num, 0);
}
answer as i64
}
fn solve(map: &mut FxHashMap<(u64,u64), u64>, num: u64, step: u64) -> u64 {
if step == STEPS {
return 1;
}
if let Some(v) = map.get(&(num,step)) {
return *v;
}
let count = if num == 0 {
solve(map, 1, step+1)
} else {
let len = num.ilog(10) + 1;
if len % 2 == 0 {
let (a, b) = split(num);
solve(map, a, step+1) + solve(map, b, step+1)
} else {
solve(map, num * 2024, step+1)
}
};
map.insert((num,step), count);
count
}
#[inline]
const fn split(n: u64) -> (u64, u64) {
let len = n.ilog10() + 1;
(n / 10u64.pow(len/2), n % 10u64.pow(len/2))
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+68
View File
@@ -0,0 +1,68 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashMap;
const INPUTS: [&str; 2] = [
"125 17",
include_str!("./input.txt"),
];
const STEPS: u64 = 75;
pub fn run(input: &str) -> i64 {
let mut answer = 0;
let mut map = FxHashMap::default();
for num in input.split(' ').filter(|x| !x.is_empty()).map(|x| x.trim().parse::<u64>().unwrap()) {
answer += solve(&mut map, num, 0);
}
answer as i64
}
fn solve(map: &mut FxHashMap<(u64,u64), u64>, num: u64, step: u64) -> u64 {
if step == STEPS {
return 1;
}
if let Some(v) = map.get(&(num,step)) {
return *v;
}
let count = if num == 0 {
solve(map, 1, step+1)
} else {
let len = num.ilog(10) + 1;
if len % 2 == 0 {
let (a, b) = split(num);
solve(map, a, step+1) + solve(map, b, step+1)
} else {
solve(map, num * 2024, step+1)
}
};
map.insert((num,step), count);
count
}
#[inline]
const fn split(n: u64) -> (u64, u64) {
let len = n.ilog10() + 1;
(n / 10u64.pow(len/2), n % 10u64.pow(len/2))
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+89
View File
@@ -0,0 +1,89 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut grid = input.lines().map(|x| x.chars().collect::<Vec<char>>()).collect::<Vec<Vec<char>>>();
let m = grid.len();
let n = grid[0].len();
let mut area_total = 0;
for i in 0..m {
for j in 0..n {
let plant = grid[i][j];
if plant == '0' {
continue;
}
let mut perimeter = 0;
let mut area = 0;
let mut seen = FxHashSet::default();
let mut stack = vec![];
stack.push((i as i32, j as i32));
while let Some((i, j)) = stack.pop() {
grid[i as usize][j as usize] = '0';
area += 1;
seen.insert((i, j));
for dir in [(0,1), (1,0), (-1,0), (0,-1)].iter() {
let x = i as i32 + dir.0;
let y = j as i32 + dir.1;
if seen.contains(&(x,y)) {
continue;
}
if x < 0 || y < 0 || x >= m as i32 || y >= n as i32 {
perimeter += 1;
continue;
}
let c = grid[x as usize][y as usize];
if c == plant {
seen.insert((x,y));
stack.push((x,y));
continue;
}
perimeter += 1;
}
}
area_total += area * perimeter;
}
}
area_total
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+138
View File
@@ -0,0 +1,138 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut grid = input.lines().map(|x| x.chars().collect::<Vec<char>>()).collect::<Vec<Vec<char>>>();
let m = grid.len();
let n = grid[0].len();
let mut area_total = 0;
for i in 0..m {
for j in 0..n {
let plant = grid[i][j];
if plant == '.' {
continue;
}
let mut area = 0;
let mut fence2 = vec![];
let mut fence = FxHashSet::default();
let mut seen = FxHashSet::default();
let mut stack = vec![];
stack.push((i as i32, j as i32));
while let Some((i, j)) = stack.pop() {
grid[i as usize][j as usize] = '.';
area += 1;
seen.insert((i, j));
for dir in [(0,1), (1,0), (-1,0), (0,-1)].iter() {
let x = i as i32 + dir.0;
let y = j as i32 + dir.1;
let direction = match dir {
(0,1) => 1,
(1,0) => 2,
(-1,0) => 0,
(0,-1) => 3,
_ => unreachable!()
};
if seen.contains(&(x,y)) {
continue;
}
if x < 0 || y < 0 || x >= m as i32 || y >= n as i32 {
fence.insert((x,y,direction));
fence2.push((x,y,direction));
continue;
}
let c = grid[x as usize][y as usize];
if c == plant {
seen.insert((x,y));
stack.push((x,y));
continue;
}
fence.insert((x,y,direction));
fence2.push((x,y,direction));
}
}
let mut sides = 0;
for f @(tx,ty,direction) in fence2 {
if !fence.contains(&f) {
continue;
}
fence.remove(&f);
sides += 1;
for i in tx+1..m as i32 {
if !fence.contains(&(i,ty,direction)) {
break;
}
fence.remove(&(i, ty, direction));
}
for i in (0..tx).rev() {
if !fence.contains(&(i,ty,direction)) {
break;
}
fence.remove(&(i, ty, direction));
}
for j in ty+1..n as i32 {
if !fence.contains(&(tx,j,direction)) {
break;
}
fence.remove(&(tx, j, direction));
}
for j in (0..ty).rev() {
if !fence.contains(&(tx,j,direction)) {
break;
}
fence.remove(&(tx, j, direction));
}
}
area_total += area * sides;
}
}
area_total
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+102
View File
@@ -0,0 +1,102 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400
Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176
Button A: X+17, Y+86
Button B: X+84, Y+37
Prize: X=7870, Y=6450
Button A: X+69, Y+23
Button B: X+27, Y+71
Prize: X=18641, Y=10279",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut answer = 0.0;
for set in input.split("\n\n") {
let mut nums = Vec::with_capacity(6);
let mut tmp = 0;
for c in set.bytes() {
if c >= b'0' && c <= b'9' {
tmp *= 10;
tmp += (c - b'0') as i64;
} else if tmp != 0 {
nums.push(tmp as f64);
tmp = 0;
} else {
tmp = 0;
}
}
if tmp != 0 {
nums.push(tmp as f64);
}
assert!(nums.len() == 6);
let py = nums[5];
let px = nums[4];
let by = nums[3];
let bx = nums[2];
let ay = nums[1];
let ax = nums[0];
/*
* axA + bxB = px
* ayA + byB = py
*
* ay*ax*A + ay*bx*B = ay*px
* ax*ay*A + ax*by*B = ax*py
*
* ay*bx*B - ax*by*B = ay*px - ax*py
* (ay*bx - ax*by) B = ay*px - ax*py
*
* B = (ay*px - ax*py) / (ay*bx - ax*by)
* A = (px - bx * B) / ax;
*/
const ERROR_MARGIN: f64 = 0.0001;
let _b = (ay * px - ax * py) / (ay * bx - ax * by);
let _a = (px - bx * _b) / ax;
// If there is too much error in reaching a point then we didn't actually reach it.
// overshot or undershot
if _b - (_b as isize) as f64 >= ERROR_MARGIN {
continue;
}
if _a - (_a as isize) as f64 >= ERROR_MARGIN {
continue;
}
answer += _a * 3.0 + _b * 1.0;
}
answer as i64
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+102
View File
@@ -0,0 +1,102 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400
Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176
Button A: X+17, Y+86
Button B: X+84, Y+37
Prize: X=7870, Y=6450
Button A: X+69, Y+23
Button B: X+27, Y+71
Prize: X=18641, Y=10279",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut answer = 0.0;
for set in input.split("\n\n") {
let mut nums = Vec::with_capacity(6);
let mut tmp = 0;
for c in set.bytes() {
if c >= b'0' && c <= b'9' {
tmp *= 10;
tmp += (c - b'0') as i64;
} else if tmp != 0 {
nums.push(tmp as f64);
tmp = 0;
} else {
tmp = 0;
}
}
if tmp != 0 {
nums.push(tmp as f64);
}
assert!(nums.len() == 6);
let py = nums[5] + 10000000000000.0;
let px = nums[4] + 10000000000000.0;
let by = nums[3];
let bx = nums[2];
let ay = nums[1];
let ax = nums[0];
/*
* axA + bxB = px
* ayA + byB = py
*
* ay*ax*A + ay*bx*B = ay*px
* ax*ay*A + ax*by*B = ax*py
*
* ay*bx*B - ax*by*B = ay*px - ax*py
* (ay*bx - ax*by) B = ay*px - ax*py
*
* B = (ay*px - ax*py) / (ay*bx - ax*by)
* A = (px - bx * B) / ax;
*/
const ERROR_MARGIN: f64 = 0.0001;
let _b = (ay * px - ax * py) / (ay * bx - ax * by);
let _a = (px - bx * _b) / ax;
// If there is too much error in reaching a point then we didn't actually reach it.
// overshot or undershot
if _b - (_b as isize) as f64 >= ERROR_MARGIN {
continue;
}
if _a - (_a as isize) as f64 >= ERROR_MARGIN {
continue;
}
answer += _a * 3.0 + _b * 1.0;
}
answer as i64
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+94
View File
@@ -0,0 +1,94 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"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",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut m = 0;
let mut n = 0;
let mut robots = vec![];
for line in input.lines() {
let (p,v) = line.split_once(' ').unwrap();
let (_, p) = p.split_once('=').unwrap();
let (_, v) = v.split_once('=').unwrap();
let (px, py) = p.split_once(',').unwrap();
let px = px.parse::<i64>().unwrap();
let py = py.parse::<i64>().unwrap();
let (vx, vy) = v.split_once(',').unwrap();
let vx = vx.parse::<i64>().unwrap();
let vy = vy.parse::<i64>().unwrap();
m = std::cmp::max(m, px+1);
n = std::cmp::max(n, py+1);
robots.push((px, py, vx, vy));
}
for _ in 0..100 {
for robot in robots.iter_mut() {
robot.0 += robot.2;
robot.1 += robot.3;
if robot.0 < 0 {
robot.0 += m;
} else if robot.0 >= m {
robot.0 -= m;
}
if robot.1 < 0 {
robot.1 += n;
} else if robot.1 >= n {
robot.1 -= n;
}
}
}
let mx = m / 2;
let nx = n / 2;
let mut quads = [0;4];
for (px,py, _,_) in robots {
if px == mx || py == nx {
continue;
}
if px > mx && py > nx {
quads[0] += 1;
} else if px > mx && py < nx {
quads[1] += 1;
} else if px < mx && py > nx {
quads[2] += 1;
} else if px < mx && py < nx {
quads[3] += 1;
}
}
quads.into_iter().product()
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+112
View File
@@ -0,0 +1,112 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 1] = [
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut m = 0;
let mut n = 0;
let mut robots = vec![];
for line in input.lines() {
let line = line.chars().filter(|&x| x.is_digit(10) || x == '-' || x == ' ' || x == ',').collect::<String>();
let (p,v) = line.split_once(' ').unwrap();
let (px, py) = p.split_once(',').unwrap();
let px = px.parse::<i64>().unwrap();
let py = py.parse::<i64>().unwrap();
let (vx, vy) = v.split_once(',').unwrap();
let vx = vx.parse::<i64>().unwrap();
let vy = vy.parse::<i64>().unwrap();
m = std::cmp::max(m, px+1);
n = std::cmp::max(n, py+1);
robots.push((px, py, vx, vy));
}
let mut seen = Bitmap::new(std::cmp::max(m,n));
let mut second = 1;
loop {
seen.clear();
for robot in robots.iter_mut() {
robot.0 += robot.2;
robot.1 += robot.3;
if robot.0 < 0 {
robot.0 += m;
} else if robot.0 >= m {
robot.0 -= m;
}
if robot.1 < 0 {
robot.1 += n;
} else if robot.1 >= n {
robot.1 -= n;
}
seen.set(robot.0, robot.1);
}
if seen.test() {
return second;
}
second += 1;
}
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: Vec<u64>,
size: i64,
}
impl Bitmap {
fn new(size: i64) -> Self {
Self { inner: vec![0; ((size * size) as usize / WORD_SIZE) + 1], size }
}
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;
self.inner[index] |= 1 << bit_offset;
}
fn test(&mut self) -> bool {
for num in self.inner.iter() {
for i in 0..8 {
let mask = 0b1111_1111 << i;
if num & mask == mask {
return true;
}
}
}
false
}
fn clear(&mut self) {
for v in self.inner.iter_mut() {
*v = 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);
});
}
+140
View File
@@ -0,0 +1,140 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"##########
#..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^<<^",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let (grid, moves) = input.split_once("\n\n").unwrap();
let mut grid = grid.lines().map(|x| x.chars().collect::<Vec<char>>()).collect::<Vec<Vec<char>>>();
let moves = moves.chars().filter(|x| !x.is_whitespace()).collect::<Vec<char>>();
let m = grid.len();
let n = grid[0].len();
let mut answer = 0;
let mut sx = 0;
let mut sy = 0;
for i in 0..m {
for j in 0..n {
if grid[i][j] == '@' {
sx = i as i64;
sy = j as i64;
break;
}
}
}
for mmove in moves.into_iter() {
let (nx, ny, ndir) = match mmove {
'^' => (sx - 1, sy, 0),
'>' => (sx, sy + 1, 1),
'v' => (sx + 1, sy, 2),
'<' => (sx, sy - 1, 3),
_ => unreachable!()
};
if validate_move(&mut grid, nx, ny, ndir) {
grid[sx as usize][sy as usize] = '.';
grid[nx as usize][ny as usize] = '@';
sx = nx;
sy = ny;
}
}
for i in 0..m {
for j in 0..n {
if grid[i][j] != 'O' {
continue;
}
answer += i as i64 * 100 + j as i64 ;
}
}
answer
}
fn validate_move(grid: &mut Vec<Vec<char>>, x: i64, y: i64, direction: i64) -> bool {
if grid[x as usize][y as usize] == '.' {
return true;
}
if grid[x as usize][y as usize] == '#' {
return false;
}
let delta = match direction {
0 => (-1,0),
1 => (0,1),
2 => (1,0),
3 => (0,-1),
_ => return false,
};
let mut fx = x;
let mut fy = y;
let mut count = 0;
while grid[fx as usize][fy as usize] == 'O' {
fx += delta.0;
fy += delta.1;
count += 1;
}
let mut nx = fx;
let mut ny = fy;
while count > 0 && grid[nx as usize][ny as usize] == '.' {
grid[nx as usize][ny as usize] = 'O';
nx = fx - delta.0;
ny = fy - delta.1;
fx = fx - delta.0;
fy = fy - delta.1;
grid[fx as usize][fy as usize] = '.';
count -= 1;
}
count == 0
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+230
View File
@@ -0,0 +1,230 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"##########
#..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^<<^",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let (grid, moves) = input.split_once("\n\n").unwrap();
let mut grid = grid.lines().map(|x| x.chars().collect::<Vec<char>>()).collect::<Vec<Vec<char>>>();
let moves = moves.chars().filter(|x| !x.is_whitespace()).collect::<Vec<char>>();
for row in grid.iter_mut() {
let mut new = vec![];
for &c in row.iter() {
match c {
'#' => new.extend(['#', '#'].iter()),
'O' => new.extend(['[', ']'].iter()),
'.' => new.extend(['.', '.'].iter()),
'@' => new.extend(['@', '.'].iter()),
_ => unreachable!()
}
}
*row = new;
}
let m = grid.len();
let n = grid[0].len();
let mut answer = 0;
let mut sx = 0;
let mut sy = 0;
for i in 0..m {
for j in 0..n {
if grid[i][j] == '@' {
sx = i as i64;
sy = j as i64;
break;
}
}
}
for mmove in moves.into_iter() {
let (nx, ny, ndir) = match mmove {
'^' => (sx - 1, sy, 0),
'>' => (sx, sy + 1, 1),
'v' => (sx + 1, sy, 2),
'<' => (sx, sy - 1, 3),
_ => unreachable!()
};
if validate_move(&mut grid, nx, ny, ndir) {
grid[sx as usize][sy as usize] = '.';
grid[nx as usize][ny as usize] = '@';
sx = nx;
sy = ny;
}
}
for i in 0..m {
for j in 0..n {
if grid[i][j] != '[' {
continue;
}
answer += i as i64 * 100 + j as i64 ;
}
}
answer
}
fn validate_move(grid: &mut Vec<Vec<char>>, x: i64, y: i64, direction: i64) -> bool {
if grid[x as usize][y as usize] == '.' {
return true;
}
if grid[x as usize][y as usize] == '#' {
return false;
}
let delta = match direction {
0 => (-1,0),
1 => (0,1),
2 => (1,0),
3 => (0,-1),
_ => unreachable!()
};
let mut fx = x;
let mut fy = y;
let mut count = 0;
while grid[fx as usize][fy as usize] == '[' || grid[fx as usize][fy as usize] == ']' {
fx += delta.0;
fy += delta.1;
count += 1;
}
count /= 2;
let mut nx = fx;
let mut ny = fy;
match direction {
1 | 3 => {
while count > 0 && grid[nx as usize][ny as usize] == '.' {
grid[nx as usize][ny as usize] = if direction == 1 { ']' } else { '[' };
nx -= delta.0;
ny -= delta.1;
grid[nx as usize][ny as usize] = if direction == 1 { '[' } else { ']' };
nx -= delta.0;
ny -= delta.1;
grid[nx as usize][ny as usize] = '.';
count -= 1;
}
count == 0
}
0 | 2 => {
let mut seen = FxHashSet::default();
let mut to_move = vec![];
let starting_point = if grid[x as usize][y as usize] == '[' {
[(x, y), (x, y+1)]
} else if grid[x as usize][y as usize] == ']' {
[(x, y-1), (x, y)]
} else {
return false;
};
seen.insert(starting_point);
to_move.push(starting_point);
let mut last_checked = 0;
while last_checked != to_move.len() {
for i in last_checked..to_move.len() {
let point = to_move[i];
for (cx,cy) in point {
let cx = cx + delta.0;
let cy = cy + delta.1;
let p = if grid[cx as usize][cy as usize] == '[' {
[(cx,cy), (cx, cy+1)]
} else if grid[cx as usize][cy as usize] == ']' {
[(cx,cy-1), (cx,cy)]
} else {
continue;
};
if seen.contains(&p) {
continue;
}
to_move.push(p);
seen.insert(p);
}
last_checked = i+1;
}
}
// Test if all can be moved
let mut g = grid.clone();
while let Some(coord) = to_move.pop() {
if coord.iter().any(|x| g[(x.0 + delta.0) as usize][(x.1 + delta.1) as usize] != '.') {
to_move.push(coord);
break;
}
g[coord[0].0 as usize][coord[0].1 as usize] = '.';
g[coord[1].0 as usize][coord[1].1 as usize] = '.';
g[(coord[0].0 + delta.0) as usize][(coord[0].1 + delta.1) as usize] = '[';
g[(coord[1].0 + delta.0) as usize][(coord[1].1 + delta.1) as usize] = ']';
}
if to_move.is_empty() {
*grid = g;
return true;
} else {
return false;
}
}
_ => false
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+55
View File
@@ -0,0 +1,55 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut safe = 0;
for line in input.lines().filter(|x| !x.is_empty()) {
let nums: Vec<i64> = line.split(' ').filter(|x| !x.is_empty()).map(|x| x.parse::<i64>().unwrap()).collect();
let increasing = nums.windows(2).all(|nums| {
let diff = nums[1] - nums[0];
nums[1] > nums[0] && diff >= 1 && diff <= 3
});
if increasing {
safe += 1;
continue;
}
let decreasing = nums.windows(2).all(|nums| {
let diff = nums[0] - nums[1];
nums[1] < nums[0] && diff >= 1 && diff <= 3
});
if decreasing {
safe += 1;
}
}
safe
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+61
View File
@@ -0,0 +1,61 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut safe = 0;
for line in input.lines().filter(|x| !x.is_empty()) {
let mut nums: Vec<i64> = line.split(' ').filter(|x| !x.is_empty()).map(|x| x.parse::<i64>().unwrap()).collect();
if test_array(&nums) {
safe += 1;
continue;
}
for i in 0..nums.len() {
let tmp = nums.remove(i);
if test_array(&nums) {
safe += 1;
break;
}
nums.insert(i, tmp);
}
}
safe
}
fn test_array(nums: &[i64]) -> bool {
nums.windows(2).all(|nums| {
let diff = nums[1] - nums[0];
nums[1] > nums[0] && diff >= 1 && diff <= 3
}) || nums.windows(2).all(|nums| {
let diff = nums[0] - nums[1];
nums[1] < nums[0] && diff >= 1 && diff <= 3
})
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+78
View File
@@ -0,0 +1,78 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))",
include_str!("./input.txt"),
];
pub fn run(file: &str) -> u64 {
let mut mul_count = 0;
let mut mul_active = false;
let mut first_num = true;
let mut num1 = 0;
let mut num2 = 0;
let mut sum = 0;
for c in file.chars() {
match c {
'm' if mul_count == 0 => {
mul_count += 1;
}
'u' if mul_count == 1 => {
mul_count += 1;
}
'l' if mul_count == 2 => {
mul_count += 1;
}
'(' if mul_count == 3 => {
mul_active=true;
first_num = true;
}
'0'..='9' if mul_active && first_num => {
let c = (c as u8 - b'0') as u64;
num1 *= 10;
num1 += c;
}
'0'..='9' if mul_active && !first_num => {
let c = (c as u8 - b'0') as u64;
num2 *= 10;
num2 += c;
}
',' if mul_active => {
first_num = false;
}
')' if mul_active => {
sum += num1 * num2;
num1 = 0;
num2 = 0;
mul_active = false;
mul_count = 0 ;
first_num = true;
}
_ => {
mul_active = false;
mul_count = 0;
num1 = 0;
num2 = 0;
}
}
}
return sum;
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+133
View File
@@ -0,0 +1,133 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> u64 {
let mut mul_count = 0;
let mut mul_active = false;
let mut dont_active = false;
let mut dont_count = 0;
let mut do_count = 0;
let mut first_num = true;
let mut sum = 0;
let mut num1 = 0;
let mut num2 = 0;
for c in input.chars() {
match c {
'd' => {
if dont_count == 0 {
dont_count += 1;
}
if do_count == 0 {
do_count += 1 ;
}
mul_count = 0;
}
'o' => {
if dont_count == 1 {
dont_count += 1;
}
if do_count == 1 {
do_count += 1;
}
mul_count = 0;
}
'n' if dont_count == 2 => {
dont_count += 1;
do_count = 0;
mul_count = 0;
}
'\'' if dont_count == 3 => {
dont_count += 1;
do_count = 0;
mul_count = 0;
}
't' if dont_count == 4 => {
dont_count += 1;
do_count = 0;
mul_count = 0;
}
'm' if mul_count == 0 => {
mul_count += 1;
do_count = 0;
dont_count = 0;
}
'u' if mul_count == 1 => {
mul_count += 1;
do_count = 0;
dont_count = 0;
}
'l' if mul_count == 2 => {
mul_count += 1;
do_count = 0;
dont_count = 0;
}
'(' if mul_count == 3 && !dont_active => {
mul_active=true;
first_num = true;
}
'(' if do_count == 2 => {
do_count += 1;
}
')' if do_count == 3 => {
dont_active = false;
}
'(' if dont_count == 5 => {
dont_count += 1;
}
')' if dont_count == 6 => {
dont_active = true;
}
'0'..='9' if mul_active && first_num => {
let c = (c as u8 - b'0') as u64;
num1 *= 10;
num1 += c;
}
'0'..='9' if mul_active && !first_num => {
let c = (c as u8 - b'0') as u64;
num2 *= 10;
num2 += c;
}
',' if mul_active => {
first_num = false;
}
')' if mul_active => {
sum += num1 * num2;
num1 = 0;
num2 = 0;
mul_active = false;
mul_count = 0 ;
first_num = true;
}
_ => {
mul_active = false;
mul_count = 0;
num1 = 0;
num2 = 0;
}
}
}
return sum;
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+103
View File
@@ -0,0 +1,103 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13
75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut input = input.split("\n\n");
let mut ordering = vec![vec![]; 100];
for order in input.next().unwrap().lines().map(|x| x.split('|').map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>()) {
let x = order[0];
let y = order[1];
ordering[x as usize].push(y);
}
let mut sum = 0;
let mut count = 0;
for line in input.next().unwrap().lines() {
let line = line.split(',').map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>();
if validate_order(&ordering, &line) {
let n = line.len();
sum += line[n/2];
} else {
count += 1;
}
}
println!("count = {:?}", count);
sum
}
fn validate_order(ordering: &Vec<Vec<i64>>, line: &Vec<i64>) -> bool {
let mut seen = FxHashSet::default();
for &num in line {
seen.insert(num);
let preorder = &ordering[num as usize];
if preorder.iter().any(|x| seen.contains(&x)) {
return false;
}
}
true
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+125
View File
@@ -0,0 +1,125 @@
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13
75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut input = input.split("\n\n");
let mut ordering = vec![vec![]; 100];
for order in input.next().unwrap().lines().map(|x| x.split('|').map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>()) {
let x = order[0];
let y = order[1];
ordering[x as usize].push(y);
}
let mut sum = 0;
for line in input.next().unwrap().lines() {
let line = line.split(',').map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>();
if !validate_order(&ordering, &line) {
let line = rearrange(&ordering, line);
let n = line.len();
sum += line[n/2];
}
}
sum
}
fn rearrange(ordering: &Vec<Vec<i64>>, mut line: Vec<i64>) -> Vec<i64> {
let mut out = vec![];
let result = dfs(&ordering, &mut out, &mut line);
out
}
fn dfs(ordering: &Vec<Vec<i64>>, out: &mut Vec<i64>, nums: &mut Vec<i64>) -> bool {
if !validate_order(&ordering, out) {
return false;
}
if nums.is_empty() {
return true;
}
for i in 0..nums.len() {
let num = nums.remove(i);
out.push(num);
if dfs(ordering, out, nums) {
return true;
}
out.pop();
nums.insert(i, num);
}
false
}
fn validate_order(ordering: &Vec<Vec<i64>>, line: &Vec<i64>) -> bool {
let mut seen = FxHashSet::default();
for &num in line {
seen.insert(num);
let preorder = &ordering[num as usize];
if preorder.iter().any(|x| seen.contains(&x)) {
return false;
}
}
true
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+128
View File
@@ -0,0 +1,128 @@
#![feature(iter_intersperse)]
#![feature(test)]
extern crate test;
use fxhash::FxHashSet;
const INPUTS: [&str; 2] = [
"....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let grid: Vec<Vec<u8>> = input.split(|&x| x == b'\n').filter(|x| !x.is_empty()).map(|x| x.to_vec()).collect();
let m = grid.len();
let n = grid[0].len();
let mut gx = 0i32;
let mut gy = 0i32;
for i in 0..m {
for j in 0..n {
if grid[i][j] == b'^' {
gx = i as i32;
gy = j as i32;
}
}
}
compute(&grid, gx, gy)
}
fn is_blocked(grid: &Vec<Vec<u8>>, x: i32, y: i32) -> bool {
let m = grid.len() as i32;
let n = grid[0].len() as i32;
if x < 0 || y < 0 || x >= m || y >= n {
return false;
}
unsafe {
*grid.get_unchecked(x as usize).get_unchecked(y as usize) == b'#'
}
}
fn should_turn(grid: &Vec<Vec<u8>>, x: i32, y: i32, direction: u8) -> (bool, u8) {
match direction {
0 => {
if is_blocked(&grid, x-1, y) {
return (true, 1);
}
}
1 => {
if is_blocked(&grid, x, y+1) {
return (true, 2);
}
}
2 => {
if is_blocked(&grid, x+1, y) {
return (true, 3);
}
}
3 => {
if is_blocked(&grid, x, y-1) {
return (true, 0);
}
}
_ => ()
}
return (false, direction)
}
fn compute(grid: &Vec<Vec<u8>>, mut x: i32, mut y: i32) -> i64 {
let m = grid.len();
let n = grid[0].len();
let mut set = FxHashSet::default();
let mut direction = 0;
while x >= 0 && y >= 0 && x < m as i32 && y < n as i32 {
set.insert((x,y));
// Might need maxiumum 2 consecutive turns
// perform those if needed
let turn;
(turn, direction) = should_turn(grid, x, y, direction);
if turn {
(_, direction) = should_turn(grid, x, y, direction);
}
match direction {
0 => x -= 1,
1 => y += 1,
2 => x += 1,
3 => y -= 1,
_ => ()
}
}
set.len() as i64
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+203
View File
@@ -0,0 +1,203 @@
#![feature(test)]
extern crate test;
use rayon::prelude::*;
const INPUTS: [&str; 2] = [
"....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let grid: Vec<Vec<u8>> = input
.split(|&x| x == b'\n')
.filter(|x| !x.is_empty())
.map(|x| x.to_vec())
.collect();
let m = grid.len();
let n = grid[0].len();
let mut gx = 0i32;
let mut gy = 0i32;
for i in 0..m {
for j in 0..n {
if grid[i][j] == b'^' {
gx = i as i32;
gy = j as i32;
}
}
}
let answer = (0..m)
.into_par_iter()
.map(|i| {
let grid = grid.clone();
(0..n)
.into_par_iter()
.map(move |j| {
if grid[i][j] != b'.' {
return 0;
}
let mut grid = grid.clone();
grid[i][j] = b'#';
if test(&grid, gx, gy) {
return 1;
}
0
})
.sum::<i64>()
})
.sum::<i64>();
answer
}
fn is_blocked(grid: &Vec<Vec<u8>>, x: i32, y: i32) -> bool {
let m = grid.len() as i32;
let n = grid[0].len() as i32;
if x < 0 || y < 0 || x >= m || y >= n {
return false;
}
unsafe { *grid.get_unchecked(x as usize).get_unchecked(y as usize) == b'#' }
}
fn should_turn(grid: &Vec<Vec<u8>>, x: i32, y: i32, direction: i32) -> (bool, i32) {
match direction {
0 => {
if is_blocked(&grid, x - 1, y) {
return (true, 1);
}
}
1 => {
if is_blocked(&grid, x, y + 1) {
return (true, 2);
}
}
2 => {
if is_blocked(&grid, x + 1, y) {
return (true, 3);
}
}
3 => {
if is_blocked(&grid, x, y - 1) {
return (true, 0);
}
}
_ => (),
}
return (false, direction);
}
fn test(grid: &Vec<Vec<u8>>, mut x: i32, mut y: i32) -> bool {
let m = grid.len();
let n = grid[0].len();
let mut direction = 0;
let limit = m * n;
let mut steps = 0;
let mut seen = Bitmap::new();
while x >= 0 && y >= 0 && x < m as i32 && y < n as i32 {
if steps > limit {
return true;
}
steps += 1;
if seen.get(x,y,direction) {
return true;
}
seen.set(x,y,direction);
// Might need maxiumum 2 consecutive turns
// perform those if needed
let turn;
(turn, direction) = should_turn(grid, x, y, direction);
if turn {
(_, direction) = should_turn(grid, x, y, direction);
}
match direction {
0 => x -= 1,
1 => y += 1,
2 => x += 1,
3 => y -= 1,
_ => (),
}
}
false
}
const ROW: usize = 130;
const COL: usize = 130;
const WORD_SIZE: usize = 64;
const SIZE: usize = (4 + ROW * ROW + ROW * COL * COL) / WORD_SIZE;
struct Bitmap {
inner: [u64; SIZE],
}
impl Bitmap {
#[allow(unused)]
fn new() -> Self {
Self { inner: [0; SIZE] }
}
#[allow(unused)]
const fn get(&self, x: i32, y: i32, dir: i32) -> bool {
let offset = (dir + ROW as i32 * (x + COL as i32 * y)) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
(self.inner[index] >> bit_offset & 1) == 1
}
#[allow(unused)]
fn set(&mut self, x: i32, y: i32, dir: i32) {
let offset = (dir + ROW as i32 * (x + COL as i32 * y)) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
self.inner[index] |= 1 << bit_offset;
}
#[allow(unused)]
fn count(&self) -> u32 {
let mut count = 0;
for c in self.inner.iter() {
count += c.count_ones();
}
count
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+66
View File
@@ -0,0 +1,66 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut sum = 0;
for line in input.lines().filter(|x| !x.is_empty()) {
let (total, nums) = line.split_once(": ").unwrap();
let total = total.parse::<i64>().unwrap();
let nums = nums.split(' ').filter(|x| !x.is_empty()).map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>();
if test(&nums, total, 0) {
sum += total;
}
}
sum
}
fn test(nums: &[i64], target: i64, so_far: i64) -> bool {
if so_far == target && nums.is_empty() {
return true;
}
if so_far > target || nums.is_empty() {
return false;
}
if test(&nums[1..], target, if so_far == 0 { 1 } else { so_far } * nums[0]) {
return true;
}
if test(&nums[1..], target, so_far + nums[0]) {
return true;
}
false
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+75
View File
@@ -0,0 +1,75 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let mut sum = 0;
for line in input.lines() {
let (total, nums) = line.split_once(": ").unwrap();
let total = total.parse::<i64>().unwrap();
let nums = nums.split(' ').map(|x| x.parse::<i64>().unwrap()).collect::<Vec<i64>>();
if test(&nums, total, 0) {
sum += total;
}
}
sum
}
fn test(nums: &[i64], target: i64, so_far: i64) -> bool {
if so_far == target && nums.is_empty() {
return true;
}
if so_far > target || nums.is_empty() {
return false;
}
if test(&nums[1..], target, concat(so_far, nums[0])) {
return true;
}
if test(&nums[1..], target, if so_far == 0 { 1 } else { so_far } * nums[0]) {
return true;
}
if test(&nums[1..], target, so_far + nums[0]) {
return true;
}
false
}
#[inline]
const fn concat(a: i64, b: i64) -> i64 {
a * 10i64.pow(b.ilog(10) + 1) + b
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+120
View File
@@ -0,0 +1,120 @@
#![feature(iter_intersperse)]
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let size = input.iter().position(|&x| x == b'\n').unwrap();
let mut map = vec![Vec::with_capacity(size); 128];
for i in 0..size {
for j in 0..size {
let c = input[i*size+j+i];
if c == b'.' {
continue;
}
map[c as usize].push((i as i32, j as i32));
}
}
let mut seen = Bitmap::new(size as i32);
for pos in map {
for p in 0..pos.len() {
let (a1,b1) = pos[p];
for q in p+1..pos.len() {
let (a2,b2) = pos[q];
let dx = (a1 - a2).abs();
let dy = (b1 - b2).abs();
let mut p1x = a1;
let mut p1y = b1;
let mut p2x = a2;
let mut p2y = b2;
if a1 < a2 && b1 < b2 {
p1x -= dx;
p1y -= dy;
p2x += dx;
p2y += dy;
} else if a1 < a2 && b1 > b2 {
p1x -= dx;
p1y += dy;
p2x += dx;
p2y -= dy;
}
seen.set(p1x,p1y);
seen.set(p2x,p2y);
}
}
}
seen.count() as i64
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: Vec<u64>,
size: i32,
}
impl Bitmap {
fn new(size: i32) -> Self {
Self { inner: vec![0; ((size * size) as usize / WORD_SIZE) + 1], size }
}
fn set(&mut self, x: i32, y: i32) {
if x < 0 || y < 0 || x >= self.size || y >= self.size {
return;
}
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
self.inner[index] |= 1 << bit_offset;
}
fn count(&self) -> u32 {
let mut count = 0;
for c in self.inner.iter() {
count += c.count_ones();
}
count
}
}
fn main() {
for input in INPUTS.iter().take(3) {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+127
View File
@@ -0,0 +1,127 @@
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"T.........
...T......
.T........
..........
..........
..........
..........
..........
..........
..........",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let size = input.iter().position(|&x| x == b'\n').unwrap();
let mut map = vec![Vec::with_capacity(size); 128];
for i in 0..size {
for j in 0..size {
let c = input[i*size+j+i];
if c == b'.' {
continue;
}
map[c as usize].push((i as i32, j as i32));
}
}
let mut seen = Bitmap::new(size as i32);
for pos in map {
for p in 0..pos.len() {
let (a1,b1) = pos[p];
seen.set(a1,b1);
for q in p+1..pos.len() {
let (a2,b2) = pos[q];
let dx = (a1 - a2).abs();
let dy = (b1 - b2).abs();
let mut p1x = a1;
let mut p1y = b1;
let mut p2x = a2;
let mut p2y = b2;
while p1x >= 0 && p1y >= 0 && p1x < size as i32 && p1y < size as i32 {
if a1 < a2 && b1 < b2 {
p1x -= dx;
p1y -= dy;
} else if a1 < a2 && b1 > b2 {
p1x += dx;
p1y -= dy;
}
seen.set(p1x,p1y);
}
while p2x >= 0 && p2y >= 0 && p2x < size as i32 && p2y < size as i32 {
if a1 < a2 && b1 < b2 {
p2x += dx;
p2y += dy;
} else if a1 < a2 && b1 > b2 {
p2x -= dx;
p2y += dy;
}
seen.set(p2x,p2y);
}
}
}
}
seen.count() as i64
}
const WORD_SIZE: usize = 64;
struct Bitmap {
inner: Vec<u64>,
size: i32,
}
impl Bitmap {
fn new(size: i32) -> Self {
Self { inner: vec![0; ((size * size) as usize / WORD_SIZE) + 1], size }
}
fn set(&mut self, x: i32, y: i32) {
if x < 0 || y < 0 || x >= self.size || y >= self.size {
return;
}
let offset = (x * self.size + y) as usize;
let index = offset / WORD_SIZE;
let bit_offset = offset % WORD_SIZE;
self.inner[index] |= 1 << bit_offset;
}
fn count(&self) -> u32 {
let mut count = 0;
for c in self.inner.iter() {
count += c.count_ones();
}
count
}
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+83
View File
@@ -0,0 +1,83 @@
#![feature(test)]
extern crate test;
use std::collections::VecDeque;
const INPUTS: [&str; 2] = [
"2333133121414131402",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
let input = input.as_bytes();
let mut is_space = false;
let mut block_id = 0;
let mut offset = 0;
let mut zeroes = VecDeque::with_capacity(input.len() / 2);
let mut blocks = Vec::with_capacity(input.len() / 2);
for c in input {
if c.is_ascii_whitespace() {
continue;
}
let n = (c - b'0') as i64;
if is_space {
zeroes.push_back((offset, n));
} else {
blocks.push((block_id, offset, n));
block_id += 1;
}
offset += n;
is_space = !is_space;
}
let mut answer = 0;
for (block_id, block_offset, mut block_len) in blocks.into_iter().rev() {
if block_id == 0 {
continue;
}
while block_len > 0 {
let Some((zero_offset, zero_len)) = zeroes.pop_front() else {
let sum = ((block_offset + block_len - 1) * (block_offset + block_len + 1 - 1) / 2) - ((block_offset - 1) * (block_offset + 1 - 1) / 2);
answer += block_id * sum;
break;
};
if zero_offset > block_offset {
let sum = ((block_offset + block_len - 1) * (block_offset + block_len + 1 - 1) / 2) - ((block_offset - 1) * (block_offset + 1 - 1) / 2);
answer += block_id * sum;
break;
}
let moveable = std::cmp::min(block_len, zero_len);
let sum = ((zero_offset + moveable - 1) * (zero_offset + moveable + 1 - 1) / 2) - ((zero_offset - 1) * (zero_offset + 1 - 1) / 2);
answer += block_id * sum;
if zero_len > block_len {
zeroes.push_front((zero_offset + block_len, zero_len - block_len));
}
block_len = std::cmp::max(0, block_len - zero_len);
}
}
answer as i64
}
fn main() {
for input in INPUTS.iter().take(3) {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+88
View File
@@ -0,0 +1,88 @@
#![feature(test)]
extern crate test;
use std::collections::BinaryHeap;
use std::cmp::Reverse;
const INPUTS: [&str; 2] = [
"2333133121414131402",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> u64 {
let input = input.as_bytes();
let mut is_space = false;
let mut block_id = 0;
let mut offset = 0;
let mut zeroes = [const { BinaryHeap::new() }; 10];
let mut blocks = Vec::with_capacity(input.len() / 2);
for c in input {
if c.is_ascii_whitespace() {
continue;
}
let n = (c - b'0') as usize;
if is_space {
zeroes[n].push(Reverse(offset));
} else {
blocks.push((block_id, offset, n));
block_id += 1;
}
offset += n;
is_space = !is_space;
}
for (_, block_offset, block_len) in blocks.iter_mut().rev() {
let mut zero_offset = std::usize::MAX;
let mut zero_len = 0;
for (i, heap) in zeroes[*block_len..].iter().enumerate() {
if let Some(&Reverse(offset)) = heap.peek() {
if offset < zero_offset && offset < *block_offset {
zero_offset = offset;
zero_len = *block_len + i;
}
}
}
if zero_offset == std::usize::MAX {
continue;
}
zeroes[zero_len].pop();
if zero_len == *block_len {
std::mem::swap(&mut zero_offset, block_offset);
} else {
*block_offset = zero_offset;
zero_len -= *block_len;
zero_offset += *block_len;
zeroes[zero_len].push(Reverse(zero_offset));
}
}
let mut sum = 0;
for (id, offset, len) in blocks {
let range_sum = ((offset + len - 1) * (offset + len + 1 - 1) / 2) - ((offset - 1) * (offset + 1 - 1) / 2);
sum += id * range_sum;
}
sum as u64
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}
+106
View File
@@ -0,0 +1,106 @@
use std::{env, fs::{self, File}, io};
use std::path::Path;
const AOC_TOKEN: &str = include_str!("../.aoc_token");
const P1_TEMPLATE: &str = r#"
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part1(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}"#;
const P2_TEMPLATE: &str = r#"
#![feature(test)]
extern crate test;
const INPUTS: [&str; 2] = [
"",
include_str!("./input.txt"),
];
pub fn run(input: &str) -> i64 {
}
fn main() {
for input in INPUTS.iter() {
println!("answer = {}", run(input));
}
}
#[bench]
fn part2(b: &mut test::Bencher) {
b.iter(|| {
let v = run(INPUTS[1]);
test::black_box(v);
});
}"#;
fn main() {
let args: Vec<String> = env::args().collect();
assert!(args.len() == 2);
let day: u8 = args[1].parse::<u8>().expect("error in parsing day");
assert!((1..=25).contains(&day));
let request = ureq::get(&format!("https://adventofcode.com/2024/day/{}/input", day))
.set("Cookie", AOC_TOKEN);
println!("{:?}", request);
let response = match request.call() {
Ok(r) => r,
Err(e) => {
eprintln!("error in fetching input for day {}: {}", day, e);
if let Some(v) = e.into_response() {
eprintln!(
"error in fetching input for day {} status code = {} response = {:?}",
day,
v.status(),
v.into_string()
);
}
return;
}
};
// Create directory
let path = format!("./src/day{}", day);
if !Path::new(&path).exists() {
fs::create_dir(&path).expect("error in creating directory");
}
// Create the file
let mut file =
File::create(format!("./{}/input.txt", path)).expect("error in creating file");
// Copy contents to file
io::copy(&mut response.into_reader(), &mut file).expect("error in writing to file");
// Generate 1.rs and 2.rs from templates
fs::write(format!("./{}/1.rs", path), P1_TEMPLATE).expect("error in generating template 1.rs");
fs::write(format!("./{}/2.rs", path), P2_TEMPLATE).expect("error in generating template 1.rs");
println!("Saved input for day {}", day);
}