Work on day20

This commit is contained in:
Malte Tammena 2022-12-22 12:30:48 +01:00
parent 7353989dd2
commit db7cfc6b49
5 changed files with 5203 additions and 2 deletions

3
Cargo.lock generated
View file

@ -357,6 +357,9 @@ version = "0.1.0"
[[package]]
name = "day20"
version = "0.1.0"
dependencies = [
"bitvec",
]
[[package]]
name = "day21"

View file

@ -8,3 +8,4 @@ build = true
app = true
[dependencies]
bitvec = "1.0.1"

5000
day20/input Normal file

File diff suppressed because it is too large Load diff

7
day20/input.test Normal file
View file

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

View file

@ -1,3 +1,193 @@
fn main() {
println!("Hello, world!");
use std::{
fs::File,
io::{BufRead, BufReader},
ops::{Range, RangeInclusive},
};
use bitvec::{prelude::Msb0, vec::BitVec};
#[derive(Debug, Default, PartialEq, Eq)]
enum SolvePuzzle {
First,
#[default]
Second,
}
#[derive(Debug)]
struct List {
numbers: Vec<i64>,
number_positions: Vec<usize>,
}
impl List {
fn parse_input<const DECRYPTION_KEY: i64, R: BufRead>(reader: R) -> Self {
reader
.lines()
.map(Result::unwrap)
.map(|line| line.parse())
.map(Result::unwrap)
.map(|number: i64| number * DECRYPTION_KEY)
.collect()
}
fn apply_rotation(&mut self) {
let mut moved: BitVec<usize, Msb0> = BitVec::repeat(false, self.numbers.len());
println!("NUM: {:>3?}", self.numbers);
println!("POS: {:>3?}", self.number_positions);
println!(
"MOV: {:>3?}",
moved.iter().by_vals().map(u8::from).collect::<Vec<_>>()
);
println!(
"***: {:>3?}",
self.number_positions
.iter()
.map(|&idx| self.numbers[idx])
.collect::<Vec<_>>()
);
for position_index in 0..self.number_positions.len() {
let number_index = self.number_positions[position_index];
println!("\n=== {number_index} ===");
let elem = self.numbers[position_index];
let op = Operation::new(elem, number_index, self.numbers.len());
println!("OP: {op:?}");
let idx_saved = self.number_positions[op.from];
let rotate_right = op.should_rotate_right();
let range = op.get_rotation_range();
if rotate_right {
self.number_positions[range.clone()].rotate_right(1);
moved[range.clone()].rotate_left(1);
} else {
self.number_positions[range.clone()].rotate_left(1);
moved[range.clone()].rotate_right(1);
}
self.number_positions[op.to] = idx_saved;
moved.set(op.to, true);
println!("NUM: {:>3?}", self.numbers);
println!("POS: {:>3?}", self.number_positions);
println!(
"MOV: {:>3?}",
moved.iter().by_vals().map(u8::from).collect::<Vec<_>>()
);
println!(
"***: {:>3?}",
self.number_positions
.iter()
.map(|&idx| self.numbers[idx])
.collect::<Vec<_>>()
);
}
}
fn sum_of_magic_positions(&self) -> i64 {
let pos_of_zero = self
.numbers
.iter()
.position(|&num| num == 0)
.expect("Zero must be present in data");
let first = (pos_of_zero + 1000) % self.numbers.len();
let second = (pos_of_zero + 2000) % self.numbers.len();
let third = (pos_of_zero + 3000) % self.numbers.len();
self.numbers[first] + self.numbers[second] + self.numbers[third]
}
}
#[derive(Debug)]
struct Operation {
from: usize,
to: usize,
insert: i64,
}
impl Operation {
fn new(insert: i64, from: usize, list_len: usize) -> Self {
let to_unbounded = from as i64 + insert;
let mut to = to_unbounded.rem_euclid(list_len as i64 - 1);
if to == 0 {
to = list_len as i64 - 1;
}
Self {
from,
to: to as usize,
insert,
}
}
fn should_rotate_right(&self) -> bool {
self.to < self.from
}
fn get_rotation_range(&self) -> RangeInclusive<usize> {
self.from.min(self.to)..=self.from.max(self.to)
}
fn index_change(&self) -> usize {
if self.to < self.from {
1
} else {
0
}
}
}
pub fn solve_first_puzzle<R: BufRead>(reader: R) -> i64 {
let mut list = List::parse_input::<1, _>(reader);
list.apply_rotation();
list.sum_of_magic_positions()
}
pub fn solve_second_puzzle<R: BufRead>(reader: R) -> i64 {
let mut list = List::parse_input::<811589153, _>(reader);
for _ in 0..10 {
list.apply_rotation();
}
list.sum_of_magic_positions()
}
fn main() {
let mut args = ::std::env::args().skip(1);
let file = args.next().unwrap_or_else(|| String::from("./input"));
let solve = args
.next()
.map(|arg| match arg.as_str() {
"first" => SolvePuzzle::First,
"second" => SolvePuzzle::Second,
_ => unreachable!(),
})
.unwrap_or_default();
let file = BufReader::new(File::open(file).expect("Opening file"));
match solve {
SolvePuzzle::First => println!("{}", solve_first_puzzle(file)),
SolvePuzzle::Second => println!("{}", solve_second_puzzle(file)),
};
}
impl FromIterator<i64> for List {
fn from_iter<T: IntoIterator<Item = i64>>(iter: T) -> Self {
let numbers: Vec<i64> = iter.into_iter().collect();
let number_positions = (0..numbers.len()).collect();
Self {
numbers,
number_positions,
}
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::*;
#[test]
fn example_on_first() {
let reader = Cursor::new(include_str!("../input.test"));
assert_eq!(solve_first_puzzle(reader), 3);
}
#[test]
fn example_on_second() {
let reader = Cursor::new(include_str!("../input.test"));
assert_eq!(solve_second_puzzle(reader), 1623178306);
}
}