Cleanup for 2022 days 11 through 21: Turned into a lib and introduced parse errors
This commit is contained in:
parent
c7852c9791
commit
fcb2fed515
26 changed files with 1095 additions and 879 deletions
|
@ -1,4 +1,17 @@
|
|||
use std::{fs, usize};
|
||||
use core::fmt::Display;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ParseError {
|
||||
InvalidDirection(char),
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidDirection(c) => write!(f, "Trying to parse invalid character {c} into Direction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Shape {
|
||||
|
@ -9,15 +22,15 @@ enum Shape {
|
|||
Square,
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
fn from(number: usize) -> Self {
|
||||
match number%5 {
|
||||
impl <T: Into<usize>> From <T> for Shape {
|
||||
fn from(number: T) -> Self {
|
||||
match number.into() % 5 {
|
||||
0 => Shape::Minus,
|
||||
1 => Shape::Plus,
|
||||
2 => Shape::L,
|
||||
3 => Shape::Pipe,
|
||||
4 => Shape::Square,
|
||||
_ => panic!("WTF? This can never happen."),
|
||||
_ => unreachable!("number%5 can only ever be one of the values above"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +38,18 @@ impl Shape {
|
|||
#[derive(PartialEq, Debug)]
|
||||
enum Direction { Left, Right, Down }
|
||||
|
||||
impl TryFrom<char> for Direction {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
'<' => Ok(Direction::Left),
|
||||
'>' => Ok(Direction::Right),
|
||||
c => Err(Self::Error::InvalidDirection(c)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum State { Falling, Resting }
|
||||
|
||||
|
@ -292,7 +317,7 @@ impl Block {
|
|||
self.bl_position.x = match direction {
|
||||
Direction::Left => self.bl_position.x - 1,
|
||||
Direction::Right => self.bl_position.x + 1,
|
||||
_ => panic!("unexpected direction"),
|
||||
Direction::Down => panic!("Didn't expect to be pushed down"),
|
||||
};
|
||||
for position in &old_positions {
|
||||
arena.free(position);
|
||||
|
@ -317,14 +342,10 @@ impl PlayArea {
|
|||
|
||||
fn occupy(&mut self, coordinates: &Position) {
|
||||
self.blocked_tiles[coordinates.y][coordinates.x as usize] = true;
|
||||
//self.max_y = self.max_y.max(coordinates.y as isize);
|
||||
}
|
||||
|
||||
fn free(&mut self, coordinates: &Position) {
|
||||
self.blocked_tiles[coordinates.y][coordinates.x as usize] = false;
|
||||
// if coordinates.y as isize == self.max_y && !self.blocked_tiles[coordinates.y].iter().any(|&b| b) {
|
||||
// self.max_y -= 1; // self.max_y.saturating_sub(1);
|
||||
// }
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
|
@ -336,20 +357,6 @@ impl PlayArea {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_directions(winds: &str) -> Vec<Direction> {
|
||||
winds.chars()
|
||||
.filter(|c| ['<', '>'].contains(c))
|
||||
.map(|c| match c {
|
||||
'<' => Direction::Left,
|
||||
'>' => Direction::Right,
|
||||
_ => panic!("unexpected wind direction: {}", c),
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn read_file(path: &str) -> String {
|
||||
fs::read_to_string(path)
|
||||
.expect("File not Found")
|
||||
}
|
||||
|
||||
fn solve_with_pattern(target: usize, directions: &[Direction]) -> usize {
|
||||
let mut results: Vec<(usize, usize, usize)> = Vec::new();
|
||||
|
@ -369,9 +376,9 @@ fn solve_with_pattern(target: usize, directions: &[Direction]) -> usize {
|
|||
let state = (i, direction_index, arena.max_y as usize);
|
||||
let old_results: Vec<(usize, usize, usize)> = results.iter().filter(|(old_i, old_direction, _)| old_i % 5 == i % 5 && *old_direction == direction_index).cloned().collect();
|
||||
if old_results.len() > 1 {
|
||||
let period = (i - old_results[1].0) as usize;
|
||||
let period = i - old_results[1].0;
|
||||
let period_growth = arena.max_y as usize - old_results[1].2;
|
||||
let offset = results[target % period].2 as usize;
|
||||
let offset = results[target % period].2;
|
||||
return (target/period) * period_growth + offset;
|
||||
} else {
|
||||
results.push(state);
|
||||
|
@ -383,30 +390,31 @@ fn solve_with_pattern(target: usize, directions: &[Direction]) -> usize {
|
|||
0
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let winds = read_file("input");
|
||||
|
||||
let directions = parse_directions(&winds);
|
||||
|
||||
[2022, 1_000_000_000_000].iter().for_each(|target| {
|
||||
println!("After {} rocks have fallen, the tower is {} units high.", target, solve_with_pattern(*target, &directions));
|
||||
});
|
||||
pub fn run(input: &str) -> Result<(usize, usize), ParseError> {
|
||||
let directions = input.chars().map(Direction::try_from).collect::<Result<Vec<_>, _>>()?;
|
||||
let first = solve_with_pattern(2022, &directions);
|
||||
let second = solve_with_pattern(1_000_000_000_000, &directions);
|
||||
Ok((first, second))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample_input() {
|
||||
let winds = read_file("tests/sample_input");
|
||||
let directions = parse_directions(&winds);
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
assert_eq!(solve_with_pattern(2022, &directions), 3069);
|
||||
assert_eq!(solve_with_pattern(1_000_000_000_000, &directions), 1514285714288);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn challenge_input() {
|
||||
let winds = read_file("tests/input");
|
||||
let directions = parse_directions(&winds);
|
||||
|
||||
assert_eq!(solve_with_pattern(2022, &directions), 3219);
|
||||
assert_eq!(solve_with_pattern(1_000_000_000_000, &directions), 1582758620701);
|
||||
fn read_file(name: &str) -> String {
|
||||
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let sample_input = read_file("tests/sample_input");
|
||||
assert_eq!(run(&sample_input), Ok((3069, 1514285714288)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_challenge() {
|
||||
let challenge_input = read_file("tests/challenge_input");
|
||||
assert_eq!(run(&challenge_input), Ok((3219, 1582758620701)));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue