parent
57784350d0
commit
4af822d729
@ -0,0 +1,9 @@ |
||||
[package] |
||||
name = "day23" |
||||
version = "0.1.0" |
||||
authors = ["inga-lovinde <52715130+inga-lovinde@users.noreply.github.com>"] |
||||
edition = "2018" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
@ -0,0 +1,168 @@ |
||||
use std::fmt; |
||||
use std::{io::{self, BufRead}}; |
||||
|
||||
#[derive(Clone, Copy)] |
||||
struct Entry { |
||||
previous_value: usize, |
||||
next_value: usize, |
||||
} |
||||
|
||||
struct GameState { |
||||
current_cup: usize, |
||||
state: Vec<Entry>, |
||||
} |
||||
|
||||
impl GameState { |
||||
fn new(raw_data: &[usize]) -> GameState { |
||||
let data: Vec<_> = raw_data.iter().map(|&x| x-1).collect(); |
||||
let mut state = vec![None; data.len()]; |
||||
state[data[0]] = Some(Entry { |
||||
previous_value: data[data.len()-1], |
||||
next_value: data[1], |
||||
}); |
||||
for i in 1..data.len()-1 { |
||||
state[data[i]] = Some(Entry { |
||||
previous_value: data[i-1], |
||||
next_value: data[i+1], |
||||
}); |
||||
} |
||||
state[data[data.len()-1]] = Some(Entry { |
||||
previous_value: data[data.len()-2], |
||||
next_value: data[0], |
||||
}); |
||||
|
||||
GameState { |
||||
current_cup: data[0], |
||||
state: state.into_iter().collect::<Option<_>>().unwrap(), |
||||
} |
||||
} |
||||
|
||||
fn get_next_value(&self, value: usize) -> usize { |
||||
self.state[value].next_value |
||||
} |
||||
|
||||
// unsafe, leaves self in an inconsistent state, only invoke from link_values
|
||||
fn set_next_value(&mut self, value: usize, new_next_value: usize) { |
||||
self.state[value] = Entry { |
||||
next_value: new_next_value, |
||||
..self.state[value] |
||||
} |
||||
} |
||||
|
||||
// unsafe, leaves self in an inconsistent state, only invoke from link_values
|
||||
fn set_previous_value(&mut self, value: usize, new_previous_value: usize) { |
||||
self.state[value] = Entry { |
||||
previous_value: new_previous_value, |
||||
..self.state[value] |
||||
} |
||||
} |
||||
|
||||
// unsafe, leaves self in an inconsistent state, only invoke from move_value
|
||||
fn link_values(&mut self, previous_value: usize, next_value: usize) { |
||||
self.set_next_value(previous_value, next_value); |
||||
self.set_previous_value(next_value, previous_value); |
||||
} |
||||
|
||||
fn move_value(&mut self, value: usize, new_previous: usize) { |
||||
let old_previous = self.state[value].previous_value; |
||||
let old_next = self.state[value].next_value; |
||||
let new_next = self.state[new_previous].next_value; |
||||
self.link_values(old_previous, old_next); |
||||
self.link_values(new_previous, value); |
||||
self.link_values(value, new_next); |
||||
} |
||||
|
||||
fn get_destination_cup(&self, current_cup: usize) -> usize { |
||||
let blacklisted_cups = [ |
||||
current_cup, |
||||
self.get_next_value(current_cup), |
||||
self.get_next_value(self.get_next_value(current_cup)), |
||||
self.get_next_value(self.get_next_value(self.get_next_value(current_cup))), |
||||
]; |
||||
|
||||
let mut destination_label = current_cup; |
||||
loop { |
||||
if destination_label == 0 { |
||||
destination_label = self.state.len(); |
||||
} |
||||
destination_label -= 1; |
||||
|
||||
if !blacklisted_cups.contains(&destination_label) { |
||||
return destination_label; |
||||
} |
||||
} |
||||
} |
||||
|
||||
fn mutate_next_step(&mut self) { |
||||
let current_cup = self.current_cup; |
||||
let mut destination_cup = self.get_destination_cup(current_cup); |
||||
for _i in 0..3 { |
||||
let value_to_move = self.get_next_value(current_cup); |
||||
self.move_value(value_to_move, destination_cup); |
||||
destination_cup = value_to_move; |
||||
} |
||||
|
||||
self.current_cup = self.get_next_value(current_cup); |
||||
} |
||||
|
||||
fn get_hard_result(&self) -> u64 { |
||||
(self.get_next_value(0) as u64 + 1) * (self.get_next_value(self.get_next_value(0)) as u64 + 1) |
||||
} |
||||
} |
||||
|
||||
impl fmt::Debug for GameState { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
let mut list = Vec::with_capacity(self.state.len()); |
||||
list.push(1); |
||||
let mut current_value = self.get_next_value(0); |
||||
while current_value != 0 { |
||||
list.push(current_value + 1); |
||||
current_value = self.get_next_value(current_value); |
||||
} |
||||
|
||||
f.debug_struct("GameState") |
||||
.field("current_cup", &(self.current_cup + 1)) |
||||
.field("cups", &list) |
||||
.finish() |
||||
} |
||||
} |
||||
|
||||
fn game_simple(original_data: &[usize]) { |
||||
let mut state = GameState::new(&original_data); |
||||
|
||||
for i in 0..=100 { |
||||
println!("{}: {:?}", i, state); |
||||
state.mutate_next_step(); |
||||
} |
||||
} |
||||
|
||||
fn game_hard(original_data: &[usize]) { |
||||
let mut state = GameState::new(&original_data); |
||||
|
||||
for i in 0..10_000_000 { |
||||
if i % 10_000 == 0 { |
||||
println!("Step {}", i); |
||||
} |
||||
state.mutate_next_step(); |
||||
} |
||||
|
||||
println!("{}", state.get_hard_result()); |
||||
} |
||||
|
||||
fn main() { |
||||
let stdin = io::stdin(); |
||||
let mut lines = stdin.lock().lines(); |
||||
let line = lines.next().unwrap().unwrap(); |
||||
let original_state: Vec<usize> = line.chars().map(|ch| ch.to_string().parse().unwrap()).collect(); |
||||
game_simple(&original_state); |
||||
|
||||
let mut hard_state = Vec::with_capacity(1_000_000); |
||||
for i in 0..original_state.len() { |
||||
hard_state.push(original_state[i]); |
||||
} |
||||
|
||||
for i in original_state.len()..1_000_000 { |
||||
hard_state.push(i+1); |
||||
} |
||||
game_hard(&hard_state); |
||||
} |
Loading…
Reference in new issue