Completed day 15
This commit is contained in:
parent
71d3e8cc7e
commit
52fafa5716
14
day15/Cargo.lock
generated
Normal file
14
day15/Cargo.lock
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day15"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
]
|
10
day15/Cargo.toml
Normal file
10
day15/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day15"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Tyler Hallada <tyler@hallada.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
1
day15/input/input.txt
Normal file
1
day15/input/input.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
16,1,0,18,12,14,19
|
1
day15/input/test.txt
Normal file
1
day15/input/test.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
0,3,6
|
107
day15/src/main.rs
Normal file
107
day15/src/main.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
const INPUT: &str = "input/input.txt";
|
||||||
|
|
||||||
|
fn take_turn(nums: &mut Vec<usize>) {
|
||||||
|
if let Some(position) = nums[..nums.len() - 1]
|
||||||
|
.iter()
|
||||||
|
.rposition(|&num| num == nums[nums.len() - 1])
|
||||||
|
{
|
||||||
|
nums.push(nums.len() - (position + 1));
|
||||||
|
} else {
|
||||||
|
nums.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Game {
|
||||||
|
turn: usize,
|
||||||
|
last_num: usize,
|
||||||
|
prev_nums: HashMap<usize, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
fn new(input: &str) -> Result<Self> {
|
||||||
|
let mut nums = input
|
||||||
|
.split(",")
|
||||||
|
.enumerate()
|
||||||
|
.map(|(position, num)| Ok((num.trim().parse()?, position + 1)))
|
||||||
|
.collect::<Result<Vec<(usize, usize)>>>()?;
|
||||||
|
let (last_num, turn) = nums.pop().ok_or_else(|| anyhow!("input is empty"))?;
|
||||||
|
let prev_nums = nums.into_iter().collect();
|
||||||
|
Ok(Self {
|
||||||
|
turn,
|
||||||
|
last_num,
|
||||||
|
prev_nums,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_turn(&mut self) {
|
||||||
|
self.turn += 1;
|
||||||
|
let new_num = if let Some(prev_turn) = self.prev_nums.get(&self.last_num) {
|
||||||
|
self.turn - prev_turn - 1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
self.prev_nums.insert(self.last_num, self.turn - 1);
|
||||||
|
self.last_num = new_num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_part1(input_path: &str) -> Result<usize> {
|
||||||
|
let mut file = File::open(input_path)?;
|
||||||
|
let mut nums = String::new();
|
||||||
|
file.read_to_string(&mut nums)?;
|
||||||
|
let mut nums: Vec<usize> = nums
|
||||||
|
.split(",")
|
||||||
|
.map(|num| Ok(num.trim().parse()?))
|
||||||
|
.collect::<Result<Vec<usize>>>()?;
|
||||||
|
let num_turns = 2020 - nums.len();
|
||||||
|
for _ in 0..num_turns {
|
||||||
|
take_turn(&mut nums);
|
||||||
|
}
|
||||||
|
Ok(nums.pop().expect("non-empty nums"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_part2(input_path: &str) -> Result<usize> {
|
||||||
|
let mut file = File::open(input_path)?;
|
||||||
|
let mut nums = String::new();
|
||||||
|
file.read_to_string(&mut nums)?;
|
||||||
|
let mut game = Game::new(&nums)?;
|
||||||
|
let num_turns = 30000000 - game.turn;
|
||||||
|
for _ in 0..num_turns {
|
||||||
|
game.take_turn();
|
||||||
|
}
|
||||||
|
Ok(game.last_num)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut now = Instant::now();
|
||||||
|
println!("Part 1: {}", solve_part1(INPUT).unwrap());
|
||||||
|
println!("(elapsed: {:?})", now.elapsed());
|
||||||
|
now = Instant::now();
|
||||||
|
println!("");
|
||||||
|
println!("Part 2: {}", solve_part2(INPUT).unwrap());
|
||||||
|
println!("(elapsed: {:?})", now.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_INPUT: &str = "input/test.txt";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn solves_part1() {
|
||||||
|
assert_eq!(solve_part1(TEST_INPUT).unwrap(), 436);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn solves_part2() {
|
||||||
|
assert_eq!(solve_part2(TEST_INPUT).unwrap(), 175594);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user