Day 14
This commit is contained in:
parent
a91b120155
commit
290789d5f5
5 changed files with 571 additions and 27 deletions
169
src/day14.rs
Normal file
169
src/day14.rs
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
use itertools::Itertools;
|
||||
use pest::{
|
||||
iterators::{Pair, Pairs},
|
||||
Parser,
|
||||
};
|
||||
use raylib::prelude::*;
|
||||
use rayon::prelude::*;
|
||||
|
||||
const WIDTH: i64 = 101;
|
||||
const HEIGHT: i64 = 103;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum PlayState {
|
||||
Paused,
|
||||
Forward(i64),
|
||||
Backward(i64),
|
||||
}
|
||||
|
||||
pub fn day14() {
|
||||
let mut robots = parse_robots(&crate::input(14));
|
||||
|
||||
let (mut rl, thread) = raylib::init()
|
||||
.size(1920, 1080)
|
||||
.title("Advent of Code: Day 14")
|
||||
.build();
|
||||
|
||||
let mut total_elapsed: u32 = 6440;
|
||||
let mut play_state = PlayState::Forward(1);
|
||||
let mut safety_score: usize = 0;
|
||||
|
||||
rl.set_target_fps(1);
|
||||
while !rl.window_should_close() {
|
||||
let pressed_key = rl.get_key_pressed();
|
||||
match pressed_key {
|
||||
Some(KeyboardKey::KEY_ENTER) => {
|
||||
let mut quadrants: Vec<Vec<Robot>> = vec![vec![]; 4];
|
||||
for robot in robots.iter() {
|
||||
if let Some(quadrant) = robot.quadrant() {
|
||||
quadrants[quadrant].push(*robot);
|
||||
}
|
||||
}
|
||||
let safety_score = quadrants
|
||||
.iter()
|
||||
.map(Vec::len)
|
||||
.reduce(|acc, e| acc * e)
|
||||
.unwrap();
|
||||
println!("Safety Score: {}", safety_score);
|
||||
}
|
||||
Some(KeyboardKey::KEY_D) => {
|
||||
play_state = match play_state {
|
||||
PlayState::Forward(speed) => PlayState::Forward((speed * 2).min(16)),
|
||||
PlayState::Backward(speed) if speed == 1 => PlayState::Forward(1),
|
||||
PlayState::Backward(speed) => PlayState::Backward(speed / 2),
|
||||
_ => PlayState::Forward(1),
|
||||
};
|
||||
}
|
||||
Some(KeyboardKey::KEY_A) => {
|
||||
play_state = match play_state {
|
||||
PlayState::Backward(speed) => PlayState::Backward((speed * 2).min(16)),
|
||||
PlayState::Forward(speed) if speed == 1 => PlayState::Backward(1),
|
||||
PlayState::Forward(speed) => PlayState::Forward(speed / 2),
|
||||
_ => PlayState::Backward(1),
|
||||
};
|
||||
}
|
||||
Some(KeyboardKey::KEY_SPACE) => {
|
||||
play_state = match play_state {
|
||||
PlayState::Paused => PlayState::Forward(1),
|
||||
_ => PlayState::Paused,
|
||||
};
|
||||
let mut quadrants: Vec<usize> = vec![0; 4];
|
||||
for robot in robots.iter() {
|
||||
if let Some(q) = robot.quadrant() {
|
||||
quadrants[q] += 1;
|
||||
}
|
||||
}
|
||||
safety_score = quadrants.into_iter().reduce(|acc, e| acc * e).unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match play_state {
|
||||
PlayState::Paused => {}
|
||||
PlayState::Forward(speed) => {
|
||||
rl.set_target_fps(speed as u32);
|
||||
robots.par_iter_mut().for_each(|r| r.tick(1));
|
||||
total_elapsed += 1;
|
||||
}
|
||||
PlayState::Backward(speed) => {
|
||||
rl.set_target_fps(speed as u32);
|
||||
robots.par_iter_mut().for_each(|r| r.tick(-1));
|
||||
total_elapsed -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut d = rl.begin_drawing(&thread);
|
||||
d.clear_background(Color::BLACK);
|
||||
for robot in robots.iter() {
|
||||
let x = (robot.p.0 as f32 / WIDTH as f32) * 1920.;
|
||||
let y = (robot.p.1 as f32 / HEIGHT as f32) * 1080.;
|
||||
d.draw_circle(x as i32, y as i32, 10., Color::GREEN);
|
||||
}
|
||||
d.draw_text(
|
||||
format!("Elapsed: {}", total_elapsed).as_str(),
|
||||
0,
|
||||
0,
|
||||
20,
|
||||
Color::MAGENTA,
|
||||
);
|
||||
if play_state == PlayState::Paused {
|
||||
d.draw_text(
|
||||
format!("Safety Score: {}", safety_score).as_str(),
|
||||
0,
|
||||
40,
|
||||
20,
|
||||
Color::MAGENTA,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Robot {
|
||||
p: (i64, i64),
|
||||
v: (i64, i64),
|
||||
}
|
||||
|
||||
impl Robot {
|
||||
fn tick(&mut self, delta: i64) {
|
||||
self.p.0 = (self.p.0 + self.v.0 * delta).rem_euclid(WIDTH);
|
||||
self.p.1 = (self.p.1 + self.v.1 * delta).rem_euclid(HEIGHT);
|
||||
}
|
||||
|
||||
fn quadrant(&self) -> Option<usize> {
|
||||
if self.p.0 == WIDTH / 2 || self.p.1 == HEIGHT / 2 {
|
||||
return None;
|
||||
}
|
||||
Some(((self.p.1 > HEIGHT / 2) as usize) * 2 + (self.p.0 > WIDTH / 2) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(pest_derive::Parser)]
|
||||
#[grammar = "grammars/day14.pest"]
|
||||
struct RobotsParser {}
|
||||
|
||||
fn parse_robots(input: &str) -> Vec<Robot> {
|
||||
RobotsParser::parse(Rule::robots, input)
|
||||
.unwrap()
|
||||
.nth(0)
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.map(Pair::<'_, Rule>::into_inner)
|
||||
.map(Robot::parse)
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl Robot {
|
||||
fn parse(input: Pairs<'_, Rule>) -> Self {
|
||||
let (p, v) = input
|
||||
.map(Pair::<'_, Rule>::into_inner)
|
||||
.map(|a| {
|
||||
a.map(|ns| ns.as_str().parse::<i64>().unwrap())
|
||||
.collect_tuple()
|
||||
.unwrap()
|
||||
})
|
||||
.collect_tuple()
|
||||
.unwrap();
|
||||
Self { p, v }
|
||||
}
|
||||
}
|
||||
9
src/grammars/day14.pest
Normal file
9
src/grammars/day14.pest
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
_WHITESPACE = _{ " " }
|
||||
NEWLINE = _{ "\n" }
|
||||
|
||||
int = { "-"? ~ ASCII_DIGIT+ }
|
||||
coord_statement = { ("p" | "v") ~ "=" ~ int ~ "," ~ int }
|
||||
robot = { coord_statement ~ _WHITESPACE* ~ coord_statement ~ NEWLINE? }
|
||||
|
||||
eoi = _{ !ANY }
|
||||
robots = { SOI ~ robot+ ~ eoi }
|
||||
|
|
@ -24,10 +24,12 @@ mod day10;
|
|||
mod day11;
|
||||
#[allow(dead_code)]
|
||||
mod day12;
|
||||
#[allow(dead_code)]
|
||||
mod day13;
|
||||
mod day14;
|
||||
|
||||
fn main() {
|
||||
day13::day13();
|
||||
day14::day14();
|
||||
}
|
||||
|
||||
pub fn input(day: u8) -> String {
|
||||
|
|
|
|||
Reference in a new issue