Compare commits

..

No commits in common. "bd91fcb60c46f3f293e94998991fb923de181f36" and "de7ee8f0f6942036015d27ddba6067b8735b7859" have entirely different histories.

6 changed files with 104 additions and 272 deletions

82
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "ahash" name = "ahash"
@ -70,8 +70,6 @@ dependencies = [
"colored", "colored",
"grid", "grid",
"itertools", "itertools",
"misc",
"nom",
"rayon", "rayon",
"regex", "regex",
"rustc-hash", "rustc-hash",
@ -146,9 +144,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "colored" name = "colored"
version = "2.2.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"windows-sys", "windows-sys",
@ -156,9 +154,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.6" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [ dependencies = [
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
@ -175,9 +173,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.21" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]] [[package]]
name = "darling" name = "darling"
@ -289,29 +287,6 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "misc"
version = "0.1.0"
dependencies = [
"num-traits",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@ -574,23 +549,22 @@ dependencies = [
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.59.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
"windows_i686_gnu", "windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc",
"windows_x86_64_gnu", "windows_x86_64_gnu",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm",
@ -599,51 +573,45 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"

View File

@ -1,7 +1,7 @@
[package] [package]
edition = "2021"
name = "aoc2024" name = "aoc2024"
version = "0.1.0" version = "0.1.0"
edition = "2021"
[dependencies] [dependencies]
aoc-runner = "0.3.0" aoc-runner = "0.3.0"
@ -10,10 +10,8 @@ atoi = "2.0.0"
bitflags = "2.6.0" bitflags = "2.6.0"
cached = "0.54.0" cached = "0.54.0"
colored = "2.1.0" colored = "2.1.0"
grid = {version = "0.1.0", path = "utils/grid"} grid = { version = "0.1.0", path = "utils/grid" }
itertools = "0.13.0" itertools = "0.13.0"
misc = {path = "utils/misc"}
nom = "7.1.3"
rayon = "1.10.0" rayon = "1.10.0"
regex = "1.11.1" regex = "1.11.1"
rustc-hash = "2.1.0" rustc-hash = "2.1.0"

View File

@ -1,27 +1,12 @@
use aoc_runner_derive::aoc; use aoc_runner_derive::aoc;
use colored::Colorize; use colored::Colorize;
use grid::{AsCoord2d, Coord2d, Grid}; use grid::{AsCoord2d, Coord2d, Grid};
use misc::CustomWrapped;
use nom::{
bytes::complete::tag,
character::complete::digit1,
combinator::{map_res, opt, recognize},
sequence::{preceded, separated_pair},
IResult,
};
use regex::Regex; use regex::Regex;
use std::{fmt::Display, str::FromStr}; use std::str::FromStr;
type Coord = (CustomWrapped<i64>, CustomWrapped<i64>);
struct Robot { struct Robot {
pos: Coord, pos: Coord2d,
vel: (i64, i64), vel: Coord2d,
}
struct Robots {
robots: Vec<Robot>,
width: i64,
height: i64,
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -32,37 +17,52 @@ enum Quadrant {
SE = 3, SE = 3,
} }
fn nom_i64(input: &str) -> IResult<&str, i64> { impl FromStr for Robot {
let (i, number) = map_res(recognize(preceded(opt(tag("-")), digit1)), |s| i64::from_str(s))(input)?; type Err = Box<dyn std::error::Error>;
Ok((i, number)) fn from_str(s: &str) -> Result<Self, Self::Err> {
} let re = Regex::new(r"p=(\d+),(\d+) v=([+-]?\d+),([+-]?\d+)").unwrap();
fn nom_i64_pair(input: &str) -> IResult<&str, (i64, i64)> { match re.captures(s) {
let (i, pair) = separated_pair(nom_i64, tag(","), nom_i64)(input)?; Some(c) => Ok(Self {
Ok((i, pair)) pos: (
c.get(1).unwrap().as_str().parse::<i64>().unwrap(),
c.get(2).unwrap().as_str().parse().unwrap(),
)
.to_coord(),
vel: (
c.get(3).unwrap().as_str().parse::<i64>().unwrap(),
c.get(4).unwrap().as_str().parse().unwrap(),
)
.to_coord(),
}),
None => panic!(),
}
}
} }
impl Robot { impl Robot {
fn from_str(s: &str, bounds: (i64, i64)) -> Self { fn step(&mut self, bounds: (i64, i64)) {
let (s, pos) = preceded(tag("p="), nom_i64_pair)(s).unwrap(); let mut candidate_new_pos = ((self.pos.x() + self.vel.x()), (self.pos.y() + self.vel.y()));
let (_, vel) = preceded(tag(" v="), nom_i64_pair)(s).unwrap(); if candidate_new_pos.0 < 0 {
Self { // if pos goes negative, add the upper bound
pos: (CustomWrapped::new(pos.0, bounds.0), CustomWrapped::new(pos.1, bounds.1)), candidate_new_pos.0 += bounds.0;
vel,
} }
if candidate_new_pos.1 < 0 {
candidate_new_pos.1 += bounds.1;
} }
fn step(&mut self, count: i64) { candidate_new_pos.0 %= bounds.0;
self.pos.0 += self.vel.x() * count; candidate_new_pos.1 %= bounds.1;
self.pos.1 += self.vel.y() * count;
self.pos = candidate_new_pos.to_coord();
} }
fn quad(&self, bounds: (i64, i64)) -> Option<Quadrant> { fn quad(&self, bounds: (i64, i64)) -> Option<Quadrant> {
let splits = (bounds.0 / 2, bounds.1 / 2); let splits = (bounds.0 / 2, bounds.1 / 2);
if self.pos.0 < splits.0 && self.pos.1 < splits.1 { if self.pos.x() < splits.0 && self.pos.y() < splits.1 {
Some(Quadrant::NW) Some(Quadrant::NW)
} else if self.pos.0 > splits.0 && self.pos.1 < splits.1 { } else if self.pos.x() > splits.0 && self.pos.y() < splits.1 {
Some(Quadrant::NE) Some(Quadrant::NE)
} else if self.pos.0 < splits.0 && self.pos.1 > splits.1 { } else if self.pos.x() < splits.0 && self.pos.y() > splits.1 {
Some(Quadrant::SW) Some(Quadrant::SW)
} else if self.pos.0 > splits.0 && self.pos.1 > splits.1 { } else if self.pos.x() > splits.0 && self.pos.y() > splits.1 {
Some(Quadrant::SE) Some(Quadrant::SE)
} else { } else {
None None
@ -70,58 +70,49 @@ impl Robot {
} }
} }
impl Robots { #[allow(dead_code)]
fn from_vec(robots: Vec<Robot>, width: i64, height: i64) -> Self { fn display(robots: &Vec<Robot>, bounds: (i64, i64)) {
Self { robots, width, height } let grid = as_grid(robots, bounds);
}
fn as_grid(&self) -> Grid<usize> {
let mut grid = Grid::with_shape(self.width as usize, self.height as usize, 0usize);
for r in &self.robots {
grid.increment(&(r.pos.0.val, r.pos.1.val), 1usize);
}
grid
}
fn count_quads(&self) -> [u64; 4] {
let mut counts = [0; 4];
for r in &self.robots {
if let Some(q) = r.quad((self.width, self.height)) {
counts[q as usize] += 1
}
}
counts
}
fn step(&mut self, count: i64) {
for robot in &mut self.robots {
robot.step(count)
}
}
}
impl Display for Robots {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let grid = self.as_grid();
for row in 0..grid.height() { for row in 0..grid.height() {
for col in 0..grid.width() { for col in 0..grid.width() {
print!(
"{}",
if *grid.get(&(col, row)).unwrap() != 0 { if *grid.get(&(col, row)).unwrap() != 0 {
"".green().fmt(f)?; "".green()
} else { } else {
" ".color(colored::Color::Black).fmt(f)?; " ".color(colored::Color::Black)
} }
);
} }
writeln!(f)? println!();
}
Ok(())
} }
} }
fn parse(input: &str, width: i64, height: i64) -> Vec<Robot> { fn as_grid(robots: &Vec<Robot>, bounds: (i64, i64)) -> Grid<usize> {
input.lines().map(|l| Robot::from_str(l, (width, height))).collect() let mut grid = Grid::with_shape(bounds.0 as usize, bounds.1 as usize, 0);
for r in robots {
grid.increment(&r.pos, 1usize);
}
grid
}
fn parse(input: &str) -> Vec<Robot> {
input.lines().map(|l| l.parse().unwrap()).collect()
} }
fn part1_impl(input: &str, width: i64, height: i64) -> u64 { fn part1_impl(input: &str, width: i64, height: i64) -> u64 {
let mut robots = Robots::from_vec(parse(input, width, height), width, height); let mut robots = parse(input);
robots.step(100); for _ in 0..100 {
let counts = robots.count_quads(); for r in &mut robots {
r.step((width, height))
}
}
let mut counts = [0; 4];
for r in robots {
if let Some(q) = r.quad((width, height)) {
counts[q as usize] += 1
}
}
counts.iter().product() counts.iter().product()
} }
@ -134,11 +125,13 @@ pub fn part1(input: &str) -> u64 {
pub fn part2(input: &str) -> u64 { pub fn part2(input: &str) -> u64 {
let width = 101; let width = 101;
let height = 103; let height = 103;
let mut robots = Robots::from_vec(parse(input, width, height), width, height); let mut robots = parse(input);
for i in 1.. { for i in 1.. {
robots.step(1); for r in &mut robots {
r.step((width, height))
}
// collect into lines // collect into lines
let g = robots.as_grid(); let g = as_grid(&robots, (width, height));
if g.data if g.data
.chunk_by(|a, b| *a != 0 && *b != 0) .chunk_by(|a, b| *a != 0 && *b != 0)
.filter(|c| !c.is_empty() && c[0] != 0) .filter(|c| !c.is_empty() && c[0] != 0)

25
utils/misc/Cargo.lock generated
View File

@ -1,25 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "misc"
version = "0.1.0"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]

View File

@ -1,7 +0,0 @@
[package]
name = "misc"
version = "0.1.0"
edition = "2021"
[dependencies]
num-traits = "0.2.19"

View File

@ -1,95 +0,0 @@
use num_traits::Signed;
use std::ops::{Add, AddAssign};
use std::fmt::{Debug, Display};
/// Wrapped signed integer with custom upper bound with wrapping of 0s to the upper bound
#[derive(Eq, Clone, Copy)]
pub struct CustomWrapped<T: Signed + Copy> {
pub val: T,
pub bound: T,
}
impl<T: Signed + Copy> Add<T> for CustomWrapped<T> {
type Output = CustomWrapped<T>;
fn add(self, rhs: T) -> Self::Output {
Self {
val: ((self.val + rhs % self.bound) + self.bound) % self.bound,
bound: self.bound,
}
}
}
impl<T: Signed + Copy> Add<T> for &CustomWrapped<T> {
type Output = CustomWrapped<T>;
fn add(self, rhs: T) -> Self::Output {
CustomWrapped {
val: ((self.val + rhs % self.bound) + self.bound) % self.bound,
bound: self.bound,
}
}
}
impl<T: Signed + Copy> AddAssign<T> for CustomWrapped<T> {
fn add_assign(&mut self, rhs: T) {
self.val = ((self.val + rhs % self.bound) + self.bound) % self.bound
}
}
impl<T: Signed + Copy> CustomWrapped<T> {
pub fn new(val: T, bound: T) -> Self {
Self { val, bound }
}
}
impl<T: Signed + Copy + PartialEq> PartialEq for CustomWrapped<T> {
fn eq(&self, other: &Self) -> bool {
self.val.eq(&other.val)
}
}
impl<T: Signed + PartialOrd + Copy> PartialOrd for CustomWrapped<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.val.partial_cmp(&other.val)
}
}
impl<T: Signed + Ord + Copy> Ord for CustomWrapped<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.val.cmp(&other.val)
}
}
impl<T: Signed + PartialEq + Copy> PartialEq<T> for CustomWrapped<T> {
fn eq(&self, other: &T) -> bool {
self.val == *other
}
}
impl<T: Signed + PartialOrd + Copy> PartialOrd<T> for CustomWrapped<T> {
fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
self.val.partial_cmp(other)
}
}
impl<T: Display + Signed + Copy> Display for CustomWrapped<T> where T: Display {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.val.fmt(f)
}
}
// impl<T> Into<T> for CustomWrapped<T> {
// fn into(self) -> T {
// self.val
// }
// }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}