Compare commits
No commits in common. "75c7b08449a42982fe888ae88bf773c566c8074d" and "daa8b6b1d0a06e9be961d6b5ddf4460730e7f1c8" have entirely different histories.
75c7b08449
...
daa8b6b1d0
11 changed files with 101 additions and 1533 deletions
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
|
|
@ -7,15 +7,15 @@
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug executable 'advent2022'",
|
"name": "Debug executable 'advent2019'",
|
||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"build",
|
"build",
|
||||||
"--bin=advent2022",
|
"--bin=advent2019",
|
||||||
"--package=advent2022"
|
"--package=advent2019"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "advent2022",
|
"name": "advent2019",
|
||||||
"kind": "bin"
|
"kind": "bin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -30,16 +30,16 @@
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug unit tests in executable 'advent2022'",
|
"name": "Debug unit tests in executable 'advent2019'",
|
||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"test",
|
"test",
|
||||||
"--no-run",
|
"--no-run",
|
||||||
"--bin=advent2022",
|
"--bin=advent2019",
|
||||||
"--package=advent2022"
|
"--package=advent2019"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "advent2022",
|
"name": "advent2019",
|
||||||
"kind": "bin"
|
"kind": "bin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -1,4 +1,3 @@
|
||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true
|
||||||
"debug.allowBreakpointsEverywhere": true
|
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
const_format = "0.2.31"
|
const_format = "0.2.31"
|
||||||
itertools = "0.11"
|
itertools = "0.11"
|
||||||
|
lazy_static = "1.4"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
regex = "1.7"
|
regex = "1.7"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
####
|
|
||||||
|
|
||||||
.#.
|
|
||||||
###
|
|
||||||
.#.
|
|
||||||
|
|
||||||
..#
|
|
||||||
..#
|
|
||||||
###
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
##
|
|
||||||
##
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,5 @@
|
||||||
use super::template::{DayTrait, ResultType};
|
use super::template::{DayTrait, ResultType};
|
||||||
use once_cell::sync::Lazy;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{iter::zip, num::ParseIntError};
|
use std::{iter::zip, num::ParseIntError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -72,14 +72,13 @@ struct Monkey {
|
||||||
bad_monkey: usize,
|
bad_monkey: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
static MONKEY: Lazy<Regex> = Lazy::new(|| Regex::new(r"Monkey (\d+)").unwrap());
|
lazy_static! {
|
||||||
static STARTING: Lazy<Regex> =
|
static ref MONKEY: Regex = Regex::new(r"Monkey (\d+)").unwrap();
|
||||||
Lazy::new(|| Regex::new(r"Starting items: (\d+(?:, \d+)*)").unwrap());
|
static ref STARTING: Regex = Regex::new(r"Starting items: (\d+(?:, \d+)*)").unwrap();
|
||||||
static OP: Lazy<Regex> =
|
static ref OP: Regex = Regex::new(r"Operation: new = old ([+*] \d+|\* old)").unwrap();
|
||||||
Lazy::new(|| Regex::new(r"Operation: new = old ([+*] \d+|\* old)").unwrap());
|
static ref TEST: Regex = Regex::new(r"Test: divisible by (\d+)").unwrap();
|
||||||
static TEST: Lazy<Regex> = Lazy::new(|| Regex::new(r"Test: divisible by (\d+)").unwrap());
|
static ref NEXT: Regex = Regex::new(r"If (?:true|false): throw to monkey (\d+)").unwrap();
|
||||||
static NEXT: Lazy<Regex> =
|
}
|
||||||
Lazy::new(|| Regex::new(r"If (?:true|false): throw to monkey (\d+)").unwrap());
|
|
||||||
|
|
||||||
impl Monkey {
|
impl Monkey {
|
||||||
fn parse_line<'a>(re: &Regex, line: &'a str) -> Result<&'a str, MonkeyError> {
|
fn parse_line<'a>(re: &Regex, line: &'a str) -> Result<&'a str, MonkeyError> {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::template::{DayTrait, ResultType};
|
use super::template::{DayTrait, ResultType};
|
||||||
use crate::common::pos::Pos;
|
use crate::common::pos::Pos;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{collections::HashSet, num::ParseIntError};
|
use std::{collections::HashSet, num::ParseIntError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -209,8 +209,9 @@ struct Sensor {
|
||||||
radius: i64,
|
radius: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
static SENSOR: Lazy<Regex> =
|
lazy_static! {
|
||||||
Lazy::new(|| Regex::new(r"x=(-?\d+), y=(-?\d+).*x=(-?\d+), y=(-?\d+)").unwrap());
|
static ref SENSOR: Regex = Regex::new(r"x=(-?\d+), y=(-?\d+).*x=(-?\d+), y=(-?\d+)").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
impl Sensor {
|
impl Sensor {
|
||||||
pub fn parse(line: &str) -> Result<(Sensor, Pos<i64>), SensorError> {
|
pub fn parse(line: &str) -> Result<(Sensor, Pos<i64>), SensorError> {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,424 +0,0 @@
|
||||||
use std::{cell::Cell, marker::PhantomData, ops::Index};
|
|
||||||
|
|
||||||
use crate::common::file::read_lines;
|
|
||||||
|
|
||||||
use super::template::{DayTrait, ResultType};
|
|
||||||
use itertools::Itertools;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
const DAY_NUMBER: usize = 17;
|
|
||||||
const STACK_WIDTH: usize = 7;
|
|
||||||
|
|
||||||
pub struct Day;
|
|
||||||
|
|
||||||
impl DayTrait for Day {
|
|
||||||
fn get_day_number(&self) -> usize {
|
|
||||||
DAY_NUMBER
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
|
||||||
let pushes = Dispenser::new(lines[0].chars().map(|c| Push::parse(c)).try_collect()?);
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 2022)?;
|
|
||||||
|
|
||||||
Ok(ResultType::Integer(result as i64))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
|
||||||
let pushes = Dispenser::new(lines[0].chars().map(|c| Push::parse(c)).try_collect()?);
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 1000000000000)?;
|
|
||||||
|
|
||||||
Ok(ResultType::Integer(result as i64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Day {
|
|
||||||
fn run(push_cycle: Dispenser<Push>, max_cycles: i64) -> Result<i64, RockError> {
|
|
||||||
let raw = read_lines(DAY_NUMBER, "blocks.txt")?;
|
|
||||||
let rock_cycle = Dispenser::new(Rock::parse(&raw)?);
|
|
||||||
let mut cycle = 0;
|
|
||||||
let mut stack = Stack::new();
|
|
||||||
|
|
||||||
let mut last_drop = None;
|
|
||||||
let mut prev_bottom = 0;
|
|
||||||
let mut additional_height = None;
|
|
||||||
|
|
||||||
while cycle < max_cycles {
|
|
||||||
let bottom = stack.one_rock(rock_cycle.next(), &push_cycle);
|
|
||||||
if bottom < prev_bottom {
|
|
||||||
let drop_distance = prev_bottom - bottom;
|
|
||||||
|
|
||||||
match last_drop {
|
|
||||||
None => {
|
|
||||||
last_drop = Some((bottom, drop_distance, cycle, None));
|
|
||||||
}
|
|
||||||
Some((_, last_distance, _, _)) if last_distance < drop_distance => {
|
|
||||||
last_drop = Some((bottom, drop_distance, cycle, None));
|
|
||||||
}
|
|
||||||
Some((last_bottom, last_distance, last_cycle, None))
|
|
||||||
if last_distance == drop_distance =>
|
|
||||||
{
|
|
||||||
last_drop = Some((
|
|
||||||
bottom,
|
|
||||||
drop_distance,
|
|
||||||
cycle,
|
|
||||||
Some((bottom - last_bottom, cycle - last_cycle)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Some((last_bottom, last_distance, last_cycle, Some((growth, period))))
|
|
||||||
if last_distance == drop_distance =>
|
|
||||||
{
|
|
||||||
if growth == bottom - last_bottom && period == cycle - last_cycle {
|
|
||||||
let first_bottom = last_bottom - growth;
|
|
||||||
let all_equal = (0..growth).all(|row| {
|
|
||||||
stack.0[first_bottom + row] == stack.0[last_bottom + row]
|
|
||||||
});
|
|
||||||
if all_equal {
|
|
||||||
let iterations = (max_cycles - cycle) / period;
|
|
||||||
additional_height = Some(iterations * growth as i64);
|
|
||||||
cycle += iterations * period;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last_drop = Some((
|
|
||||||
bottom,
|
|
||||||
drop_distance,
|
|
||||||
cycle,
|
|
||||||
Some((bottom - last_bottom, cycle - last_cycle)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev_bottom = bottom;
|
|
||||||
cycle += 1;
|
|
||||||
}
|
|
||||||
match additional_height {
|
|
||||||
None => Ok(stack.height() as i64),
|
|
||||||
Some(height) => Ok(stack.height() as i64 + height),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
enum RockError {
|
|
||||||
#[error("IO Error")]
|
|
||||||
RockIOError(#[from] std::io::Error),
|
|
||||||
|
|
||||||
#[error("A rock must not be zero length or hight")]
|
|
||||||
MustNotBeEmpty,
|
|
||||||
|
|
||||||
#[error("All lines in a block must be the same length")]
|
|
||||||
AllLinesSameLength,
|
|
||||||
|
|
||||||
#[error("Unknown direction: {0}")]
|
|
||||||
UnknownDirection(char),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
struct Rock {
|
|
||||||
positions: Vec<(usize, usize)>,
|
|
||||||
width: usize,
|
|
||||||
height: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rock {
|
|
||||||
pub fn new(blocks: Vec<Vec<bool>>) -> Result<Rock, RockError> {
|
|
||||||
let height = blocks.len();
|
|
||||||
if height == 0 {
|
|
||||||
return Err(RockError::MustNotBeEmpty);
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = blocks.iter().map(|line| line.len()).max().unwrap_or(0);
|
|
||||||
if width == 0 {
|
|
||||||
return Err(RockError::MustNotBeEmpty);
|
|
||||||
}
|
|
||||||
for line in blocks.iter() {
|
|
||||||
if line.len() != width {
|
|
||||||
return Err(RockError::AllLinesSameLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let positions = blocks
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(y, line)| {
|
|
||||||
line.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(move |(x, block)| block.then_some((x, height - 1 - y)))
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
Ok(Rock {
|
|
||||||
positions,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(lines: &[String]) -> Result<Vec<Rock>, RockError> {
|
|
||||||
lines
|
|
||||||
.iter()
|
|
||||||
.batching(|it| {
|
|
||||||
let blocks = it
|
|
||||||
.skip_while(|line| line.is_empty())
|
|
||||||
.take_while(|line| !line.is_empty())
|
|
||||||
.map(|line| line.chars().map(|c| c == '#').collect_vec())
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
if blocks.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(Rock::new(blocks))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.try_collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum Push {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Push {
|
|
||||||
pub fn parse(c: char) -> Result<Push, RockError> {
|
|
||||||
match c {
|
|
||||||
'<' => Ok(Push::Left),
|
|
||||||
'>' => Ok(Push::Right),
|
|
||||||
_ => Err(RockError::UnknownDirection(c)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FallingRock<'a> {
|
|
||||||
rock: &'a Rock,
|
|
||||||
bottom: usize,
|
|
||||||
left: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FallingRock<'a> {
|
|
||||||
pub fn new(rock: &'a Rock, stack_height: usize) -> FallingRock<'a> {
|
|
||||||
FallingRock {
|
|
||||||
rock,
|
|
||||||
bottom: stack_height + 3,
|
|
||||||
left: 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_push(mut self, push: &Push, stack: &Stack) -> Self {
|
|
||||||
let left = match push {
|
|
||||||
Push::Left => {
|
|
||||||
if self.left == 0 {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
self.left - 1
|
|
||||||
}
|
|
||||||
Push::Right => {
|
|
||||||
if self.left + self.rock.width >= STACK_WIDTH {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
self.left + 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if self.check_position(left, self.bottom, stack) {
|
|
||||||
self.left = left;
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_drop(mut self, stack: &Stack) -> Result<Self, Self> {
|
|
||||||
if self.bottom == 0 {
|
|
||||||
return Err(self);
|
|
||||||
}
|
|
||||||
let bottom = self.bottom - 1;
|
|
||||||
if self.check_position(self.left, bottom, stack) {
|
|
||||||
self.bottom = bottom;
|
|
||||||
Ok(self)
|
|
||||||
} else {
|
|
||||||
Err(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_position(&self, left: usize, bottom: usize, stack: &Stack) -> bool {
|
|
||||||
self.rock
|
|
||||||
.positions
|
|
||||||
.iter()
|
|
||||||
.all(|(x, y)| *y + bottom >= stack.height() || !stack[*y + bottom][*x + left])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reach(&self) -> usize {
|
|
||||||
self.bottom + self.rock.height
|
|
||||||
}
|
|
||||||
|
|
||||||
fn positions(&'a self) -> impl Iterator<Item = (usize, usize)> + 'a {
|
|
||||||
self.rock
|
|
||||||
.positions
|
|
||||||
.iter()
|
|
||||||
.map(|(x, y)| (*x + self.left, *y + self.bottom))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Stack(Vec<[bool; STACK_WIDTH]>);
|
|
||||||
|
|
||||||
impl Stack {
|
|
||||||
pub fn new() -> Stack {
|
|
||||||
Stack(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn height(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn settle_rock(&mut self, rock: FallingRock<'_>) {
|
|
||||||
for _ in self.0.len()..rock.reach() {
|
|
||||||
self.0.push([false; STACK_WIDTH]);
|
|
||||||
}
|
|
||||||
for (x, y) in rock.positions() {
|
|
||||||
self.0[y][x] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one_rock(&mut self, rock: &Rock, push_cycle: &Dispenser<Push>) -> usize {
|
|
||||||
let mut rock = FallingRock::new(rock, self.height());
|
|
||||||
loop {
|
|
||||||
let push = push_cycle.next();
|
|
||||||
rock = rock.try_push(push, &self);
|
|
||||||
match rock.try_drop(&self) {
|
|
||||||
Ok(next_rock) => rock = next_rock,
|
|
||||||
Err(rock) => {
|
|
||||||
let bottom = rock.bottom;
|
|
||||||
self.settle_rock(rock);
|
|
||||||
return bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Stack {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let text = self
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.map(|line| line.iter().map(|b| if *b { "#" } else { " " }).join(""))
|
|
||||||
.join("\n");
|
|
||||||
write!(f, "{}", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Stack {
|
|
||||||
type Output = [bool; STACK_WIDTH];
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Dispenser<'a, T>
|
|
||||||
where
|
|
||||||
T: 'a,
|
|
||||||
{
|
|
||||||
data: Vec<T>,
|
|
||||||
current: Cell<usize>,
|
|
||||||
_marker: PhantomData<&'a T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Dispenser<'a, T> {
|
|
||||||
pub fn new(data: Vec<T>) -> Self {
|
|
||||||
Dispenser {
|
|
||||||
data,
|
|
||||||
current: Cell::new(0),
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&'a self) -> &'a T {
|
|
||||||
let idx = self.current.get();
|
|
||||||
self.current.set(self.current.get() + 1);
|
|
||||||
if self.current.get() >= self.data.len() {
|
|
||||||
self.current.set(0);
|
|
||||||
}
|
|
||||||
self.data.get(idx).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::common::file::read_lines;
|
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part1() -> Result<()> {
|
|
||||||
let day = Day {};
|
|
||||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
|
||||||
let expected = ResultType::Integer(3068);
|
|
||||||
let result = day.part1(&lines)?;
|
|
||||||
assert_eq!(result, expected);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part2() -> Result<()> {
|
|
||||||
let day = Day {};
|
|
||||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
|
||||||
let expected = ResultType::Integer(1514285714288);
|
|
||||||
let result = day.part2(&lines)?;
|
|
||||||
assert_eq!(result, expected);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn read_blocks() -> Result<()> {
|
|
||||||
let day = Day {};
|
|
||||||
let raw = read_lines(day.get_day_number(), "blocks.txt")?;
|
|
||||||
let rocks = Rock::parse(&raw)?;
|
|
||||||
let expected = Rock::new(vec![vec![true]; 4])?;
|
|
||||||
assert_eq!(rocks[3], expected);
|
|
||||||
|
|
||||||
let angle_rock = &rocks[2];
|
|
||||||
assert_eq!(
|
|
||||||
angle_rock.positions,
|
|
||||||
vec![(2, 2), (2, 1), (0, 0), (1, 0), (2, 0)]
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn drop_one() -> Result<()> {
|
|
||||||
let day = Day {};
|
|
||||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
|
||||||
let pushes = Dispenser::new(lines[0].chars().map(|c| Push::parse(c)).try_collect()?);
|
|
||||||
let raw = read_lines(day.get_day_number(), "blocks.txt")?;
|
|
||||||
let rocks = Dispenser::new(Rock::parse(&raw)?);
|
|
||||||
|
|
||||||
let mut stack = Stack::new();
|
|
||||||
stack.one_rock(rocks.next(), &pushes);
|
|
||||||
|
|
||||||
assert_eq!(stack.0, vec![[false, false, true, true, true, true, false]]);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn drop_some() -> Result<()> {
|
|
||||||
let day = Day {};
|
|
||||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
|
||||||
let pushes = Dispenser::new(lines[0].chars().map(|c| Push::parse(c)).try_collect()?);
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 10)?;
|
|
||||||
|
|
||||||
assert_eq!(result, 17);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,7 +14,6 @@ mod day13;
|
||||||
mod day14;
|
mod day14;
|
||||||
mod day15;
|
mod day15;
|
||||||
mod day16;
|
mod day16;
|
||||||
mod day17;
|
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
pub use template::DayTrait;
|
pub use template::DayTrait;
|
||||||
|
|
@ -24,7 +23,7 @@ pub mod day_provider {
|
||||||
use super::*;
|
use super::*;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
const MAX_DAY: usize = 17;
|
const MAX_DAY: usize = 16;
|
||||||
|
|
||||||
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
|
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
|
||||||
match day_num {
|
match day_num {
|
||||||
|
|
@ -44,7 +43,6 @@ pub mod day_provider {
|
||||||
14 => Ok(Box::new(day14::Day)),
|
14 => Ok(Box::new(day14::Day)),
|
||||||
15 => Ok(Box::new(day15::Day)),
|
15 => Ok(Box::new(day15::Day)),
|
||||||
16 => Ok(Box::new(day16::Day)),
|
16 => Ok(Box::new(day16::Day)),
|
||||||
17 => Ok(Box::new(day17::Day)),
|
|
||||||
_ => Err(ProviderError::InvalidNumber(day_num)),
|
_ => Err(ProviderError::InvalidNumber(day_num)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue