Added day 17
This commit is contained in:
parent
eeba8bc91d
commit
b1c1c3f41e
181
src/day17/1.rs
181
src/day17/1.rs
|
@ -0,0 +1,181 @@
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
|
||||||
|
enum Moves {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &'static str) -> Vec<Moves> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.flat_map(|line| {
|
||||||
|
line.bytes().map(|c| match c {
|
||||||
|
b'>' => Moves::Right,
|
||||||
|
b'<' => Moves::Left,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum Rock {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Plus,
|
||||||
|
L,
|
||||||
|
Box,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rock {
|
||||||
|
pub fn points(rock: &Rock, height: i32) -> Vec<(i32, i32)> {
|
||||||
|
match rock {
|
||||||
|
Rock::Horizontal => vec![(height, 2), (height, 3), (height, 4), (height, 5)],
|
||||||
|
Rock::Vertical => vec![
|
||||||
|
(height, 2),
|
||||||
|
(height + 1, 2),
|
||||||
|
(height + 2, 2),
|
||||||
|
(height + 3, 2),
|
||||||
|
],
|
||||||
|
Rock::Plus => vec![
|
||||||
|
(height, 3),
|
||||||
|
(height + 1, 2),
|
||||||
|
(height + 1, 3),
|
||||||
|
(height + 1, 4),
|
||||||
|
(height + 2, 3),
|
||||||
|
],
|
||||||
|
Rock::L => vec![
|
||||||
|
(height, 2),
|
||||||
|
(height, 3),
|
||||||
|
(height, 4),
|
||||||
|
(height + 1, 4),
|
||||||
|
(height + 2, 4),
|
||||||
|
],
|
||||||
|
Rock::Box => vec![(height, 2), (height, 3), (height + 1, 2), (height + 1, 3)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_left(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a, *c - 1)) || *c == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, c) in points.iter_mut() {
|
||||||
|
*c -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_right(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a, *c + 1)) || *c == 6)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, c) in points.iter_mut() {
|
||||||
|
*c += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) -> bool {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a - 1, *c)) || *a == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (a, _) in points.iter_mut() {
|
||||||
|
*a -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ROCKS: [Rock; 5] = [
|
||||||
|
Rock::Horizontal,
|
||||||
|
Rock::Plus,
|
||||||
|
Rock::L,
|
||||||
|
Rock::Vertical,
|
||||||
|
Rock::Box,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Grid {
|
||||||
|
highest_point: i32,
|
||||||
|
frozen_points: HashSet<(i32, i32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
highest_point: 0,
|
||||||
|
frozen_points: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_points(&mut self, points: Vec<(i32, i32)>) {
|
||||||
|
let highest = *points.iter().map(|(a, _)| a).max().unwrap();
|
||||||
|
|
||||||
|
self.highest_point = std::cmp::max(self.highest_point, highest + 1);
|
||||||
|
|
||||||
|
self.frozen_points.extend(points.into_iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(input: Vec<Moves>) -> i32 {
|
||||||
|
let mut grid = Grid::new();
|
||||||
|
|
||||||
|
let mut input = input.iter().cycle().peekable();
|
||||||
|
|
||||||
|
for rock in ROCKS.iter().cycle().take(2022) {
|
||||||
|
let mut height = grid.highest_point + 3;
|
||||||
|
|
||||||
|
let mut rockp = Rock::points(rock, height);
|
||||||
|
|
||||||
|
for wind in input.by_ref() {
|
||||||
|
match wind {
|
||||||
|
Moves::Left => Rock::move_left(&mut rockp, &grid.frozen_points),
|
||||||
|
Moves::Right => Rock::move_right(&mut rockp, &grid.frozen_points),
|
||||||
|
}
|
||||||
|
|
||||||
|
if Rock::move_down(&mut rockp, &grid.frozen_points) {
|
||||||
|
height -= 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.add_points(rockp);
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.highest_point
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for input in INPUTS.iter() {
|
||||||
|
let output = parse(input);
|
||||||
|
let score = solution(output);
|
||||||
|
println!("{}", score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
fn solution_bench(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
let input = parse(INPUTS[1]);
|
||||||
|
let result = solution(input);
|
||||||
|
test::black_box(result);
|
||||||
|
})
|
||||||
|
}
|
227
src/day17/2.rs
227
src/day17/2.rs
|
@ -0,0 +1,227 @@
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
|
||||||
|
enum Moves {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &'static str) -> Vec<Moves> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.flat_map(|line| {
|
||||||
|
line.bytes().map(|c| match c {
|
||||||
|
b'>' => Moves::Right,
|
||||||
|
b'<' => Moves::Left,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum Rock {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Plus,
|
||||||
|
L,
|
||||||
|
Box,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rock {
|
||||||
|
pub fn points(rock: &Rock, height: i32) -> Vec<(i32, i32)> {
|
||||||
|
match rock {
|
||||||
|
Rock::Horizontal => vec![(height, 2), (height, 3), (height, 4), (height, 5)],
|
||||||
|
Rock::Vertical => vec![
|
||||||
|
(height, 2),
|
||||||
|
(height + 1, 2),
|
||||||
|
(height + 2, 2),
|
||||||
|
(height + 3, 2),
|
||||||
|
],
|
||||||
|
Rock::Plus => vec![
|
||||||
|
(height, 3),
|
||||||
|
(height + 1, 2),
|
||||||
|
(height + 1, 3),
|
||||||
|
(height + 1, 4),
|
||||||
|
(height + 2, 3),
|
||||||
|
],
|
||||||
|
Rock::L => vec![
|
||||||
|
(height, 2),
|
||||||
|
(height, 3),
|
||||||
|
(height, 4),
|
||||||
|
(height + 1, 4),
|
||||||
|
(height + 2, 4),
|
||||||
|
],
|
||||||
|
Rock::Box => vec![(height, 2), (height, 3), (height + 1, 2), (height + 1, 3)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_left(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a, *c - 1)) || *c == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, c) in points.iter_mut() {
|
||||||
|
*c -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_right(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a, *c + 1)) || *c == 6)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, c) in points.iter_mut() {
|
||||||
|
*c += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down(points: &mut [(i32, i32)], frozen_points: &HashSet<(i32, i32)>) -> bool {
|
||||||
|
if points
|
||||||
|
.iter()
|
||||||
|
.any(|(a, c)| frozen_points.contains(&(*a - 1, *c)) || *a == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (a, _) in points.iter_mut() {
|
||||||
|
*a -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ROCKS: [Rock; 5] = [
|
||||||
|
Rock::Horizontal,
|
||||||
|
Rock::Plus,
|
||||||
|
Rock::L,
|
||||||
|
Rock::Vertical,
|
||||||
|
Rock::Box,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Grid {
|
||||||
|
highest_point: i32,
|
||||||
|
frozen_points: HashSet<(i32, i32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
highest_point: 0,
|
||||||
|
frozen_points: HashSet::with_capacity_and_hasher(5000000, Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_points(&mut self, points: Vec<(i32, i32)>) {
|
||||||
|
let highest = *points.iter().map(|(a, _)| a).max().unwrap();
|
||||||
|
|
||||||
|
self.highest_point = std::cmp::max(self.highest_point, highest + 1);
|
||||||
|
|
||||||
|
self.frozen_points.extend(points.into_iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(input: Vec<Moves>) -> usize {
|
||||||
|
let mut grid = Grid::new();
|
||||||
|
|
||||||
|
let mut deltas = vec![0; 5000];
|
||||||
|
|
||||||
|
let mut input = input.iter().cycle();
|
||||||
|
|
||||||
|
for (k, rock) in ROCKS.iter().cycle().take(5000).enumerate() {
|
||||||
|
let mut height = grid.highest_point + 3;
|
||||||
|
|
||||||
|
let mut rockp = Rock::points(rock, height);
|
||||||
|
|
||||||
|
for wind in input.by_ref() {
|
||||||
|
match wind {
|
||||||
|
Moves::Left => Rock::move_left(&mut rockp, &grid.frozen_points),
|
||||||
|
Moves::Right => Rock::move_right(&mut rockp, &grid.frozen_points),
|
||||||
|
}
|
||||||
|
|
||||||
|
if Rock::move_down(&mut rockp, &grid.frozen_points) {
|
||||||
|
height -= 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_height = grid.highest_point;
|
||||||
|
grid.add_points(rockp);
|
||||||
|
|
||||||
|
deltas[k] = grid.highest_point - old_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pattern_length = 1000;
|
||||||
|
let mut found_plen = 0;
|
||||||
|
let d = &deltas[pattern_length..];
|
||||||
|
for plen in 1..=d.len() / 2 {
|
||||||
|
let pattern = &d[0..plen];
|
||||||
|
let mut found = true;
|
||||||
|
|
||||||
|
for i in 0..d.len() - plen {
|
||||||
|
if d[i + plen] != pattern[i % plen] {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
found_plen = plen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pattern = &d[0..found_plen];
|
||||||
|
let pattern_sum = pattern.iter().sum::<i32>();
|
||||||
|
|
||||||
|
let iter_count = 1000000000000usize;
|
||||||
|
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
for i in 0..deltas.len() {
|
||||||
|
if &deltas[i..i + found_plen] == pattern {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ideltas = &deltas[0..idx];
|
||||||
|
let ideltassum = ideltas.iter().sum::<i32>();
|
||||||
|
|
||||||
|
let num_patterns = (iter_count - ideltas.len()) / pattern.len();
|
||||||
|
let num_leftover = (iter_count - ideltas.len()) % pattern.len();
|
||||||
|
|
||||||
|
let leftoversum = pattern[0..num_leftover].iter().sum::<i32>();
|
||||||
|
|
||||||
|
ideltassum as usize + pattern_sum as usize * num_patterns + leftoversum as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for input in INPUTS.iter() {
|
||||||
|
let output = parse(input);
|
||||||
|
let score = solution(output);
|
||||||
|
println!("{}", score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
fn solution_bench(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
let input = parse(INPUTS[1]);
|
||||||
|
let result = solution(input);
|
||||||
|
test::black_box(result);
|
||||||
|
})
|
||||||
|
}
|
1
src/day17/input.txt
Normal file
1
src/day17/input.txt
Normal file
File diff suppressed because one or more lines are too long
1
src/day17/sample.txt
Normal file
1
src/day17/sample.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
Loading…
Reference in New Issue
Block a user