add 2023/14/2
This commit is contained in:
parent
433b554594
commit
50bd733e55
|
@ -1,14 +1,14 @@
|
||||||
#![feature(test, try_blocks)]
|
#![feature(test, try_blocks)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use aoc2023::{boilerplate, common::*, direction::Direction};
|
use aoc2023::{boilerplate, common::*};
|
||||||
use itertools::Itertools;
|
use fnv::{FnvHashMap, FnvHasher};
|
||||||
use std::mem::transmute;
|
use std::{hash::Hasher, mem::transmute};
|
||||||
|
|
||||||
const DAY: usize = 14;
|
const DAY: usize = 14;
|
||||||
type Parsed = Vec<Vec<Tile>>;
|
type Parsed = Vec<Vec<Tile>>;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum Tile {
|
enum Tile {
|
||||||
Round = b'O',
|
Round = b'O',
|
||||||
|
@ -16,33 +16,65 @@ enum Tile {
|
||||||
Empty = b'.',
|
Empty = b'.',
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_index(x: usize, y: usize, direction: Direction) -> Option<(usize, usize)> {
|
|
||||||
match direction {
|
|
||||||
Direction::Up => Some((x, y.checked_sub(1)?)),
|
|
||||||
Direction::Down => Some((x, y + 1)),
|
|
||||||
Direction::Right => Some((x + 1, y)),
|
|
||||||
Direction::Left => Some((x.checked_sub(1)?, y)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(raw: &str) -> Parsed {
|
fn parse_input(raw: &str) -> Parsed {
|
||||||
raw.lines().map(|l| unsafe { transmute::<&str, &[Tile]>(l) }.to_vec()).collect()
|
raw.lines().map(|l| unsafe { transmute::<&str, &[Tile]>(l) }.to_vec()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tilt(grid: &mut Parsed, direction: Direction) {
|
fn tilt_north(grid: &mut Parsed) {
|
||||||
for y in 0..grid.len() {
|
for y in 0..grid.len() {
|
||||||
|
for x in 0..grid[y].len() {
|
||||||
|
if grid[y][x] == Tile::Round {
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some(Tile::Empty) = try { grid.get(y.checked_sub(i + 1)?)?[x] } {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
grid[y][x] = Tile::Empty;
|
||||||
|
grid[y - i][x] = Tile::Round;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tilt_west(grid: &mut Parsed) {
|
||||||
|
for y in 0..grid.len() {
|
||||||
|
for x in 0..grid[y].len() {
|
||||||
|
if grid[y][x] == Tile::Round {
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some(Tile::Empty) = try { grid[y][x.checked_sub(i + 1)?] } {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
grid[y][x] = Tile::Empty;
|
||||||
|
grid[y][x - i] = Tile::Round;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tilt_south(grid: &mut Parsed) {
|
||||||
|
for y in (0..grid.len()).rev() {
|
||||||
for x in 0..(grid[y].len()) {
|
for x in 0..(grid[y].len()) {
|
||||||
if grid[y][x] == Tile::Round {
|
if grid[y][x] == Tile::Round {
|
||||||
grid[y][x] = Tile::Empty;
|
let mut i = 0;
|
||||||
let (mut x, mut y) = (x, y);
|
while let Some(Tile::Empty) = try { grid.get(y + i + 1)?[x] } {
|
||||||
// While the next position is valid, move 1 step
|
i += 1;
|
||||||
while let Some(idx) = try {
|
|
||||||
let (next_x, next_y) = next_index(x, y, direction)?;
|
|
||||||
(*grid.get(next_y)?.get(next_x)? == Tile::Empty).then_some((next_x, next_y))?
|
|
||||||
} {
|
|
||||||
(x, y) = idx;
|
|
||||||
}
|
}
|
||||||
grid[y][x] = Tile::Round;
|
grid[y][x] = Tile::Empty;
|
||||||
|
grid[y + i][x] = Tile::Round;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tilt_east(grid: &mut Parsed) {
|
||||||
|
for y in 0..grid.len() {
|
||||||
|
for x in (0..grid[y].len()).rev() {
|
||||||
|
if grid[y][x] == Tile::Round {
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some(Tile::Empty) = try { grid[y].get(x + i + 1)? } {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
grid[y][x] = Tile::Empty;
|
||||||
|
grid[y][x + i] = Tile::Round;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,12 +86,33 @@ fn weight(grid: &Parsed) -> usize {
|
||||||
|
|
||||||
fn part1(parsed: &Parsed) -> usize {
|
fn part1(parsed: &Parsed) -> usize {
|
||||||
let mut grid = parsed.clone();
|
let mut grid = parsed.clone();
|
||||||
tilt(&mut grid, Direction::Up);
|
tilt_north(&mut grid);
|
||||||
weight(&grid)
|
weight(&grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(parsed: &Parsed) -> usize {
|
fn part2(parsed: &Parsed) -> usize {
|
||||||
unimplemented!()
|
let mut grid = parsed.clone();
|
||||||
|
let mut weights = FnvHashMap::default();
|
||||||
|
let mut n = 0;
|
||||||
|
let cycle = loop {
|
||||||
|
let mut hasher = FnvHasher::default();
|
||||||
|
for l in grid.iter() {
|
||||||
|
hasher.write(unsafe { transmute(l.as_slice()) });
|
||||||
|
}
|
||||||
|
let hash = hasher.finish();
|
||||||
|
if let Some((_, old_n)) = weights.insert(hash, (weight(&grid), n)) {
|
||||||
|
break n - old_n;
|
||||||
|
}
|
||||||
|
n += 1;
|
||||||
|
|
||||||
|
tilt_north(&mut grid);
|
||||||
|
tilt_west(&mut grid);
|
||||||
|
tilt_south(&mut grid);
|
||||||
|
tilt_east(&mut grid);
|
||||||
|
};
|
||||||
|
const REPETITIONS: usize = 1000000000;
|
||||||
|
let steps = (REPETITIONS - n) % cycle;
|
||||||
|
weights.into_iter().find_map(|(_, (w, n2))| (n2 == n - cycle + steps).then_some(w)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
boilerplate! {
|
boilerplate! {
|
||||||
|
@ -79,6 +132,6 @@ O.#..O.#.#
|
||||||
part2: { TEST_INPUT => 64 },
|
part2: { TEST_INPUT => 64 },
|
||||||
},
|
},
|
||||||
bench1 == 110407,
|
bench1 == 110407,
|
||||||
bench2 == 0,
|
bench2 == 87273,
|
||||||
bench_parse: Vec::len => 100,
|
bench_parse: Vec::len => 100,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user