More D22 WIP
This commit is contained in:
parent
5fe8277bf1
commit
656ca6e0b7
|
@ -0,0 +1 @@
|
|||
43719219567200 too low
|
|
@ -1,5 +1,8 @@
|
|||
use std::collections::HashSet;
|
||||
use std::io::{self, BufRead};
|
||||
mod tests;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ShuffleOperation {
|
||||
CutLeft(usize),
|
||||
CutRight(usize),
|
||||
|
@ -7,30 +10,32 @@ enum ShuffleOperation {
|
|||
Reverse,
|
||||
}
|
||||
|
||||
fn parse_operation(operation: &str) -> ShuffleOperation {
|
||||
let words: Vec<_> = operation.split(' ').collect();
|
||||
match words[0] {
|
||||
"cut" => {
|
||||
let offset: isize = words[1].parse().expect("Not a valid number for cutting");
|
||||
if offset < 0 {
|
||||
ShuffleOperation::CutRight(offset.abs() as usize)
|
||||
} else {
|
||||
ShuffleOperation::CutLeft(offset as usize)
|
||||
impl<'a> From<&'a str> for ShuffleOperation {
|
||||
fn from(raw: &'a str) -> ShuffleOperation {
|
||||
let words: Vec<_> = raw.split(' ').collect();
|
||||
match words[0] {
|
||||
"cut" => {
|
||||
let offset: isize = words[1].parse().expect("Not a valid number for cutting");
|
||||
if offset < 0 {
|
||||
ShuffleOperation::CutRight(offset.abs() as usize)
|
||||
} else {
|
||||
ShuffleOperation::CutLeft(offset as usize)
|
||||
}
|
||||
}
|
||||
"deal" => match words[1] {
|
||||
// with increment
|
||||
"with" => ShuffleOperation::DealWithIncrement(words[3].parse().unwrap()),
|
||||
// into new stack
|
||||
"into" => ShuffleOperation::Reverse,
|
||||
_ => unreachable!("Unknown deal command"),
|
||||
},
|
||||
_ => unreachable!("Unknown shuffle command"),
|
||||
}
|
||||
"deal" => match words[1] {
|
||||
// with increment
|
||||
"with" => ShuffleOperation::DealWithIncrement(words[3].parse().unwrap()),
|
||||
// into new stack
|
||||
"into" => ShuffleOperation::Reverse,
|
||||
_ => unreachable!("Unknown deal command"),
|
||||
},
|
||||
_ => unreachable!("Unknown shuffle command"),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(deck: &mut Vec<usize>, operation: &str) {
|
||||
match parse_operation(operation) {
|
||||
fn apply(deck: &mut Vec<usize>, operation: ShuffleOperation) {
|
||||
match operation {
|
||||
ShuffleOperation::Reverse => deck.reverse(),
|
||||
ShuffleOperation::CutLeft(offset) => {
|
||||
let clone = deck.clone();
|
||||
|
@ -53,27 +58,16 @@ fn apply(deck: &mut Vec<usize>, operation: &str) {
|
|||
};
|
||||
}
|
||||
|
||||
fn get_previous_index(current: usize, operation: &str, deck_size: usize) -> usize {
|
||||
match parse_operation(operation) {
|
||||
fn get_previous_index(current: usize, operation: ShuffleOperation, deck_size: usize) -> usize {
|
||||
match operation {
|
||||
ShuffleOperation::Reverse => deck_size - current - 1,
|
||||
ShuffleOperation::CutLeft(offset) => {
|
||||
if current >= deck_size - offset {
|
||||
current - (deck_size - offset)
|
||||
} else {
|
||||
current + offset
|
||||
}
|
||||
}
|
||||
ShuffleOperation::CutRight(offset) => {
|
||||
if current < offset {
|
||||
deck_size - offset + current
|
||||
} else {
|
||||
current - offset
|
||||
}
|
||||
}
|
||||
ShuffleOperation::CutLeft(offset) => (current + offset) % deck_size,
|
||||
ShuffleOperation::CutRight(offset) => (current + deck_size - offset) % deck_size,
|
||||
ShuffleOperation::DealWithIncrement(increment) => (0..)
|
||||
.filter_map(|x| {
|
||||
if (x * deck_size + current) % increment == 0 {
|
||||
Some((x * deck_size + current) / increment)
|
||||
let old_position = x * deck_size + current;
|
||||
if old_position % increment == 0 {
|
||||
Some(old_position / increment)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -91,171 +85,42 @@ fn create_deck(len: usize) -> Vec<usize> {
|
|||
|
||||
fn get_original_index(
|
||||
initial: usize,
|
||||
iterations: u128,
|
||||
iterations: i128,
|
||||
deck_size: usize,
|
||||
operations: &[String],
|
||||
) -> u128 {
|
||||
operations: &[ShuffleOperation],
|
||||
) -> i128 {
|
||||
let mut last = initial;
|
||||
for operation in operations.iter().rev() {
|
||||
last = get_previous_index(last, operation, deck_size);
|
||||
last = get_previous_index(last, *operation, deck_size);
|
||||
}
|
||||
let initial = initial as i128;
|
||||
let deck_size = deck_size as i128;
|
||||
let drift = last as i128 - initial;
|
||||
dbg!(drift);
|
||||
let new_index = initial + drift * iterations;
|
||||
if new_index >= 0 {
|
||||
new_index % deck_size
|
||||
} else {
|
||||
(new_index + deck_size * ((new_index.abs() / deck_size) + 1)) % deck_size
|
||||
}
|
||||
let drift = (last - initial) as u128;
|
||||
(P2_INDEX as u128 + drift * iterations) % deck_size as u128
|
||||
}
|
||||
|
||||
const DECK_SIZE: usize = 10007;
|
||||
const P2_DECK_SIZE: usize = 119315717514047;
|
||||
const P2_ITERATIONS: u128 = 101741582076661;
|
||||
const P2_INDEX: usize = 2020;
|
||||
|
||||
fn main() {
|
||||
let input: Vec<_> = io::stdin().lock().lines().map(|l| l.unwrap()).collect();
|
||||
let input: Vec<ShuffleOperation> = io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.map(|l| ShuffleOperation::from(l.unwrap().as_ref()))
|
||||
.collect();
|
||||
const DECK_SIZE: usize = 10007;
|
||||
let mut deck = create_deck(DECK_SIZE);
|
||||
for operation in &input {
|
||||
apply(&mut deck, operation);
|
||||
apply(&mut deck, *operation);
|
||||
}
|
||||
println!("Part 1: {}", deck.iter().position(|&x| x == 2019).unwrap());
|
||||
let p2 = get_original_index(P2_INDEX, P2_ITERATIONS, P2_DECK_SIZE, &input);
|
||||
println!("Part 2: {}", p2);
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const EXAMPLE_1: &str = "deal with increment 7
|
||||
deal into new stack
|
||||
deal into new stack";
|
||||
const EXAMPLE_2: &str = "cut 6
|
||||
deal with increment 7
|
||||
deal into new stack";
|
||||
const EXAMPLE_3: &str = "deal with increment 7
|
||||
deal with increment 9
|
||||
cut -2";
|
||||
const EXAMPLE_4: &str = "deal into new stack
|
||||
cut -2
|
||||
deal with increment 7
|
||||
cut 8
|
||||
cut -4
|
||||
deal with increment 7
|
||||
cut 3
|
||||
deal with increment 9
|
||||
deal with increment 3
|
||||
cut -1";
|
||||
/// Example 4 but with an even number of reversals
|
||||
const EXAMPLE_5: &str = "deal into new stack
|
||||
cut -2
|
||||
deal with increment 7
|
||||
cut 8
|
||||
cut -4
|
||||
deal with increment 7
|
||||
cut 3
|
||||
deal into new stack
|
||||
deal with increment 9
|
||||
deal with increment 3
|
||||
cut -1";
|
||||
|
||||
#[test]
|
||||
fn deal_test() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_1.lines() {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cut_deal_test() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_2.lines() {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[3, 0, 7, 4, 1, 8, 5, 2, 9, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_4.lines() {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[9, 2, 5, 8, 1, 4, 7, 0, 3, 6]);
|
||||
}
|
||||
|
||||
// tests for part 2
|
||||
#[test]
|
||||
fn reverse_stack_deal_test() {
|
||||
assert_eq!(
|
||||
reverse_step("deal into new stack", 10),
|
||||
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse_cut_test() {
|
||||
assert_eq!(reverse_step("cut 3", 10), [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]);
|
||||
assert_eq!(reverse_step("cut -4", 10), [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse_increment_test() {
|
||||
assert_eq!(
|
||||
reverse_step("deal with increment 3", 10),
|
||||
[0, 7, 4, 1, 8, 5, 2, 9, 6, 3]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test1() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_1), 0);
|
||||
assert_eq!(index_before_instructions(2, EXAMPLE_1), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test2() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_2), 3);
|
||||
assert_eq!(index_before_instructions(6, EXAMPLE_2), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test3() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_3), 6);
|
||||
assert_eq!(index_before_instructions(9, EXAMPLE_3), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_twice() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_5.lines() {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
for line in EXAMPLE_5.lines() {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[2, 1, 0, 9, 8, 7, 6, 5, 4, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpolate_drift_test() {
|
||||
//get_original_index(0, 1, 10, EXAMPLE_4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test4() {
|
||||
let instructions = EXAMPLE_4;
|
||||
assert_eq!(index_before_instructions(1, instructions), 2);
|
||||
}
|
||||
|
||||
fn index_before_instructions(mut last: usize, instructions: &str) -> usize {
|
||||
for line in instructions.lines().rev() {
|
||||
last = get_previous_index(last, line, 10);
|
||||
}
|
||||
last
|
||||
}
|
||||
|
||||
fn reverse_step(instruction: &str, len: usize) -> Vec<usize> {
|
||||
(0..len)
|
||||
.into_iter()
|
||||
.map(|n| get_previous_index(n, instruction, 10))
|
||||
.collect()
|
||||
}
|
||||
|
||||
const P2_DECK_SIZE: usize = 119315717514047;
|
||||
const P2_ITERATIONS: i128 = 101_741_582_076_661;
|
||||
const P2_INDEX: usize = 2020;
|
||||
let mut last = P2_INDEX;
|
||||
println!("Part 2: {}", last);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
use super::*;
|
||||
|
||||
const EXAMPLE_1: &str = "deal with increment 7
|
||||
deal into new stack
|
||||
deal into new stack";
|
||||
const EXAMPLE_2: &str = "cut 6
|
||||
deal with increment 7
|
||||
deal into new stack";
|
||||
const EXAMPLE_3: &str = "deal with increment 7
|
||||
deal with increment 9
|
||||
cut -2";
|
||||
const EXAMPLE_4: &str = "deal into new stack
|
||||
cut -2
|
||||
deal with increment 7
|
||||
cut 8
|
||||
cut -4
|
||||
deal with increment 7
|
||||
cut 3
|
||||
deal with increment 9
|
||||
deal with increment 3
|
||||
cut -1";
|
||||
/// Example 4 but with an even number of reversals
|
||||
const EXAMPLE_5: &str = "deal into new stack
|
||||
cut -2
|
||||
deal with increment 7
|
||||
cut 8
|
||||
cut -4
|
||||
deal with increment 7
|
||||
cut 3
|
||||
deal into new stack
|
||||
deal with increment 9
|
||||
deal with increment 3
|
||||
cut -1";
|
||||
|
||||
#[test]
|
||||
fn deal_test() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_1.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cut_deal_test() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_2.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[3, 0, 7, 4, 1, 8, 5, 2, 9, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_4.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[9, 2, 5, 8, 1, 4, 7, 0, 3, 6]);
|
||||
}
|
||||
|
||||
// tests for part 2
|
||||
#[test]
|
||||
fn reverse_stack_deal_test() {
|
||||
assert_eq!(
|
||||
reverse_step("deal into new stack", 10),
|
||||
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse_cut_test() {
|
||||
assert_eq!(reverse_step("cut 3", 10), [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]);
|
||||
assert_eq!(reverse_step("cut -4", 10), [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse_increment_test() {
|
||||
assert_eq!(
|
||||
reverse_step("deal with increment 3", 10),
|
||||
[0, 7, 4, 1, 8, 5, 2, 9, 6, 3]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test1() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_1), 0);
|
||||
assert_eq!(index_before_instructions(2, EXAMPLE_1), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test2() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_2), 3);
|
||||
assert_eq!(index_before_instructions(6, EXAMPLE_2), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test3() {
|
||||
assert_eq!(index_before_instructions(0, EXAMPLE_3), 6);
|
||||
assert_eq!(index_before_instructions(9, EXAMPLE_3), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_twice() {
|
||||
let mut deck = create_deck(10);
|
||||
for line in EXAMPLE_5.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
for line in EXAMPLE_5.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[2, 1, 0, 9, 8, 7, 6, 5, 4, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_original_index_test() {
|
||||
let instructions = EXAMPLE_1;
|
||||
let mut deck = create_deck(10);
|
||||
for line in instructions.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
assert_eq!(deck, &[0, 3, 6, 9, 2, 5, 8, 1, 4, 7]);
|
||||
assert_eq!(
|
||||
deck,
|
||||
(0..10)
|
||||
.map(|n| index_before_instructions(n, instructions))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(
|
||||
deck,
|
||||
(0..10)
|
||||
.map(|n| get_original_index(
|
||||
n,
|
||||
1,
|
||||
10,
|
||||
&instructions
|
||||
.lines()
|
||||
.map(|l| l.into())
|
||||
.collect::<Vec<_>>()
|
||||
) as usize)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
(0..10)
|
||||
.map(|n| index_before_instructions(n, EXAMPLE_4))
|
||||
.collect::<Vec<_>>(),
|
||||
(0..10)
|
||||
.map(|n| get_original_index(
|
||||
n,
|
||||
1,
|
||||
10,
|
||||
&EXAMPLE_4.lines().map(|l| l.into()).collect::<Vec<_>>()
|
||||
) as usize)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpolate_drift_test() {
|
||||
const INSTRUCTIONS: &str = EXAMPLE_5;
|
||||
const ITERATIONS: usize = 4;
|
||||
let mut deck = create_deck(10);
|
||||
for _ in 0..ITERATIONS {
|
||||
for line in INSTRUCTIONS.lines().map(|l| l.into()) {
|
||||
apply(&mut deck, line);
|
||||
}
|
||||
}
|
||||
assert_eq!(
|
||||
deck,
|
||||
(0..10)
|
||||
.map(|n| get_original_index(
|
||||
n,
|
||||
ITERATIONS as i128,
|
||||
10,
|
||||
&INSTRUCTIONS
|
||||
.lines()
|
||||
.map(|l| l.into())
|
||||
.collect::<Vec<_>>()
|
||||
) as usize)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_reverse_test4() {
|
||||
assert_eq!(index_before_instructions(1, EXAMPLE_4), 2);
|
||||
}
|
||||
|
||||
fn index_before_instructions(mut last: usize, instructions: &str) -> usize {
|
||||
for line in instructions.lines().rev().map(|l| l.into()) {
|
||||
last = get_previous_index(last, line, 10);
|
||||
}
|
||||
last
|
||||
}
|
||||
|
||||
fn reverse_step(instruction: &str, len: usize) -> Vec<usize> {
|
||||
(0..len)
|
||||
.map(|n| get_previous_index(n, instruction.into(), 10))
|
||||
.collect()
|
||||
}
|
Loading…
Reference in New Issue
Block a user