Work on day20
This commit is contained in:
parent
7353989dd2
commit
db7cfc6b49
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -357,6 +357,9 @@ version = "0.1.0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "day20"
|
name = "day20"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "day21"
|
name = "day21"
|
||||||
|
|
|
@ -8,3 +8,4 @@ build = true
|
||||||
app = true
|
app = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bitvec = "1.0.1"
|
||||||
|
|
5000
day20/input
Normal file
5000
day20/input
Normal file
File diff suppressed because it is too large
Load diff
7
day20/input.test
Normal file
7
day20/input.test
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
1
|
||||||
|
2
|
||||||
|
-3
|
||||||
|
3
|
||||||
|
-2
|
||||||
|
0
|
||||||
|
4
|
|
@ -1,3 +1,193 @@
|
||||||
fn main() {
|
use std::{
|
||||||
println!("Hello, world!");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue