This commit is contained in:
parent
8b011941c4
commit
c6153663b5
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 7.7 KiB |
@ -1,6 +1,6 @@
|
|||||||
<!-- AOC TILES BEGIN -->
|
<!-- AOC TILES BEGIN -->
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
2024 - 26 ⭐ - Rust
|
2024 - 28 ⭐ - Rust
|
||||||
</h1>
|
</h1>
|
||||||
<a href="src/day1.rs">
|
<a href="src/day1.rs">
|
||||||
<img src=".aoc_tiles/tiles/2024/01.png" width="161px">
|
<img src=".aoc_tiles/tiles/2024/01.png" width="161px">
|
||||||
@ -41,4 +41,7 @@
|
|||||||
<a href="src/day13.rs">
|
<a href="src/day13.rs">
|
||||||
<img src=".aoc_tiles/tiles/2024/13.png" width="161px">
|
<img src=".aoc_tiles/tiles/2024/13.png" width="161px">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="src/day14.rs">
|
||||||
|
<img src=".aoc_tiles/tiles/2024/14.png" width="161px">
|
||||||
|
</a>
|
||||||
<!-- AOC TILES END -->
|
<!-- AOC TILES END -->
|
||||||
|
171
src/day14.rs
Normal file
171
src/day14.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use aoc_runner_derive::aoc;
|
||||||
|
use grid::{AsCoord2d, Coord2d, Grid};
|
||||||
|
use regex::Regex;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
struct Robot {
|
||||||
|
pos: Coord2d,
|
||||||
|
vel: Coord2d,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
enum Quadrant {
|
||||||
|
NW = 0,
|
||||||
|
NE = 1,
|
||||||
|
SW = 2,
|
||||||
|
SE = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Robot {
|
||||||
|
type Err = Box<dyn std::error::Error>;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let re = Regex::new(r"p=(\d+),(\d+) v=([+-]?\d+),([+-]?\d+)").unwrap();
|
||||||
|
match re.captures(s) {
|
||||||
|
Some(c) => Ok(Self {
|
||||||
|
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 {
|
||||||
|
fn step(&mut self, bounds: (i64, i64)) {
|
||||||
|
let mut candidate_new_pos = ((self.pos.x() + self.vel.x()), (self.pos.y() + self.vel.y()));
|
||||||
|
if candidate_new_pos.0 < 0 {
|
||||||
|
// if pos goes negative, add the upper bound
|
||||||
|
candidate_new_pos.0 += bounds.0;
|
||||||
|
}
|
||||||
|
if candidate_new_pos.1 < 0 {
|
||||||
|
candidate_new_pos.1 += bounds.1;
|
||||||
|
}
|
||||||
|
candidate_new_pos.0 %= bounds.0;
|
||||||
|
candidate_new_pos.1 %= bounds.1;
|
||||||
|
|
||||||
|
self.pos = candidate_new_pos.to_coord();
|
||||||
|
}
|
||||||
|
fn quad(&self, bounds: (i64, i64)) -> Option<Quadrant> {
|
||||||
|
let splits = (bounds.0 / 2, bounds.1 / 2);
|
||||||
|
if self.pos.x() < splits.0 && self.pos.y() < splits.1 {
|
||||||
|
Some(Quadrant::NW)
|
||||||
|
} else if self.pos.x() > splits.0 && self.pos.y() < splits.1 {
|
||||||
|
Some(Quadrant::NE)
|
||||||
|
} else if self.pos.x() < splits.0 && self.pos.y() > splits.1 {
|
||||||
|
Some(Quadrant::SW)
|
||||||
|
} else if self.pos.x() > splits.0 && self.pos.y() > splits.1 {
|
||||||
|
Some(Quadrant::SE)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn display(robots: &Vec<Robot>, bounds: (i64, i64)) {
|
||||||
|
let grid = as_grid(robots, bounds);
|
||||||
|
for row in 0..grid.height() {
|
||||||
|
for col in 0..grid.width() {
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
if *grid.get(&(col, row)).unwrap() != 0 {
|
||||||
|
"█"
|
||||||
|
} else {
|
||||||
|
" "
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!(" EOL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_grid(robots: &Vec<Robot>, bounds: (i64, i64)) -> Grid<usize> {
|
||||||
|
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 {
|
||||||
|
let mut robots = parse(input);
|
||||||
|
for _ in 0..100 {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part1)]
|
||||||
|
pub fn part1(input: &str) -> u64 {
|
||||||
|
part1_impl(input, 101, 103)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part2)]
|
||||||
|
pub fn part2(input: &str) -> u64 {
|
||||||
|
let width = 101;
|
||||||
|
let height = 103;
|
||||||
|
let mut robots = parse(input);
|
||||||
|
for i in 1.. {
|
||||||
|
for r in &mut robots {
|
||||||
|
r.step((width, height))
|
||||||
|
}
|
||||||
|
// collect into lines
|
||||||
|
let g = as_grid(&robots, (width, height));
|
||||||
|
if g.data
|
||||||
|
.chunk_by(|a, b| *a != 0 && *b != 0)
|
||||||
|
.filter(|c| !c.is_empty() && c[0] != 0)
|
||||||
|
.any(|c| c.len() > width as usize / 10)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
const EXAMPLE: &str = "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";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1_impl(EXAMPLE, 11, 7), 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// part 2 does not converge using the test vector
|
||||||
|
// #[test]
|
||||||
|
// fn part2_example() {
|
||||||
|
// // assert_eq!(part2(EXAMPLE), 0);
|
||||||
|
// }
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
use aoc_runner_derive::aoc_lib;
|
use aoc_runner_derive::aoc_lib;
|
||||||
|
|
||||||
pub mod day1;
|
pub mod day1;
|
||||||
|
pub mod day10;
|
||||||
|
pub mod day11;
|
||||||
|
pub mod day12;
|
||||||
|
pub mod day13;
|
||||||
|
pub mod day14;
|
||||||
pub mod day2;
|
pub mod day2;
|
||||||
pub mod day3;
|
pub mod day3;
|
||||||
pub mod day4;
|
pub mod day4;
|
||||||
@ -9,9 +14,5 @@ pub mod day6;
|
|||||||
pub mod day7;
|
pub mod day7;
|
||||||
pub mod day8;
|
pub mod day8;
|
||||||
pub mod day9;
|
pub mod day9;
|
||||||
pub mod day10;
|
|
||||||
pub mod day11;
|
|
||||||
pub mod day12;
|
|
||||||
pub mod day13;
|
|
||||||
|
|
||||||
aoc_lib! { year = 2024 }
|
aoc_lib! { year = 2024 }
|
||||||
|
@ -3,7 +3,7 @@ use std::{
|
|||||||
io::{BufRead, Cursor},
|
io::{BufRead, Cursor},
|
||||||
iter::repeat,
|
iter::repeat,
|
||||||
mem::swap,
|
mem::swap,
|
||||||
ops::{Add, Sub},
|
ops::{Add, AddAssign, Sub},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,6 +51,18 @@ impl AsCoord2d for Coord2d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsCoord2d for &Coord2d {
|
||||||
|
fn to_coord(self) -> Coord2d {
|
||||||
|
self.to_owned()
|
||||||
|
}
|
||||||
|
fn x(&self) -> i64 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
fn y(&self) -> i64 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsCoord2d for (i32, i32) {
|
impl AsCoord2d for (i32, i32) {
|
||||||
fn to_coord(self) -> Coord2d {
|
fn to_coord(self) -> Coord2d {
|
||||||
Coord2d {
|
Coord2d {
|
||||||
@ -178,6 +190,18 @@ impl<T: Clone + Eq + PartialEq + Display + Debug> Grid<T> {
|
|||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn increment<'a, A, C: AsCoord2d>(&'a mut self, c: &C, i: A) -> Option<&'a T>
|
||||||
|
where
|
||||||
|
T: AddAssign<A>,
|
||||||
|
{
|
||||||
|
match self.valid_pos(c) {
|
||||||
|
Some(pos) => {
|
||||||
|
self.data[pos] += i;
|
||||||
|
Some(&self.data[pos])
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn row(&self, y: i64) -> Option<&[T]> {
|
pub fn row(&self, y: i64) -> Option<&[T]> {
|
||||||
if y < self.height() as i64 {
|
if y < self.height() as i64 {
|
||||||
Some(&self.data[self.pos(&(0, y)) as usize..self.pos(&(self.width, y)) as usize])
|
Some(&self.data[self.pos(&(0, y)) as usize..self.pos(&(self.width, y)) as usize])
|
||||||
@ -300,7 +324,10 @@ FBCG";
|
|||||||
fn from_string() {
|
fn from_string() {
|
||||||
let grid = unchecked_load();
|
let grid = unchecked_load();
|
||||||
assert_eq!(grid.data, "ABCDEFGHIJKLFBCG".as_bytes());
|
assert_eq!(grid.data, "ABCDEFGHIJKLFBCG".as_bytes());
|
||||||
assert_eq!(TEST_VECTOR_S.parse::<Grid<u8>>().unwrap().data, "ABCDEFGHIJKLFBCG".as_bytes());
|
assert_eq!(
|
||||||
|
TEST_VECTOR_S.parse::<Grid<u8>>().unwrap().data,
|
||||||
|
"ABCDEFGHIJKLFBCG".as_bytes()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user