Compare commits

..

2 commits

Author SHA1 Message Date
4a4117882a day 20 finished 2023-08-05 14:26:29 +02:00
1972b7285a removed usused code 2023-08-05 14:26:21 +02:00
8 changed files with 15358 additions and 10 deletions

7
data/day20/example01.txt Normal file
View file

@ -0,0 +1,7 @@
1
2
-3
3
-2
0
4

5000
data/day20/input.txt Normal file

File diff suppressed because it is too large Load diff

5005
rest.txt Normal file

File diff suppressed because it is too large Load diff

5001
result.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -78,15 +78,6 @@ enum Material {
} }
impl Material { impl Material {
pub fn prev(&self) -> Option<Material> {
match self {
Material::Geode => None,
Material::Obsidian => Some(Material::Geode),
Material::Clay => Some(Material::Obsidian),
Material::Ore => Some(Material::Clay),
}
}
pub fn next(&self) -> Option<Material> { pub fn next(&self) -> Option<Material> {
match self { match self {
Material::Geode => Some(Material::Obsidian), Material::Geode => Some(Material::Obsidian),

340
src/days/day20/mod.rs Normal file
View file

@ -0,0 +1,340 @@
use super::template::{DayTrait, ResultType};
use crate::common::file::split_lines;
use itertools::Itertools;
use std::{num::ParseIntError, str::FromStr};
use thiserror::Error;
const DAY_NUMBER: usize = 20;
pub struct Day;
impl DayTrait for Day {
fn get_day_number(&self) -> usize {
DAY_NUMBER
}
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let mut ring: Ring = lines.parse()?;
ring.mix(1);
let start = ring.index_of(0)?;
Ok(ResultType::Integer(
ring.get_item(start, 1000) + ring.get_item(start, 2000) + ring.get_item(start, 3000),
))
}
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
let mut ring: Ring = lines.parse()?;
ring.multiply(811589153);
ring.mix(10);
let start = ring.index_of(0)?;
Ok(ResultType::Integer(
ring.get_item(start, 1000) + ring.get_item(start, 2000) + ring.get_item(start, 3000),
))
}
}
#[derive(Debug, Error)]
enum RingError {
#[error("Parse Error")]
ParseError(#[from] ParseIntError),
#[error("Item not found {0}")]
ItemNotFound(i64),
}
struct Ring {
items: Vec<i64>,
next: Vec<usize>,
prev: Vec<usize>,
}
impl FromStr for Ring {
type Err = RingError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let items: Vec<_> = split_lines(s).map(|line| line.parse()).try_collect()?;
Ok(Ring::new(items))
}
}
impl Ring {
pub fn new(items: Vec<i64>) -> Self {
let mut next = Vec::with_capacity(items.len());
for i in 1..items.len() {
next.push(i);
}
next.push(0);
let mut prev = Vec::with_capacity(items.len());
prev.push(items.len() - 1);
for i in 0..items.len() - 1 {
prev.push(i);
}
Self { items, next, prev }
}
pub fn get_item(&self, start: usize, steps: usize) -> i64 {
let steps = steps % self.items.len();
let mut next = start;
for _ in 0..steps {
next = self.next[next];
}
self.items[next]
}
pub fn index_of(&self, value: i64) -> Result<usize, RingError> {
self.items
.iter()
.position(|v| *v == value)
.ok_or_else(|| RingError::ItemNotFound(value))
}
fn next_pos(&self, pos: usize) -> usize {
let len = self.items.len() as i64;
let mut moves = self.items[pos] % (len - 1);
if moves > len / 2 {
moves -= len - 1;
} else if moves < -len / 2 {
moves += len - 1;
}
match moves.cmp(&0) {
std::cmp::Ordering::Equal => pos,
std::cmp::Ordering::Less => {
let mut prev = self.prev[pos];
for _ in moves..-1 {
prev = self.prev[prev];
}
prev
}
std::cmp::Ordering::Greater => {
let mut next = self.next[pos];
for _ in 0..moves {
next = self.next[next];
}
next
}
}
}
pub fn move_item(&mut self, pos: usize) {
let next_pos = self.next_pos(pos);
if next_pos == pos {
return;
}
let old_next = self.next[pos];
self.next[self.prev[pos]] = self.next[pos];
self.next[pos] = self.next[self.prev[next_pos]];
self.next[self.prev[next_pos]] = pos;
self.prev[old_next] = self.prev[pos];
self.prev[pos] = self.prev[next_pos];
self.prev[next_pos] = pos;
}
#[allow(dead_code)]
pub fn iter(&self) -> RingIter<'_> {
let start = self.index_of(0).unwrap_or(0);
RingIter::new(self, start)
}
fn mix(&mut self, times: usize) {
for _ in 0..times {
for pos in 0..self.items.len() {
self.move_item(pos);
}
}
}
fn multiply(&mut self, arg: i64) {
self.items
.iter_mut()
.for_each(|value| *value = *value * arg);
}
}
struct RingIter<'a> {
ring: &'a Ring,
pos: Option<usize>,
start: usize,
}
impl<'a> RingIter<'a> {
pub fn new(ring: &'a Ring, start: usize) -> Self {
Self {
ring,
pos: Some(start),
start,
}
}
}
impl Iterator for RingIter<'_> {
type Item = i64;
fn next(&mut self) -> Option<Self::Item> {
let Some(pos) = self.pos else {
return None;
};
let next_pos = self.ring.next[pos];
self.pos = if next_pos != self.start {
Some(next_pos)
} else {
None
};
Some(self.ring.items[pos])
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::common::file::read_string;
use anyhow::Result;
#[test]
fn test_part1() -> Result<()> {
let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?;
let expected = ResultType::Integer(3);
let result = day.part1(&lines)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_part2() -> Result<()> {
let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?;
let expected = ResultType::Integer(1623178306);
let result = day.part2(&lines)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn move1() {
let input = vec![1, 2, 3, 4, 5, 6, 7];
let mut ring = Ring::new(input);
let expected = vec![1, 3, 4, 5, 6, 7, 2];
ring.move_item(0);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move7() {
let input = vec![7, 2, 3, 4, 5, 6, 7];
let mut ring = Ring::new(input);
let expected = vec![7, 3, 4, 5, 6, 7, 2];
ring.move_item(0);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move2() {
let input = vec![1, 2, 3, 4, 5, 6, 7];
let mut ring = Ring::new(input);
let expected = vec![1, 3, 4, 2, 5, 6, 7];
ring.move_item(1);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move_6() {
let input = vec![6, -2, 5, 6, 7, 8, 9];
let mut ring = Ring::new(input);
let expected = vec![6, -2, 5, 6, 7, 8, 9];
ring.move_item(0);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move_minus1() {
let input = vec![4, -1, 5, 6, 7, 8, 9];
let mut ring = Ring::new(input);
let expected = vec![4, 5, 6, 7, 8, 9, -1];
ring.move_item(1);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move_minus2() {
let input = vec![4, -2, 5, 6, 7, 8, 9];
let mut ring = Ring::new(input);
let expected = vec![4, 5, 6, 7, 8, -2, 9];
ring.move_item(1);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn move_minus4() {
let input = vec![4, -4, 5, 6, 7, 8, 9];
let mut ring = Ring::new(input);
let expected = vec![4, 5, 6, -4, 7, 8, 9];
ring.move_item(1);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn mix() {
let input = vec![1, 2, -3, 3, -2, 0, 4];
let mut ring = Ring::new(input);
let expected = vec![0, 3, -2, 1, 2, -3, 4];
ring.mix(1);
assert_eq!(ring.iter().collect_vec(), expected);
}
#[test]
fn get_item() {
let input = vec![1, 2, 3, 4, 5, 6, 7];
let ring = Ring::new(input);
assert_eq!(ring.get_item(0, 0), 1);
assert_eq!(ring.get_item(0, 6), 7);
assert_eq!(ring.get_item(0, 7), 1);
}
#[test]
fn for_part1() -> Result<()> {
let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?;
let mut ring: Ring = lines.parse()?;
ring.mix(1);
let expected = vec![0, 3, -2, 1, 2, -3, 4];
assert_eq!(ring.iter().collect_vec(), expected);
let start = ring.index_of(0)?;
assert_eq!(ring.get_item(start, 0), 0);
assert_eq!(ring.get_item(start, 1000), 4);
assert_eq!(ring.get_item(start, 2000), -3);
assert_eq!(ring.get_item(start, 3000), 2);
Ok(())
}
#[test]
fn for_part2() -> Result<()> {
let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?;
let mut ring: Ring = lines.parse()?;
ring.multiply(811589153);
ring.mix(10);
let expected = vec![
0,
-2434767459,
1623178306,
3246356612,
-1623178306,
2434767459,
811589153,
];
assert_eq!(ring.iter().collect_vec(), expected);
let start = ring.index_of(0)?;
assert_eq!(ring.get_item(start, 0), 0);
assert_eq!(ring.get_item(start, 1000), 811589153);
assert_eq!(ring.get_item(start, 2000), 2434767459);
assert_eq!(ring.get_item(start, 3000), -1623178306);
Ok(())
}
}

View file

@ -17,6 +17,7 @@ mod day16;
mod day17; mod day17;
mod day18; mod day18;
mod day19; mod day19;
mod day20;
mod template; mod template;
pub use template::DayTrait; pub use template::DayTrait;
@ -26,7 +27,7 @@ pub mod day_provider {
use super::*; use super::*;
use thiserror::Error; use thiserror::Error;
const MAX_DAY: usize = 19; const MAX_DAY: usize = 20;
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 {
@ -49,6 +50,7 @@ pub mod day_provider {
17 => Ok(Box::new(day17::Day)), 17 => Ok(Box::new(day17::Day)),
18 => Ok(Box::new(day18::Day)), 18 => Ok(Box::new(day18::Day)),
19 => Ok(Box::new(day19::Day)), 19 => Ok(Box::new(day19::Day)),
20 => Ok(Box::new(day20::Day)),
_ => Err(ProviderError::InvalidNumber(day_num)), _ => Err(ProviderError::InvalidNumber(day_num)),
} }
} }

View file

@ -1,3 +1,5 @@
#![feature(get_many_mut)]
mod common; mod common;
mod days; mod days;
mod macros; mod macros;