Add 2022 solutions

This commit is contained in:
Timothy Warren 2023-12-04 16:12:26 -05:00
parent b372fd0213
commit 314ef30c27
62 changed files with 14743 additions and 0 deletions

182
2022/.gitignore vendored Normal file
View File

@ -0,0 +1,182 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust,intellij+all,macos,vim,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=rust,intellij+all,macos,vim,visualstudiocode
### Intellij+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
.idea/*
!.idea/codeStyles
!.idea/runConfigurations
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# End of https://www.toptal.com/developers/gitignore/api/rust,intellij+all,macos,vim,visualstudiocode

3
2022/README.md Normal file
View File

@ -0,0 +1,3 @@
# Advent of Code 2022
[https://adventofcode.com/2022](https://adventofcode.com/2022)

View File

@ -0,0 +1,8 @@
[package]
name = "aoc-shared"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,7 @@
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Direction {
Up,
Down,
Left,
Right,
}

126
2022/aoc-shared/src/grid.rs Normal file
View File

@ -0,0 +1,126 @@
/// Reusing part of day 8's solution for a virtual 2d grid
#[derive(Debug)]
pub struct Grid<T> {
width: usize,
pub vec: Vec<T>,
}
impl<T> Grid<T> {
pub fn new(width: usize) -> Self {
Grid {
width,
vec: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
pub fn num_cols(&self) -> usize {
self.width
}
pub fn num_rows(&self) -> usize {
self.len() / self.num_cols()
}
// Convert x,y coordinate into linear array index
pub fn xy_idx(&self, x: usize, y: usize) -> usize {
(y * self.num_cols()) + x
}
/// Convert linear array index to x,y coordinate
pub fn idx_xy(&self, idx: usize) -> (usize, usize) {
(idx % self.num_cols(), idx / self.num_cols())
}
pub fn get(&self, idx: usize) -> Option<&T> {
self.vec.get(idx)
}
pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
self.vec.get_mut(idx)
}
pub fn get_row(&mut self, row_num: usize) -> &mut [T] {
let start = self.row_first_idx(row_num);
let end = self.row_last_idx(row_num);
&mut self.vec[start..=end]
}
pub fn row_first_idx(&self, row: usize) -> usize {
let idx = row * self.num_cols();
if idx < self.len() {
idx
} else {
self.len()
}
}
pub fn row_last_idx(&self, row: usize) -> usize {
if (row + 1) > self.num_rows() {
return self.len();
}
self.row_first_idx(row + 1) - 1
}
pub fn get_row_indexes(&self, row_num: usize) -> Vec<usize> {
(self.row_first_idx(row_num)..=self.row_last_idx(row_num)).collect()
}
pub fn get_column_indexes(&self, col_num: usize) -> Vec<usize> {
let mut indexes = Vec::new();
if col_num >= self.num_cols() {
panic!(
"Asked for column {}, there are {} columns",
col_num,
self.num_cols()
);
}
for r in 0..self.num_rows() {
let idx = self.num_cols() * r + col_num;
indexes.push(idx);
}
indexes
}
}
#[macro_export]
/// Simplifies newtype wrapping of the `Grid` struct
macro_rules! impl_grid_newtype {
($($struct: tt, $target: path, $type: ty),* ) => {
$(
impl ::core::ops::Deref for $struct<$type> {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for $struct<$type> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl $struct<$type> {
pub fn new(width: usize) -> Self {
$struct(<$target>::new(width))
}
}
)*
}
}

View File

@ -0,0 +1,43 @@
pub mod grid;
pub mod enums;
pub use grid::*;
pub use enums::*;
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct Location {
pub x: isize,
pub y: isize,
}
impl Location {
pub fn new(x: isize, y: isize) -> Self {
Location { x, y }
}
pub fn get_distance(self, other: Self) -> f64 {
let squares = (other.x - self.x).pow(2) + (other.y - self.y).pow(2);
(squares as f64).sqrt()
}
}
#[macro_export]
macro_rules! deref {
($($struct: ty, $target: ty),* ) => {
$(
impl ::core::ops::Deref for $struct {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for $struct {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
)*
}
}

8
2022/day1/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day1"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

52
2022/day1/README.md Normal file
View File

@ -0,0 +1,52 @@
# Day 1: Calorie Counting
## Part 1
Santa's reindeer typically eat regular reindeer food, but they need a lot of magical energy to deliver presents on Christmas. For that, their favorite snack is a special type of star fruit that only grows deep in the jungle. The Elves have brought you on their annual expedition to the grove where the fruit grows.
To supply enough magical energy, the expedition needs to retrieve a minimum of fifty stars by December 25th. Although the Elves assure you that the grove has plenty of fruit, you decide to grab any fruit you see along the way, just in case.
Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck!
The jungle must be too overgrown and difficult to navigate in vehicles or access from the air; the Elves' expedition traditionally goes on foot. As your boats approach land, the Elves begin taking inventory of their supplies. One important consideration is food - in particular, the number of Calories each Elf is carrying (your puzzle input).
The Elves take turns writing down the number of Calories contained by the various meals, snacks, rations, etc. that they've brought with them, one item per line. Each Elf separates their own inventory from the previous Elf's inventory (if any) by a blank line.
For example, suppose the Elves finish writing their items' Calories and end up with the following list:
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
This list represents the Calories of the food carried by five Elves:
The first Elf is carrying food with 1000, 2000, and 3000 Calories, a total of 6000 Calories.
The second Elf is carrying one food item with 4000 Calories.
The third Elf is carrying food with 5000 and 6000 Calories, a total of 11000 Calories.
The fourth Elf is carrying food with 7000, 8000, and 9000 Calories, a total of 24000 Calories.
The fifth Elf is carrying one food item with 10000 Calories.
In case the Elves get hungry and need extra snacks, they need to know which Elf to ask: they'd like to know how many Calories are being carried by the Elf carrying the most Calories. In the example above, this is 24000 (carried by the fourth Elf).
**Find the Elf carrying the most Calories. How many total Calories is that Elf carrying?**
## Part 2
By the time you calculate the answer to the Elves' question, they've already realized that the Elf carrying the most Calories of food might eventually run out of snacks.
To avoid this unacceptable situation, the Elves would instead like to know the total Calories carried by the top three Elves carrying the most Calories. That way, even if one of those Elves runs out of snacks, they still have two backups.
In the example above, the top three Elves are the fourth Elf (with 24000 Calories), then the third Elf (with 11000 Calories), then the fifth Elf (with 10000 Calories). The sum of the Calories carried by these three elves is 45000.
**Find the top three Elves carrying the most Calories. How many Calories are those Elves carrying in total?**

2244
2022/day1/src/input.txt Normal file

File diff suppressed because it is too large Load Diff

38
2022/day1/src/main.rs Normal file
View File

@ -0,0 +1,38 @@
fn get_elves(raw: &str) -> Vec<Vec<u32>> {
raw.split("\n\n")
.map(|raw_elf| {
raw_elf
.split('\n')
.filter(|value| value.len() > 0)
.map(move |value| value.parse::<u32>().unwrap())
.collect::<Vec<u32>>()
})
.collect()
}
fn get_elf_totals(elves: &Vec<Vec<u32>>) -> Vec<u32> {
elves
.clone()
.into_iter()
.map(|elf| {
elf.into_iter()
.reduce(|accum, item| accum + item)
.unwrap()
})
.collect()
}
fn main() {
let file_str = include_str!("input.txt"); //fs::read_to_string("input.txt")?;
let elves = get_elves(&file_str);
let mut totals: Vec<u32> = get_elf_totals(&elves);
totals.sort();
totals.reverse();
let most = totals[0];
let top3 = totals[0] + totals[1] + totals[2];
println!("Part 1: Most calories for one elf: {}", most);
println!("Part 2: Calories for top three elves: {}", top3);
}

8
2022/day10/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day10"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

323
2022/day10/README.md Normal file
View File

@ -0,0 +1,323 @@
# Day 10: Cathode-Ray Tube
## Part 1
You avoid the ropes, plunge into the river, and swim to shore.
The Elves yell something about meeting back up with them upriver, but the river is too loud to tell exactly what they're saying. They finish crossing the bridge and disappear from view.
Situations like this must be why the Elves prioritized getting the communication system on your handheld device working. You pull it out of your pack, but the amount of water slowly draining from a big crack in its screen tells you it probably won't be of much immediate use.
Unless, that is, you can design a replacement for the device's video system! It seems to be some kind of cathode-ray tube screen and simple CPU that are both driven by a precise clock circuit. The clock circuit ticks at a constant rate; each tick is called a cycle.
Start by figuring out the signal being sent by the CPU. The CPU has a single register, X, which starts with the value 1. It supports only two instructions:
- addx V takes two cycles to complete. After two cycles, the X register is increased by the value V. (V can be negative.)
- noop takes one cycle to complete. It has no other effect.
The CPU uses these instructions in a program (your puzzle input) to, somehow, tell the screen what to draw.
Consider the following small program:
noop
addx 3
addx -5
Execution of this program proceeds as follows:
- At the start of the first cycle, the noop instruction begins execution. During the first cycle, X is 1. After the first cycle, the noop instruction finishes execution, doing nothing.
- At the start of the second cycle, the addx 3 instruction begins execution. During the second cycle, X is still 1.
- During the third cycle, X is still 1. After the third cycle, the addx 3 instruction finishes execution, setting X to 4.
- At the start of the fourth cycle, the addx -5 instruction begins execution. During the fourth cycle, X is still 4.
- During the fifth cycle, X is still 4. After the fifth cycle, the addx -5 instruction finishes execution, setting X to -1.
Maybe you can learn something by looking at the value of the X register throughout execution. For now, consider the signal strength (the cycle number multiplied by the value of the X register) during the 20th cycle and every 40 cycles after that (that is, during the 20th, 60th, 100th, 140th, 180th, and 220th cycles).
For example, consider this larger program:
addx 15
addx -11
addx 6
addx -3
addx 5
addx -1
addx -8
addx 13
addx 4
noop
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx -35
addx 1
addx 24
addx -19
addx 1
addx 16
addx -11
noop
noop
addx 21
addx -15
noop
noop
addx -3
addx 9
addx 1
addx -3
addx 8
addx 1
addx 5
noop
noop
noop
noop
noop
addx -36
noop
addx 1
addx 7
noop
noop
noop
addx 2
addx 6
noop
noop
noop
noop
noop
addx 1
noop
noop
addx 7
addx 1
noop
addx -13
addx 13
addx 7
noop
addx 1
addx -33
noop
noop
noop
addx 2
noop
noop
noop
addx 8
noop
addx -1
addx 2
addx 1
noop
addx 17
addx -9
addx 1
addx 1
addx -3
addx 11
noop
noop
addx 1
noop
addx 1
noop
noop
addx -13
addx -19
addx 1
addx 3
addx 26
addx -30
addx 12
addx -1
addx 3
addx 1
noop
noop
noop
addx -9
addx 18
addx 1
addx 2
noop
noop
addx 9
noop
noop
noop
addx -1
addx 2
addx -37
addx 1
addx 3
noop
addx 15
addx -21
addx 22
addx -6
addx 1
noop
addx 2
addx 1
noop
addx -10
noop
noop
addx 20
addx 1
addx 2
addx 2
addx -6
addx -11
noop
noop
noop
The interesting signal strengths can be determined as follows:
During the 20th cycle, register X has the value 21, so the signal strength is 20 * 21 = 420. (The 20th cycle occurs in the middle of the second addx -1, so the value of register X is the starting value, 1, plus all of the other addx values up to that point: 1 + 15 - 11 + 6 - 3 + 5 - 1 - 8 + 13 + 4 = 21.)
During the 60th cycle, register X has the value 19, so the signal strength is 60 * 19 = 1140.
During the 100th cycle, register X has the value 18, so the signal strength is 100 * 18 = 1800.
During the 140th cycle, register X has the value 21, so the signal strength is 140 * 21 = 2940.
During the 180th cycle, register X has the value 16, so the signal strength is 180 * 16 = 2880.
During the 220th cycle, register X has the value 18, so the signal strength is 220 * 18 = 3960.
The sum of these signal strengths is 13140.
Find the signal strength during the 20th, 60th, 100th, 140th, 180th, and 220th cycles. **What is the sum of these six signal strengths?**
## Part 2
It seems like the X register controls the horizontal position of a sprite. Specifically, the sprite is 3 pixels wide, and the X register sets the horizontal position of the middle of that sprite. (In this system, there is no such thing as "vertical position": if the sprite's horizontal position puts its pixels where the CRT is currently drawing, then those pixels will be drawn.)
You count the pixels on the CRT: 40 wide and 6 high. This CRT screen draws the top row of pixels left-to-right, then the row below that, and so on. The left-most pixel in each row is in position 0, and the right-most pixel in each row is in position 39.
Like the CPU, the CRT is tied closely to the clock circuit: the CRT draws a single pixel during each cycle. Representing each pixel of the screen as a #, here are the cycles during which the first and last pixel in each row are drawn:
Cycle 1 -> ######################################## <- Cycle 40
Cycle 41 -> ######################################## <- Cycle 80
Cycle 81 -> ######################################## <- Cycle 120
Cycle 121 -> ######################################## <- Cycle 160
Cycle 161 -> ######################################## <- Cycle 200
Cycle 201 -> ######################################## <- Cycle 240
So, by carefully timing the CPU instructions and the CRT drawing operations, you should be able to determine whether the sprite is visible the instant each pixel is drawn. If the sprite is positioned such that one of its three pixels is the pixel currently being drawn, the screen produces a lit pixel (#); otherwise, the screen leaves the pixel dark (.).
The first few pixels from the larger example above are drawn as follows:
Sprite position: ###.....................................
Start cycle 1: begin executing addx 15
During cycle 1: CRT draws pixel in position 0
Current CRT row: #
During cycle 2: CRT draws pixel in position 1
Current CRT row: ##
End of cycle 2: finish executing addx 15 (Register X is now 16)
Sprite position: ...............###......................
Start cycle 3: begin executing addx -11
During cycle 3: CRT draws pixel in position 2
Current CRT row: ##.
During cycle 4: CRT draws pixel in position 3
Current CRT row: ##..
End of cycle 4: finish executing addx -11 (Register X is now 5)
Sprite position: ....###.................................
Start cycle 5: begin executing addx 6
During cycle 5: CRT draws pixel in position 4
Current CRT row: ##..#
During cycle 6: CRT draws pixel in position 5
Current CRT row: ##..##
End of cycle 6: finish executing addx 6 (Register X is now 11)
Sprite position: ..........###...........................
Start cycle 7: begin executing addx -3
During cycle 7: CRT draws pixel in position 6
Current CRT row: ##..##.
During cycle 8: CRT draws pixel in position 7
Current CRT row: ##..##..
End of cycle 8: finish executing addx -3 (Register X is now 8)
Sprite position: .......###..............................
Start cycle 9: begin executing addx 5
During cycle 9: CRT draws pixel in position 8
Current CRT row: ##..##..#
During cycle 10: CRT draws pixel in position 9
Current CRT row: ##..##..##
End of cycle 10: finish executing addx 5 (Register X is now 13)
Sprite position: ............###.........................
Start cycle 11: begin executing addx -1
During cycle 11: CRT draws pixel in position 10
Current CRT row: ##..##..##.
During cycle 12: CRT draws pixel in position 11
Current CRT row: ##..##..##..
End of cycle 12: finish executing addx -1 (Register X is now 12)
Sprite position: ...........###..........................
Start cycle 13: begin executing addx -8
During cycle 13: CRT draws pixel in position 12
Current CRT row: ##..##..##..#
During cycle 14: CRT draws pixel in position 13
Current CRT row: ##..##..##..##
End of cycle 14: finish executing addx -8 (Register X is now 4)
Sprite position: ...###..................................
Start cycle 15: begin executing addx 13
During cycle 15: CRT draws pixel in position 14
Current CRT row: ##..##..##..##.
During cycle 16: CRT draws pixel in position 15
Current CRT row: ##..##..##..##..
End of cycle 16: finish executing addx 13 (Register X is now 17)
Sprite position: ................###.....................
Start cycle 17: begin executing addx 4
During cycle 17: CRT draws pixel in position 16
Current CRT row: ##..##..##..##..#
During cycle 18: CRT draws pixel in position 17
Current CRT row: ##..##..##..##..##
End of cycle 18: finish executing addx 4 (Register X is now 21)
Sprite position: ....................###.................
Start cycle 19: begin executing noop
During cycle 19: CRT draws pixel in position 18
Current CRT row: ##..##..##..##..##.
End of cycle 19: finish executing noop
Start cycle 20: begin executing addx -1
During cycle 20: CRT draws pixel in position 19
Current CRT row: ##..##..##..##..##..
During cycle 21: CRT draws pixel in position 20
Current CRT row: ##..##..##..##..##..#
End of cycle 21: finish executing addx -1 (Register X is now 20)
Sprite position: ...................###..................
Allowing the program to run to completion causes the CRT to produce the following image:
##..##..##..##..##..##..##..##..##..##..
###...###...###...###...###...###...###.
####....####....####....####....####....
#####.....#####.....#####.....#####.....
######......######......######......####
#######.......#######.......#######.....
Render the image given by your program. What eight capital letters appear on your CRT?

140
2022/day10/src/input.txt Normal file
View File

@ -0,0 +1,140 @@
addx 1
noop
addx 5
addx -1
addx 5
addx 1
noop
noop
addx 2
addx 5
addx 2
addx 1
noop
addx -21
addx 26
addx -6
addx 8
noop
noop
addx 7
noop
noop
noop
addx -37
addx 13
addx -6
addx -2
addx 5
addx 25
addx 2
addx -24
addx 2
addx 5
addx 5
noop
noop
addx -2
addx 2
addx 5
addx 2
addx 7
addx -2
noop
addx -8
addx 9
addx -36
noop
noop
addx 5
addx 6
noop
addx 25
addx -24
addx 3
addx -2
noop
addx 3
addx 6
noop
addx 9
addx -8
addx 5
addx 2
addx -7
noop
addx 12
addx -10
addx 11
addx -38
addx 22
addx -15
addx -3
noop
addx 32
addx -25
addx -7
addx 11
addx 5
addx 10
addx -9
addx 17
addx -12
addx 2
noop
addx 2
addx -15
addx 22
noop
noop
noop
addx -35
addx 7
addx 21
addx -25
noop
addx 3
addx 2
noop
addx 7
noop
addx 3
noop
addx 2
addx 9
addx -4
addx -2
addx 5
addx 2
addx -2
noop
addx 7
addx 2
addx -39
addx 2
noop
addx 1
noop
addx 5
addx 24
addx -20
addx 1
addx 5
noop
noop
addx 4
noop
addx 1
noop
addx 4
addx 3
noop
addx 2
noop
noop
addx 1
addx 2
noop
addx 3
noop
noop

237
2022/day10/src/main.rs Normal file
View File

@ -0,0 +1,237 @@
use std::cmp;
#[derive(Debug)]
enum Instruction {
Addx(isize),
Noop,
}
use Instruction::*;
impl Instruction {
pub fn from_line(line: &str) -> Self {
let parts: Vec<&str> = line.split_ascii_whitespace().collect();
if parts.len() == 2 && parts[0] == "addx" {
let value = parts[1].parse::<isize>().unwrap();
return Addx(value);
}
Noop
}
}
// -----------------------------------------------------------------------------
#[derive(Debug)]
struct CPU {
x: isize,
}
impl CPU {
pub fn new() -> Self {
CPU { x: 1 }
}
fn noop(&self) -> usize {
1
}
fn add_x(&mut self, i: isize) -> usize {
self.x += i;
2
}
pub fn get_x(&self) -> isize {
self.x
}
pub fn run(&mut self, command: Instruction) -> usize {
match command {
Addx(i) => self.add_x(i),
Noop => self.noop(),
}
}
}
// -----------------------------------------------------------------------------
#[derive(Debug, Copy, Clone)]
enum Pixel {
Lit,
Dark,
}
use Pixel::*;
impl Default for Pixel {
fn default() -> Self {
Dark
}
}
// -----------------------------------------------------------------------------
#[derive(Debug)]
struct CRT {
pixels: [Pixel; 240],
}
impl CRT {
fn new() -> Self {
Self {
pixels: [Dark; 240],
}
}
fn get_lines(&self) -> Vec<String> {
self.pixels
.map(|p| match p {
Lit => '#',
Dark => '.',
})
.chunks(40)
.map(|c| String::from_iter(c))
.collect()
}
pub fn draw_pixel(&mut self, cycle: usize, x: isize) {
let line_x = x % 40;
let line_cycle = (cycle - 1) % 40;
let sprite_s = cmp::max(line_x - 1, 0);
let sprite_e = cmp::min(line_x + 1, 39);
let sprite: Vec<usize> = ((sprite_s as usize)..=(sprite_e as usize)).collect();
if cycle == 2 {
println!(
"Pixel {}, Sprite {:#?}, Line cycle: {}",
cycle - 1,
sprite,
line_cycle
);
}
if sprite.contains(&(line_cycle)) {
self.pixels[cycle - 1] = Lit;
}
}
}
// -----------------------------------------------------------------------------
#[derive(Debug)]
struct CycleCounter {
cpu: CPU,
crt: CRT,
log: Vec<isize>,
cycle: usize,
}
impl CycleCounter {
pub fn new() -> Self {
let mut cc = Self {
cpu: CPU::new(),
crt: CRT::new(),
log: vec![1, 1],
cycle: 1,
};
// Do first cycle
cc.crt.draw_pixel(cc.cycle, cc.cpu.get_x());
cc
}
fn run_line(&mut self, line: &str) {
let x = self.cpu.get_x();
let cycles = self.cpu.run(Instruction::from_line(line));
for _ in 0..(cycles - 1) {
self.add_cycle(x);
}
self.add_cycle(self.cpu.get_x());
}
fn add_cycle(&mut self, x: isize) {
self.cycle += 1;
self.crt.draw_pixel(self.cycle, x);
self.log.push(x);
}
pub fn display(&self) {
for line in self.crt.get_lines() {
println!("{}", line);
}
}
pub fn get_signal_strength(&self, cycle: usize) -> usize {
let x = self.log.get(cycle).unwrap();
(*x as usize) * cycle
}
}
// -----------------------------------------------------------------------------
fn main() {
let file_str = include_str!("input.txt");
let mut cc = CycleCounter::new();
file_str.lines().for_each(|line| cc.run_line(line));
let sum: usize = [20usize, 60, 100, 140, 180, 220]
.into_iter()
.map(|n| cc.get_signal_strength(n))
.sum();
println!("Part 1: sum of signal strength: {}", sum);
println!("Part 2: display output");
cc.display();
}
#[cfg(test)]
mod tests {
use super::*;
fn get_test_data() -> &'static str {
include_str!("test-input.txt")
}
#[test]
fn test_get_signal_strength() {
let mut cc = CycleCounter::new();
get_test_data().lines().for_each(|line| cc.run_line(line));
assert_eq!(cc.get_signal_strength(20), 420);
assert_eq!(cc.get_signal_strength(60), 1140);
assert_eq!(cc.get_signal_strength(100), 1800);
assert_eq!(cc.get_signal_strength(140), 2940);
assert_eq!(cc.get_signal_strength(180), 2880);
assert_eq!(cc.get_signal_strength(220), 3960);
}
#[test]
fn test_crt_get_lines() {
let file_str = include_str!("test-input.txt");
let mut cc = CycleCounter::new();
file_str.lines().for_each(|line| cc.run_line(line));
let actual = cc.crt.get_lines();
let expected = vec![
"##..##..##..##..##..##..##..##..##..##..".to_string(),
"###...###...###...###...###...###...###.".to_string(),
"####....####....####....####....####....".to_string(),
"#####.....#####.....#####.....#####.....".to_string(),
"######......######......######......####".to_string(),
"#######.......#######.......#######.....".to_string(),
];
assert_eq!(actual, expected);
}
}

View File

@ -0,0 +1,146 @@
addx 15
addx -11
addx 6
addx -3
addx 5
addx -1
addx -8
addx 13
addx 4
noop
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx -35
addx 1
addx 24
addx -19
addx 1
addx 16
addx -11
noop
noop
addx 21
addx -15
noop
noop
addx -3
addx 9
addx 1
addx -3
addx 8
addx 1
addx 5
noop
noop
noop
noop
noop
addx -36
noop
addx 1
addx 7
noop
noop
noop
addx 2
addx 6
noop
noop
noop
noop
noop
addx 1
noop
noop
addx 7
addx 1
noop
addx -13
addx 13
addx 7
noop
addx 1
addx -33
noop
noop
noop
addx 2
noop
noop
noop
addx 8
noop
addx -1
addx 2
addx 1
noop
addx 17
addx -9
addx 1
addx 1
addx -3
addx 11
noop
noop
addx 1
noop
addx 1
noop
noop
addx -13
addx -19
addx 1
addx 3
addx 26
addx -30
addx 12
addx -1
addx 3
addx 1
noop
noop
noop
addx -9
addx 18
addx 1
addx 2
noop
noop
addx 9
noop
noop
noop
addx -1
addx 2
addx -37
addx 1
addx 3
noop
addx 15
addx -21
addx 22
addx -6
addx 1
noop
addx 2
addx 1
noop
addx -10
noop
noop
addx 20
addx 1
addx 2
addx 2
addx -6
addx -11
noop
noop
noop

6
2022/day11/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day11"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

306
2022/day11/README.md Normal file
View File

@ -0,0 +1,306 @@
# Day 11: Monkey in the Middle
## Part 1
As you finally start making your way upriver, you realize your pack is much lighter than you remember. Just then, one of the items from your pack goes flying overhead. Monkeys are playing Keep Away with your missing things!
To get your stuff back, you need to be able to predict where the monkeys will throw your items. After some careful observation, you realize the monkeys operate based on how worried you are about each item.
You take some notes (your puzzle input) on the items each monkey currently has, how worried you are about those items, and how the monkey makes decisions based on your worry level. For example:
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1
Each monkey has several attributes:
- Starting items lists your worry level for each item the monkey is currently holding in the order they will be inspected.
- Operation shows how your worry level changes as that monkey inspects an item. (An operation like new = old * 5 means that your worry level after the monkey inspected the item is five times whatever your worry level was before inspection.)
- Test shows how the monkey uses your worry level to decide where to throw an item next.
- If true shows what happens with an item if the Test was true.
- If false shows what happens with an item if the Test was false.
After each monkey inspects an item but before it tests your worry level, your relief that the monkey's inspection didn't damage the item causes your worry level to be divided by three and rounded down to the nearest integer.
The monkeys take turns inspecting and throwing items. On a single monkey's turn, it inspects and throws all of the items it is holding one at a time and in the order listed. Monkey 0 goes first, then monkey 1, and so on until each monkey has had one turn. The process of each monkey taking a single turn is called a round.
When a monkey throws an item to another monkey, the item goes on the end of the recipient monkey's list. A monkey that starts a round with no items could end up inspecting and throwing many items by the time its turn comes around. If a monkey is holding no items at the start of its turn, its turn ends.
In the above example, the first round proceeds as follows:
Monkey 0:
Monkey inspects an item with a worry level of 79.
Worry level is multiplied by 19 to 1501.
Monkey gets bored with item. Worry level is divided by 3 to 500.
Current worry level is not divisible by 23.
Item with worry level 500 is thrown to monkey 3.
Monkey inspects an item with a worry level of 98.
Worry level is multiplied by 19 to 1862.
Monkey gets bored with item. Worry level is divided by 3 to 620.
Current worry level is not divisible by 23.
Item with worry level 620 is thrown to monkey 3.
Monkey 1:
Monkey inspects an item with a worry level of 54.
Worry level increases by 6 to 60.
Monkey gets bored with item. Worry level is divided by 3 to 20.
Current worry level is not divisible by 19.
Item with worry level 20 is thrown to monkey 0.
Monkey inspects an item with a worry level of 65.
Worry level increases by 6 to 71.
Monkey gets bored with item. Worry level is divided by 3 to 23.
Current worry level is not divisible by 19.
Item with worry level 23 is thrown to monkey 0.
Monkey inspects an item with a worry level of 75.
Worry level increases by 6 to 81.
Monkey gets bored with item. Worry level is divided by 3 to 27.
Current worry level is not divisible by 19.
Item with worry level 27 is thrown to monkey 0.
Monkey inspects an item with a worry level of 74.
Worry level increases by 6 to 80.
Monkey gets bored with item. Worry level is divided by 3 to 26.
Current worry level is not divisible by 19.
Item with worry level 26 is thrown to monkey 0.
Monkey 2:
Monkey inspects an item with a worry level of 79.
Worry level is multiplied by itself to 6241.
Monkey gets bored with item. Worry level is divided by 3 to 2080.
Current worry level is divisible by 13.
Item with worry level 2080 is thrown to monkey 1.
Monkey inspects an item with a worry level of 60.
Worry level is multiplied by itself to 3600.
Monkey gets bored with item. Worry level is divided by 3 to 1200.
Current worry level is not divisible by 13.
Item with worry level 1200 is thrown to monkey 3.
Monkey inspects an item with a worry level of 97.
Worry level is multiplied by itself to 9409.
Monkey gets bored with item. Worry level is divided by 3 to 3136.
Current worry level is not divisible by 13.
Item with worry level 3136 is thrown to monkey 3.
Monkey 3:
Monkey inspects an item with a worry level of 74.
Worry level increases by 3 to 77.
Monkey gets bored with item. Worry level is divided by 3 to 25.
Current worry level is not divisible by 17.
Item with worry level 25 is thrown to monkey 1.
Monkey inspects an item with a worry level of 500.
Worry level increases by 3 to 503.
Monkey gets bored with item. Worry level is divided by 3 to 167.
Current worry level is not divisible by 17.
Item with worry level 167 is thrown to monkey 1.
Monkey inspects an item with a worry level of 620.
Worry level increases by 3 to 623.
Monkey gets bored with item. Worry level is divided by 3 to 207.
Current worry level is not divisible by 17.
Item with worry level 207 is thrown to monkey 1.
Monkey inspects an item with a worry level of 1200.
Worry level increases by 3 to 1203.
Monkey gets bored with item. Worry level is divided by 3 to 401.
Current worry level is not divisible by 17.
Item with worry level 401 is thrown to monkey 1.
Monkey inspects an item with a worry level of 3136.
Worry level increases by 3 to 3139.
Monkey gets bored with item. Worry level is divided by 3 to 1046.
Current worry level is not divisible by 17.
Item with worry level 1046 is thrown to monkey 1.
After round 1, the monkeys are holding items with these worry levels:
Monkey 0: 20, 23, 27, 26
Monkey 1: 2080, 25, 167, 207, 401, 1046
Monkey 2:
Monkey 3:
Monkeys 2 and 3 aren't holding any items at the end of the round; they both inspected items during the round and threw them all before the round ended.
This process continues for a few more rounds:
After round 2, the monkeys are holding items with these worry levels:
Monkey 0: 695, 10, 71, 135, 350
Monkey 1: 43, 49, 58, 55, 362
Monkey 2:
Monkey 3:
After round 3, the monkeys are holding items with these worry levels:
Monkey 0: 16, 18, 21, 20, 122
Monkey 1: 1468, 22, 150, 286, 739
Monkey 2:
Monkey 3:
After round 4, the monkeys are holding items with these worry levels:
Monkey 0: 491, 9, 52, 97, 248, 34
Monkey 1: 39, 45, 43, 258
Monkey 2:
Monkey 3:
After round 5, the monkeys are holding items with these worry levels:
Monkey 0: 15, 17, 16, 88, 1037
Monkey 1: 20, 110, 205, 524, 72
Monkey 2:
Monkey 3:
After round 6, the monkeys are holding items with these worry levels:
Monkey 0: 8, 70, 176, 26, 34
Monkey 1: 481, 32, 36, 186, 2190
Monkey 2:
Monkey 3:
After round 7, the monkeys are holding items with these worry levels:
Monkey 0: 162, 12, 14, 64, 732, 17
Monkey 1: 148, 372, 55, 72
Monkey 2:
Monkey 3:
After round 8, the monkeys are holding items with these worry levels:
Monkey 0: 51, 126, 20, 26, 136
Monkey 1: 343, 26, 30, 1546, 36
Monkey 2:
Monkey 3:
After round 9, the monkeys are holding items with these worry levels:
Monkey 0: 116, 10, 12, 517, 14
Monkey 1: 108, 267, 43, 55, 288
Monkey 2:
Monkey 3:
After round 10, the monkeys are holding items with these worry levels:
Monkey 0: 91, 16, 20, 98
Monkey 1: 481, 245, 22, 26, 1092, 30
Monkey 2:
Monkey 3:
...
After round 15, the monkeys are holding items with these worry levels:
Monkey 0: 83, 44, 8, 184, 9, 20, 26, 102
Monkey 1: 110, 36
Monkey 2:
Monkey 3:
...
After round 20, the monkeys are holding items with these worry levels:
Monkey 0: 10, 12, 14, 26, 34
Monkey 1: 245, 93, 53, 199, 115
Monkey 2:
Monkey 3:
Chasing all of the monkeys at once is impossible; you're going to have to focus on the **two most active** monkeys if you want any hope of getting your stuff back. Count the **total number of times each monkey inspects items** over 20 rounds:
Monkey 0 inspected items 101 times.
Monkey 1 inspected items 95 times.
Monkey 2 inspected items 7 times.
Monkey 3 inspected items 105 times.
In this example, the two most active monkeys inspected items 101 and 105 times. The level of **monkey business** in this situation can be found by multiplying these together: `10605`.
Figure out which monkeys to chase by counting how many items they inspect over 20 rounds. **What is the level of monkey business after 20 rounds of stuff-slinging simian shenanigans?**
## Part 2
You're worried you might not ever get your items back. So worried, in fact, that your relief that a monkey's inspection didn't damage an item no longer causes your worry level to be divided by three.
Unfortunately, that relief was all that was keeping your worry levels from reaching ridiculous levels. You'll need to find another way to keep your worry levels manageable.
At this rate, you might be putting up with these monkeys for a very long time - possibly 10000 rounds!
With these new rules, you can still figure out the monkey business after 10000 rounds. Using the same example above:
== After round 1 ==
Monkey 0 inspected items 2 times.
Monkey 1 inspected items 4 times.
Monkey 2 inspected items 3 times.
Monkey 3 inspected items 6 times.
== After round 20 ==
Monkey 0 inspected items 99 times.
Monkey 1 inspected items 97 times.
Monkey 2 inspected items 8 times.
Monkey 3 inspected items 103 times.
== After round 1000 ==
Monkey 0 inspected items 5204 times.
Monkey 1 inspected items 4792 times.
Monkey 2 inspected items 199 times.
Monkey 3 inspected items 5192 times.
== After round 2000 ==
Monkey 0 inspected items 10419 times.
Monkey 1 inspected items 9577 times.
Monkey 2 inspected items 392 times.
Monkey 3 inspected items 10391 times.
== After round 3000 ==
Monkey 0 inspected items 15638 times.
Monkey 1 inspected items 14358 times.
Monkey 2 inspected items 587 times.
Monkey 3 inspected items 15593 times.
== After round 4000 ==
Monkey 0 inspected items 20858 times.
Monkey 1 inspected items 19138 times.
Monkey 2 inspected items 780 times.
Monkey 3 inspected items 20797 times.
== After round 5000 ==
Monkey 0 inspected items 26075 times.
Monkey 1 inspected items 23921 times.
Monkey 2 inspected items 974 times.
Monkey 3 inspected items 26000 times.
== After round 6000 ==
Monkey 0 inspected items 31294 times.
Monkey 1 inspected items 28702 times.
Monkey 2 inspected items 1165 times.
Monkey 3 inspected items 31204 times.
== After round 7000 ==
Monkey 0 inspected items 36508 times.
Monkey 1 inspected items 33488 times.
Monkey 2 inspected items 1360 times.
Monkey 3 inspected items 36400 times.
== After round 8000 ==
Monkey 0 inspected items 41728 times.
Monkey 1 inspected items 38268 times.
Monkey 2 inspected items 1553 times.
Monkey 3 inspected items 41606 times.
== After round 9000 ==
Monkey 0 inspected items 46945 times.
Monkey 1 inspected items 43051 times.
Monkey 2 inspected items 1746 times.
Monkey 3 inspected items 46807 times.
== After round 10000 ==
Monkey 0 inspected items 52166 times.
Monkey 1 inspected items 47830 times.
Monkey 2 inspected items 1938 times.
Monkey 3 inspected items 52013 times.
After 10000 rounds, the two most active monkeys inspected items 52166 and 52013 times. Multiplying these together, the level of monkey business in this situation is now 2713310158.
Worry levels are no longer divided by three after each item is inspected; you'll need to find another way to keep your worry levels manageable. Starting again from the initial state in your puzzle input, **what is the level of monkey business after 10000 rounds?**

55
2022/day11/src/input.txt Normal file
View File

@ -0,0 +1,55 @@
Monkey 0:
Starting items: 57
Operation: new = old * 13
Test: divisible by 11
If true: throw to monkey 3
If false: throw to monkey 2
Monkey 1:
Starting items: 58, 93, 88, 81, 72, 73, 65
Operation: new = old + 2
Test: divisible by 7
If true: throw to monkey 6
If false: throw to monkey 7
Monkey 2:
Starting items: 65, 95
Operation: new = old + 6
Test: divisible by 13
If true: throw to monkey 3
If false: throw to monkey 5
Monkey 3:
Starting items: 58, 80, 81, 83
Operation: new = old * old
Test: divisible by 5
If true: throw to monkey 4
If false: throw to monkey 5
Monkey 4:
Starting items: 58, 89, 90, 96, 55
Operation: new = old + 3
Test: divisible by 3
If true: throw to monkey 1
If false: throw to monkey 7
Monkey 5:
Starting items: 66, 73, 87, 58, 62, 67
Operation: new = old * 7
Test: divisible by 17
If true: throw to monkey 4
If false: throw to monkey 1
Monkey 6:
Starting items: 85, 55, 89
Operation: new = old + 4
Test: divisible by 2
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 7:
Starting items: 73, 80, 54, 94, 90, 52, 69, 58
Operation: new = old + 7
Test: divisible by 19
If true: throw to monkey 6
If false: throw to monkey 0

272
2022/day11/src/main.rs Normal file
View File

@ -0,0 +1,272 @@
use std::collections::VecDeque;
use std::str::FromStr;
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum WorryType {
Normal,
Extra,
}
#[derive(Debug, PartialEq, Copy, Clone)]
enum Operand {
Old,
Literal(usize),
}
#[derive(Debug)]
struct Operation {
operator: char,
operand: Operand,
}
impl Operation {
fn new(operator: char, operand: &str) -> Self {
let operand = match operand {
"old" => Operand::Old,
_ => Operand::Literal(usize::from_str(operand).unwrap()),
};
Operation { operator, operand }
}
#[inline(always)]
fn run(&self, old: usize) -> usize {
let operand = self.operand;
if operand == Operand::Old && self.operator == '*' {
return old * old;
}
let other = match operand {
Operand::Old => old,
Operand::Literal(other) => other,
};
match self.operator {
'+' => old + other,
'*' => old * other,
_ => panic!("Invalid operator"),
}
}
}
#[derive(Debug)]
pub struct Monkey {
items: VecDeque<usize>,
operation: Operation,
test: usize,
pass_monkey: usize,
fail_monkey: usize,
inspection_count: usize,
inspection_worry: WorryType,
}
impl Monkey {
pub fn from_behavior(raw: &str, inspection_worry: WorryType) -> Self {
let lines: Vec<&str> = raw.lines().collect();
let item_parts: Vec<&str> = lines[1].split(": ").collect();
let items: VecDeque<usize> = item_parts[1]
.split(", ")
.map(|i| i.parse::<usize>().unwrap())
.collect();
let op_parts: Vec<&str> = lines[2].split(" = ").collect();
let [_, operator, operand]: [&str; 3] = op_parts[1]
.split_ascii_whitespace()
.collect::<Vec<&str>>()
.try_into()
.unwrap();
let [test, pass_monkey, fail_monkey]: [usize; 3] = lines[3..]
.iter()
.map(|line| line.split_ascii_whitespace().collect::<Vec<&str>>())
.map(|parts| parts[parts.len() - 1])
.map(|n| n.parse::<usize>().unwrap())
.collect::<Vec<usize>>()
.try_into()
.unwrap();
Monkey {
items,
operation: Operation::new(operator.chars().next().unwrap(), operand),
test,
pass_monkey,
fail_monkey,
inspection_count: 0,
inspection_worry,
}
}
#[inline(always)]
fn run_test(&self, item: &usize) -> usize {
if item % self.test == 0 {
self.pass_monkey
} else {
self.fail_monkey
}
}
#[inline(always)]
pub fn inspect(&mut self, mut item: usize, divisor_product: usize) -> (usize, usize) {
self.inspection_count += 1;
let worry = if self.inspection_worry == WorryType::Normal {
self.operation.run(item) / 3
} else {
// This is the whole key to keeping the number small enough to be practical.
// I don't really understand it, but I was sick of this not being finished,
// so I based the fix on
// https://fasterthanli.me/series/advent-of-code-2022/part-11
item %= divisor_product;
self.operation.run(item)
};
let new_monkey = self.run_test(&worry);
(new_monkey, worry)
}
#[inline(always)]
pub fn catch(&mut self, item: usize) {
self.items.push_back(item);
}
}
#[derive(Debug)]
pub struct MonkeyGame {
monkeys: Vec<Monkey>,
divisor_product: usize,
}
impl MonkeyGame {
pub fn from_file_str(file_str: &'static str, inspection_worry: WorryType) -> Self {
let behaviors = file_str.split("\n\n");
let monkeys: Vec<Monkey> = behaviors
.map(|m| Monkey::from_behavior(m, inspection_worry))
.collect();
// The magic divisor for getting the result with normal integer sizes
let divisor_product = monkeys.iter().map(|m| m.test).product::<usize>();
Self {
monkeys,
divisor_product,
}
}
fn throw(&mut self, item: usize, to: usize) {
self.monkeys[to].catch(item);
}
#[inline(always)]
pub fn do_rounds(&mut self, rounds: usize) -> &Self {
for r in 0..rounds {
if r % 100 == 0 {
println!("Running round {}", r);
}
for m in 0..self.monkeys.len() {
while let Some(worry) = self.monkeys[m].items.pop_front() {
let (monkey_idx, worry) = self.monkeys[m].inspect(worry, self.divisor_product);
self.throw(worry, monkey_idx);
}
}
}
self
}
pub fn get_inspection_counts(&self) -> Vec<usize> {
let mut counts: Vec<usize> = self
.monkeys
.iter()
.map(|m| m.inspection_count.clone())
.collect();
counts.sort();
counts.into_iter().rev().collect()
}
pub fn get_monkey_business(&self) -> usize {
let inspections = self.get_inspection_counts();
inspections.get(0).unwrap() * inspections.get(1).unwrap()
}
}
fn main() {
let file_str = include_str!("input.txt");
let monkey_business1 = MonkeyGame::from_file_str(file_str, WorryType::Normal)
.do_rounds(20)
.get_monkey_business();
println!("Part 1 monkey business: {}", monkey_business1);
let monkey_business2 = MonkeyGame::from_file_str(file_str, WorryType::Extra)
.do_rounds(10_000)
.get_monkey_business();
println!("Part 2 monkey business: {}", monkey_business2);
}
#[cfg(test)]
mod tests {
use super::*;
fn get_test_data() -> &'static str {
include_str!("test-input.txt")
}
#[test]
fn monkey_round() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal);
game.do_rounds(1);
assert_eq!(game.monkeys[0].items, VecDeque::from([20, 23, 27, 26]));
assert_eq!(
game.monkeys[1].items,
VecDeque::from([2080, 25, 167, 207, 401, 1046])
);
assert_eq!(game.monkeys[2].items, VecDeque::new());
assert_eq!(game.monkeys[3].items, VecDeque::new());
}
#[test]
fn monkey_20_rounds() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Normal);
game.do_rounds(20);
assert_eq!(game.monkeys[0].inspection_count, 101);
assert_eq!(game.monkeys[3].inspection_count, 105);
assert_eq!(game.get_monkey_business(), 10605);
}
#[test]
fn monkey_20_rounds_extra_worry() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(20);
assert_eq!(game.monkeys[0].inspection_count, 99);
assert_eq!(game.monkeys[3].inspection_count, 103);
assert_eq!(game.get_monkey_business(), 10197);
}
#[test]
fn monkey_1000_rounds_extra_worry() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(1000);
assert_eq!(game.monkeys[0].inspection_count, 5204);
assert_eq!(game.monkeys[3].inspection_count, 5192);
}
#[test]
fn monkey_10_000_rounds_extra_worry() {
let mut game = MonkeyGame::from_file_str(get_test_data(), WorryType::Extra);
game.do_rounds(10_000);
assert_eq!(game.monkeys[0].inspection_count, 52166);
assert_eq!(game.monkeys[3].inspection_count, 52013);
assert_eq!(game.get_monkey_business(), 2713310158);
}
}

View File

@ -0,0 +1,27 @@
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1

9
2022/day12/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "day12"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aoc-shared = { path = "../aoc-shared"}

33
2022/day12/README.md Normal file
View File

@ -0,0 +1,33 @@
# Day 12: Hill Climbing Algorithm
## Part 1
You try contacting the Elves using your handheld device, but the river you're following must be too low to get a decent signal.
You ask the device for a heightmap of the surrounding area (your puzzle input). The heightmap shows the local area from above broken into a grid; the elevation of each square of the grid is given by a single lowercase letter, where a is the lowest elevation, b is the next-lowest, and so on up to the highest elevation, z.
Also included on the heightmap are marks for your current position (S) and the location that should get the best signal (E). Your current position (S) has elevation a, and the location that should get the best signal (E) has elevation z.
You'd like to reach E, but to save energy, you should do it in as few steps as possible. During each step, you can move exactly one square up, down, left, or right. To avoid needing to get out your climbing gear, the elevation of the destination square can be at most one higher than the elevation of your current square; that is, if your current elevation is m, you could step to elevation n, but not to elevation o. (This also means that the elevation of the destination square can be much lower than the elevation of your current square.)
For example:
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi
Here, you start in the top-left corner; your goal is near the middle. You could start by moving down or right, but eventually you'll need to head toward the e at the bottom. From there, you can spiral around to the goal:
v..v<<<<
>v.vv<<^
.>vv>E^^
..v>>>^^
..>>>>>^
In the above diagram, the symbols indicate whether the path exits each square moving up (^), down (v), left (<), or right (>). The location that should get the best signal is still E, and . marks unvisited squares.
This path reaches the goal in 31 steps, the fewest possible.
**What is the fewest steps required to move from your current position to the location that should get the best signal?**

41
2022/day12/src/input.txt Normal file
View File

@ -0,0 +1,41 @@
abccccccccccccccccaaccccccccccccccccccccaaaaaaaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa
abcccccccccccccaaaaaccccccccccccccccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaa
abccccccccccccccaaaaaccccccccccccccaaaaacccaaaaaacccccaaccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaa
abccccccccccccccaaaaacccccccccaacccaaaaacccaaaaaaaccccaaaacaacaaccccccccccccccccccccccccaaaccccaaaccccccccccccaaaa
abcccccccccccccaaaaacccccccaaaaaccaaaaaacccaaaaaaaacaaaaaacaaaaaccccccccccccccccccccccccaaacccaaaaccccccccccccaaac
abccccccaacaaaccccaaccccccccaaaaacaaaaaaccaaaacaaaacaaaaaccaaaaaaccccccccccccccccccccccccaaaaaaaacccccccccccccaacc
abccccccaaaaaaccccccccccccccaaaaacaaaaaaccaaaaccaaaacaaaaacaaaaaacccccccccccccccccccccccaaaaaaaaaccccccccccccccccc
abccccccaaaaaacccccccccccccaaaaaccccaaccccaacccccaaccaacaacaaaaaccccccccccccccccccccccccccaaakkkkllllcccaaaccccccc
abccccccaaaaaaacccccccccccccccaaccccaacccccccccccccccccccccccaaaccccccaaaacccccccccjjjjkkkkkkkkkkllllccccaacaccccc
abcccccaaaaaaaacccccaaccccccccccccccaaaaaaccccccccccccccccccaaccccccccaaaaccccccccjjjjjkkkkkkkkkppllllcccaaaaacccc
abcccccaaaaaaaaccaaaacccccccccccccccaaaaaccccccccccccccccaacaaccccccccaaaacccccccjjjjjjjkkkkkppppppplllccaaaaacccc
abccccccccaaaccccaaaaaacccccccccccaaaaaaaccccccccccccccccaaaaacccccccccaacccccccjjjjoooooooppppppppplllcccaaaccccc
abccccccccaaccccccaaaaaccccaacccccaaaaaaaaccccaaacccccccccaaaaaaacccccccccccccccjjjooooooooppppuuppppllcccaaaccccc
abccccccaacccccccaaaaacccccaaaccaaaaaaaaaaccaaaaaaccccccaaaaaaaaaacaaaccccccccccjjjoooouuuoopuuuuupppllcccaaaccccc
abacccccaaccccccccccaacccccaaaaaaaccaaaaaaccaaaaaaccccccaaaaaccaaaaaaaccccaaccccjjoootuuuuuuuuuuuuvpqlllcccccccccc
abaccaaaaaaaacccccccccccccccaaaaaaccaacccccccaaaaacccccccacaaaccaaaaaaccaaaacaccjjooottuuuuuuuxyuvvqqljjccddcccccc
abcccaaaaaaaaccccccccccccaaaaaaaaacaacaaccccaaaaaccccccccccaaaaaaaaaacccaaaaaacciijootttxxxuuxyyyvvqqjjjjdddcccccc
abcccccaaaaccccaaacccccccaaaaaaaaacaaaaaccccaaaaaccccccccccccaaaaaaaaacccaaaaccciiinntttxxxxxxyyvvqqqqjjjddddccccc
abccccaaaaaccccaaaaacccccaaaaaaaaaaaaaaaaccccccccccccccccccccaaaaaaaaaaccaaaaccciiinntttxxxxxxyyvvvqqqqjjjdddccccc
abccccaaaaaaccaaaaaccccccccaaaaaaaaaaaaaacccccccccccccccccccccccaaacaaacaacaaccciiinnnttxxxxxyyyvvvvqqqqjjjdddcccc
SbccccaaccaaccaaaaacccccccccaaaaaaaaaaaaacccccccccccccccccccccccaaacccccccccccciiinnntttxxxEzzyyyyvvvqqqjjjdddcccc
abcccccccccccccaaaaacccccccaaaaaaaaacaaaccccccccccccccccccccccccaaccccccccccccciiinnnttxxxxyyyyyyyyvvvqqqjjjdddccc
abcccccccccccccaaccccccccccaaaaaaaaccccccccccccccccccccccccccccccccccccccccccciiinnntttxxyyyyyyyyyvvvvqqqjjjdddccc
abccccccccccccccccccccccccaaaaaaaacccccccccccccccccccccccccccccccccccccccccccciiinntttxxxwwwyyywwvvvvrqqjjjjdddccc
abcccccccccccccccccccccccccccaaaaaaccccccccccccccccccccccccccccccccccccccccccciinnntttxwwwwwyyywwvvvrrrqkkkeddcccc
abcccccccccccccccccccccccccccaaaaaaccccccccccccccccccccccccccccccccccccccccccchhnnntttsswwswwyywwrrrrrrkkkkeeecccc
abcccccccccccccccccccccccccccaaaaaacccccccccccccccccccaccccccccccccaaacccccccchhhnmmssssssswwwwwwrrrkkkkkeeeeecccc
abcccccccccccccccccccccccccccccaaacccccccccccccccccccaaccccccccccaaaaaacccccaahhhmmmmmsssssswwwwrrrkkkkkeeeeeccccc
abaacccccccccccccaccccccccccccccccccccccccccccccccaaaaacaacccccccaaaaaacaaaaaahhhhmmmmmmmmssswwwrrkkkkeeeeeacccccc
abacccccccccccccaaaaaaaaccccccccaaacccccccaaccccccaaaaaaaacccccccaaaaaacaaaaaaahhhhmmmmmmmmsssrrrrkkkeeeeeaacccccc
abaaaccccaaccccccaaaaaacccccccccaaacccaacaaaccccccccaaaacccccccccaaaaacccaaaaaaahhhhhhhmmmmlsssrrllkfeeeeaaaaacccc
abaaaccaaaaccccccaaaaaacccccccccaaaaaaaaaaaaaacccccaaaaacccccccccaaaaacccaaaaaaachhhhhgggmllsssrrllkffeaaaaaaacccc
abaacccaaaaaacccaaaaaaaacccccaaaaaaaaaaaaaaaaacccccaacaaacccccccccccccccaaaaaacccccchggggglllllllllfffaaaaaaaacccc
abaaccccaaaacccaaaaaaaaaaccccaaaaaaaaacaaaaaaaccaccaccaaacccccccccccccccaaaaaacccccccccgggglllllllffffaaaaaacccccc
abcccccaaaaacccaaaaaaaaaacccccaaaaaaaccaaaaacccaaaccccccccccccccccccccccccccaacccccccccagggglllllffffccccaaacccccc
abcccccaacaaccccccaaaaacaccaacccaaaaaaaaaaaaaccaaacccccccccccccccccccccccccccccccccccccaagggggffffffcccccccccccccc
abcccccccccccaaaaaaaaacccccaaccaaaaaaaccaaaaacaaaaccccccccccccccccccccccccccccccccccccaaaacgggfffffccccccccccccccc
abcccccccccccaaaaacaacccaaaaaaaaaaccaacccaaaaaaaacccaaccccccccccccccccccccccccccccccccccccccggfffccccccccccccaaaca
abccccccccccaaaaaaccccccaaaaaaaaacccccccccaaaaaaaaaaaacccccccccccccaaaccccccccccccccccccccccaaaccccccccccccccaaaaa
abccccccccccaaaaaaccccccccaaaacccccccccccccaaaaaaaaaaaaccccccccccccaaaaccccccccccccccccccccccaaaccccccccccccccaaaa
abcccccccccccaaaaacccccccaaaaaaccccccccccaaaaaaaaaaaaaaccccccccccccaaaaccccccccccccccccccccccccccccccccccccccaaaaa

287
2022/day12/src/lib.rs Normal file
View File

@ -0,0 +1,287 @@
mod node;
use core::fmt;
use node::Node;
use aoc_shared::enums::Direction;
use aoc_shared::grid::Grid as BaseGrid;
use aoc_shared::impl_grid_newtype;
#[derive(Debug, Copy, Clone, PartialEq)]
enum CellType {
Start,
End,
Waypoint(u8),
}
#[derive(Debug, Clone)]
struct Cell {
kind: CellType,
idx: usize,
coord: (usize, usize),
}
impl Cell {
pub fn new(kind: CellType, idx: usize, coord: (usize, usize)) -> Self {
Cell { kind, idx, coord }
}
pub fn get_height(&self) -> u8 {
match self.kind {
CellType::Start => 0,
CellType::End => 25,
CellType::Waypoint(c) => c,
}
}
}
// ----------------------------------------------------------------------------
pub struct Grid<T>(BaseGrid<T>);
impl_grid_newtype!(Grid, BaseGrid<Cell>, Cell);
impl Grid<Cell> {
pub fn from_file_str(file_str: &str) -> Self {
let first_line = file_str.lines().next().unwrap();
let width = first_line.len();
let mut grid = Grid::new(width);
let mut idx = 0usize;
for c in file_str.chars() {
let kind = match c {
'S' => CellType::Start,
'E' => CellType::End,
'a'..='z' => CellType::Waypoint(c as u8 - b'a'),
'\r' | '\n' => continue,
_ => panic!("Invalid character: {c}"),
};
let (x, y) = (idx % width, idx / width);
let cell = Cell::new(kind, idx, (x, y));
grid.vec.push(cell);
idx += 1;
}
grid
}
fn find_pos(&self, value: CellType) -> Option<usize> {
self.vec.iter().position(|item| item.kind == value)
}
pub fn print(&self) {
for r in 0usize..self.num_rows() {
let range = self.row_first_idx(r)..=self.row_last_idx(r);
let line: String = self.vec[range]
.iter()
.map(|n| (n.get_height() + b'a') as char)
.collect();
println!("{}", line);
}
}
fn get_index_for_move(&self, from: usize, dir: Direction) -> Option<usize> {
let (mut x, mut y) = self.idx_xy(from);
match dir {
Direction::Up => {
if y >= 1 {
y -= 1;
} else {
return None;
}
}
Direction::Down => {
if y < self.num_rows() - 1 {
y += 1;
} else {
return None;
}
}
Direction::Left => {
if x >= 1 {
x -= 1;
} else {
return None;
}
}
Direction::Right => {
if x < self.num_cols() - 1 {
x += 1;
} else {
return None;
}
}
};
Some(self.xy_idx(x, y))
}
fn is_valid_move(&self, start: usize, end: usize) -> bool {
// Is the item within the grid?
let start_char = self.get(start);
let end_char = self.get(end);
if start_char.is_none() || end_char.is_none() {
return false;
}
let start_char = start_char.unwrap();
let end_char = end_char.unwrap();
let start_elevation = start_char.get_height();
let end_elevation = end_char.get_height();
if (end_elevation < start_elevation) || end_elevation.abs_diff(start_elevation) > 1 {
return false;
}
let ((start_x, start_y), (end_x, end_y)) = (start_char.coord, end_char.coord);
let x_diff = end_x.abs_diff(start_x);
let y_diff = end_y.abs_diff(start_y);
// Have we moved 0 or 1 in a cardinal direction?
matches!((x_diff, y_diff), (0, 0) | (0, 1) | (1, 0))
}
fn find_moves(&self, start: usize) -> Vec<usize> {
[
Direction::Up,
Direction::Down,
Direction::Left,
Direction::Right,
]
.into_iter()
.filter_map(|d| self.get_index_for_move(start, d))
.collect()
}
fn find_valid_moves(&self, start: usize) -> Vec<usize> {
self.find_moves(start)
.into_iter()
.filter(|m| self.is_valid_move(start, *m))
.collect()
}
fn has_valid_neighbor(&self, idx: usize) -> bool {
!self.find_valid_moves(idx).is_empty()
}
}
impl fmt::Debug for Grid<Cell> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for r in 0usize..self.num_rows() {
let range = self.row_first_idx(r)..=self.row_last_idx(r);
let line: String = self.vec[range]
.iter()
.map(|n| (n.get_height() + b'a') as char)
.collect();
writeln!(f, "{}", line)?;
}
Ok(())
}
}
// ----------------------------------------------------------------------------
#[derive(Debug)]
pub struct Pathfinder {
start_idx: usize,
end_idx: usize,
grid: Grid<Cell>,
tree: Node,
}
impl Pathfinder {
pub fn from_file_str(file_str: &str) -> Self {
let mut pf = Pathfinder {
start_idx: 0,
end_idx: 0,
grid: Grid::from_file_str(file_str),
tree: Node::default(),
};
let start = pf.grid.find_pos(CellType::Start).unwrap();
let end = pf.grid.find_pos(CellType::End).unwrap();
pf.start_idx = start;
pf.end_idx = end;
pf.tree.idx = start;
pf
}
fn add_children(&mut self, node: &mut Node, idx: usize) {
let possible_moves = self.grid.find_valid_moves(idx);
if possible_moves.is_empty() {
return;
}
for m in possible_moves {
if node.contains(m) {
continue;
}
let n = node.add_child(m);
if m != self.end_idx {
self.add_children(n, m);
} else {
break;
}
}
}
fn build_tree(&mut self) {
let mut tree = { self.tree.clone() };
let idx = { self.start_idx };
self.add_children(&mut tree, idx);
self.tree = tree;
}
fn get_paths(&self) -> impl Iterator<Item = &Node> {
self.tree
.get_leaves()
.into_iter()
.filter(|n| n.idx == self.end_idx)
}
pub fn find_shortest_path(&mut self) -> &Node {
self.build_tree();
self.get_paths()
.min_by(|a, b| a.get_len().cmp(&b.get_len()))
.unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn get_test_data() -> &'static str {
include_str!("test-input.txt")
}
fn get_finder() -> Pathfinder {
Pathfinder::from_file_str(get_test_data())
}
#[test]
fn find_valid_moves() {
let finder = get_finder();
assert_eq!(finder.grid.find_valid_moves(finder.start_idx), vec![8, 1]);
assert_eq!(finder.grid.find_valid_moves(8), vec![0, 16, 9]);
}
#[test]
fn find_shortest_path() {
let mut finder = get_finder();
let shortest = finder.find_shortest_path();
assert_eq!(shortest.get_len(), 31);
}
}

7
2022/day12/src/main.rs Normal file
View File

@ -0,0 +1,7 @@
fn main() {
let file_str = include_str!("input.txt");
let mut finder = ::day12::Pathfinder::from_file_str(file_str);
let shortest_path = finder.find_shortest_path();
println!("Part 1: Fewest steps: {}", shortest_path.get_len());
}

64
2022/day12/src/node.rs Normal file
View File

@ -0,0 +1,64 @@
#[derive(Debug, Default, Clone)]
pub struct Node {
pub idx: usize,
pub parents: Vec<usize>,
pub children: Vec<Node>,
}
impl Node {
pub fn new(idx: usize) -> Self {
Node {
idx,
..Node::default()
}
}
pub fn add_child(&mut self, value: usize) -> &mut Self {
let mut child = Node::new(value);
child.parents.append(&mut self.parents.clone());
child.parents.push(self.idx);
self.append(child);
self.children.last_mut().unwrap()
}
fn append(&mut self, node: Node) -> &mut Self {
self.children.push(node);
self
}
fn is_leaf(&self) -> bool {
self.children.is_empty()
}
pub fn contains(&self, value: usize) -> bool {
if self.idx == value {
return true;
}
self.parents.contains(&value)
}
pub fn get_leaves(&self) -> Vec<&Node> {
if self.is_leaf() {
return vec![self];
}
let mut leaves = Vec::new();
let children = self.children.iter();
for child in children {
let mut child_leaves = child.get_leaves();
leaves.append(&mut child_leaves);
}
leaves
}
pub fn get_len(&self) -> usize {
self.parents.len()
}
}

View File

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

8
2022/day2/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day2"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

45
2022/day2/README.md Normal file
View File

@ -0,0 +1,45 @@
# Day 2
## Part 1
The Elves begin to set up camp on the beach. To decide whose tent gets to be closest to the snack storage, a giant Rock Paper Scissors tournament is already in progress.
Rock Paper Scissors is a game between two players. Each game contains many rounds; in each round, the players each simultaneously choose one of Rock, Paper, or Scissors using a hand shape. Then, a winner for that round is selected: Rock defeats Scissors, Scissors defeats Paper, and Paper defeats Rock. If both players choose the same shape, the round instead ends in a draw.
Appreciative of your help yesterday, one Elf gives you an encrypted strategy guide (your puzzle input) that they say will be sure to help you win. "The first column is what your opponent is going to play: A for Rock, B for Paper, and C for Scissors. The second column--" Suddenly, the Elf is called away to help with someone's tent.
The second column, you reason, must be what you should play in response: X for Rock, Y for Paper, and Z for Scissors. Winning every time would be suspicious, so the responses must have been carefully chosen.
The winner of the whole tournament is the player with the highest score. Your total score is the sum of your scores for each round. The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round (0 if you lost, 3 if the round was a draw, and 6 if you won).
Since you can't be sure if the Elf is trying to help you or trick you, you should calculate the score you would get if you were to follow the strategy guide.
For example, suppose you were given the following strategy guide:
A Y
B X
C Z
This strategy guide predicts and recommends the following:
In the first round, your opponent will choose Rock (A), and you should choose Paper (Y). This ends in a win for you with a score of 8 (2 because you chose Paper + 6 because you won).
In the second round, your opponent will choose Paper (B), and you should choose Rock (X). This ends in a loss for you with a score of 1 (1 + 0).
The third round is a draw with both players choosing Scissors, giving you a score of 3 + 3 = 6.
In this example, if you were to follow the strategy guide, you would get a total score of 15 (8 + 1 + 6).
**What would your total score be if everything goes exactly according to your strategy guide?**
## Part 2
The Elf finishes helping with the tent and sneaks back over to you. "Anyway, the second column says how the round needs to end: X means you need to lose, Y means you need to end the round in a draw, and Z means you need to win. Good luck!"
The total score is still calculated in the same way, but now you need to figure out what shape to choose so the round ends as indicated. The example above now goes like this:
In the first round, your opponent will choose Rock (A), and you need the round to end in a draw (Y), so you also choose Rock. This gives you a score of 1 + 3 = 4.
In the second round, your opponent will choose Paper (B), and you choose Rock so you lose (X) with a score of 1 + 0 = 1.
In the third round, you will defeat your opponent's Scissors with Rock for a score of 1 + 6 = 7.
Now that you're correctly decrypting the ultra top secret strategy guide, you would get a total score of 12.
Following the Elf's instructions for the second column, **what would your total score be if everything goes exactly according to your strategy guide?**

2500
2022/day2/src/input.txt Normal file

File diff suppressed because it is too large Load Diff

146
2022/day2/src/main.rs Normal file
View File

@ -0,0 +1,146 @@
#[derive(Debug, Copy, Clone)]
enum Calculation {
ByMove,
ByOutcome,
}
use Calculation::*;
// ----------------------------------------------------------------------------
#[derive(Debug, Copy, Clone)]
enum Outcome {
Win,
Draw,
Lose,
}
use Outcome::*;
impl From<char> for Outcome {
fn from(c: char) -> Self {
match c {
'X' => Lose,
'Y' => Draw,
'Z' => Win,
_ => panic!("Invalid char: {}", c),
}
}
}
impl Outcome {
fn get_score(self) -> u32 {
match self {
Lose => 0,
Draw => 3,
Win => 6,
}
}
}
// ----------------------------------------------------------------------------
#[derive(Debug, Copy, Clone)]
enum Shape {
Rock,
Paper,
Scissors,
}
use Shape::*;
impl From<char> for Shape {
fn from(c: char) -> Self {
match c {
'A' | 'X' => Rock,
'B' | 'Y' => Paper,
'C' | 'Z' => Scissors,
_ => panic!("Invalid char: {}", c),
}
}
}
impl Shape {
fn get_score(self) -> u32 {
match self {
Rock => 1,
Paper => 2,
Scissors => 3,
}
}
fn get_outcome(self, outcome: char) -> Shape {
let outcome = Outcome::from(outcome);
match self {
Rock => match outcome {
Win => Paper,
Draw => Rock,
Lose => Scissors,
},
Paper => match outcome {
Win => Scissors,
Draw => Paper,
Lose => Rock,
},
Scissors => match outcome {
Win => Rock,
Draw => Scissors,
Lose => Paper,
},
}
}
}
// ----------------------------------------------------------------------------
fn get_outcome_score(them: Shape, you: Shape) -> u32 {
match (them, you) {
(Rock, Scissors) | (Paper, Rock) | (Scissors, Paper) => Lose,
(Rock, Rock) | (Paper, Paper) | (Scissors, Scissors) => Draw,
(Rock, Paper) | (Paper, Scissors) | (Scissors, Rock) => Win,
}
.get_score()
}
fn get_round_score(them: char, you: char, score_type: Calculation) -> u32 {
let them = Shape::from(them);
let you = match score_type {
ByMove => Shape::from(you),
ByOutcome => them.get_outcome(you),
};
let shape_score = you.get_score();
let outcome_score = get_outcome_score(them, you);
shape_score + outcome_score
}
fn get_scores(lines: Vec<&str>, score_type: Calculation) -> Vec<u32> {
lines
.into_iter()
.map(|line| {
// This is trying to be too clever
let [them, _, you]: [char; 3] = line.chars().collect::<Vec<char>>().try_into().unwrap();
get_round_score(them, you, score_type)
})
.collect()
}
fn get_total(lines: &Vec<&str>, score_type: Calculation) -> u32 {
get_scores(lines.clone(), score_type)
.into_iter()
.reduce(|accum, item| accum + item)
.unwrap()
}
fn main() {
let file_str = include_str!("input.txt");
let lines: Vec<&str> = file_str.lines().collect();
let part1_total = get_total(&lines, ByMove);
let part2_total = get_total(&lines, ByOutcome);
println!("Part 1: Final score: {}", part1_total);
println!("Part 2: Final score: {}", part2_total);
}

8
2022/day3/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day3"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

66
2022/day3/README.md Normal file
View File

@ -0,0 +1,66 @@
# Day 3: Rucksack Reorganization
## Part 1
One Elf has the important job of loading all of the rucksacks with supplies for the jungle journey. Unfortunately, that Elf didn't quite follow the packing instructions, and so a few items now need to be rearranged.
Each rucksack has two large compartments. All items of a given type are meant to go into exactly one of the two compartments. The Elf that did the packing failed to follow this rule for exactly one item type per rucksack.
The Elves have made a list of all of the items currently in each rucksack (your puzzle input), but they need your help finding the errors. Every item type is identified by a single lowercase or uppercase letter (that is, a and A refer to different types of items).
The list of items for each rucksack is given as characters all on a single line. A given rucksack always has the same number of items in each of its two compartments, so the first half of the characters represent items in the first compartment, while the second half of the characters represent items in the second compartment.
For example, suppose you have the following list of contents from six rucksacks:
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
<pre>
The first rucksack contains the items vJrwpWtwJgWrhcsFMMfFFhFp, which means its first compartment contains the items vJrwpWtwJgWr, while the second compartment contains the items hcsFMMfFFhFp. The only item type that appears in both compartments is lowercase p.
The second rucksack's compartments contain jqHRNqRjqzjGDLGL and rsFMfFZSrLrFZsSL. The only item type that appears in both compartments is uppercase L.
The third rucksack's compartments contain PmmdzqPrV and vPwwTWBwg; the only common item type is uppercase P.
The fourth rucksack's compartments only share item type v.
The fifth rucksack's compartments only share item type t.
The sixth rucksack's compartments only share item type s.
</pre>
To help prioritize item rearrangement, every item type can be converted to a priority:
Lowercase item types a through z have priorities 1 through 26.
Uppercase item types A through Z have priorities 27 through 52.
In the above example, the priority of the item type that appears in both compartments of each rucksack is 16 (p), 38 (L), 42 (P), 22 (v), 20 (t), and 19 (s); the sum of these is 157.
**Find the item type that appears in both compartments of each rucksack. What is the sum of the priorities of those item types?**
## Part 2
As you finish identifying the misplaced items, the Elves come to you with another issue.
For safety, the Elves are divided into groups of three. Every Elf carries a badge that identifies their group. For efficiency, within each group of three Elves, the badge is the only item type carried by all three Elves. That is, if a group's badge is item type B, then all three Elves will have item type B somewhere in their rucksack, and at most two of the Elves will be carrying any other item type.
The problem is that someone forgot to put this year's updated authenticity sticker on the badges. All of the badges need to be pulled out of the rucksacks so the new authenticity stickers can be attached.
Additionally, nobody wrote down which item type corresponds to each group's badges. The only way to tell which item type is the right one is by finding the one item type that is common between all three Elves in each group.
Every set of three lines in your list corresponds to a single group, but each group can have a different badge item type. So, in the above example, the first group's rucksacks are the first three lines:
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
And the second group's rucksacks are the next three lines:
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
In the first group, the only item type that appears in all three rucksacks is lowercase r; this must be their badges. In the second group, their badge item type must be Z.
Priorities for these items must still be found to organize the sticker attachment efforts: here, they are 18 (r) for the first group and 52 (Z) for the second group. The sum of these is 70.
**Find the item type that corresponds to the badges of each three-Elf group. What is the sum of the priorities of those item types?**

300
2022/day3/src/input.txt Normal file
View File

@ -0,0 +1,300 @@
vJrrdQlGBQWPTBTF
fcpTMnMqMfTnZpgMfPbFBWzHPpBPzbCPPH
mcVMfcsqZgmgVcmfgcmZmqZNJhrlrdhNhDdrRRJSvDTRhJlD
pMFRmLwHMbRPmMbPPddvqqrrNSTFVttdrN
hgfpgCGZcjpcgfvNtdrtjvrdtSrd
gZgsBBBlZggBGhsfhpzlzLDLmLRDRMLDPw
hChhMFCvqtTMwbSSHgTZWHZd
jjBNPjJJNfsNjVnVJJNcNfPwGbSbDZnZZgHrddwHrrgWGb
mBBRRmBBQBmNJWhCzqllzhRCCv
lQgpngNgQvHdSgWwjMRmDjmMDHmm
zCLVzfzzbbCzsZZPbZPLfFJJMDWWRcDsmJRcjmwTmlRj
BblftzBtlFznptSQQQppNG
wJJwqCtCGRcVlqlM
BQpppjBQLczTrvHRjH
QQQFnmQWWRfnpQBpQpfDCwCdbPDCwbNNPtdJPCZw
gpJjshBpgjZGppJqBGJjJZzTwzTmcvzwwcmvwsCFdmcF
WPSSWWSQLVdDDfWltDWLPfttvFCVmzCCTFnmwcnnnCTCzVVv
tLldLltDQfflrRWNqBRjgHBpJNZjHj
bzVJjVnjbCGVLZQLmmsJZZQQ
RrwwzhPScWSwrhvZZvZlZvvSTsQS
HwFhzFWdPHfcPwPWPdhWffnngpjtnjgtpnfGCGnG
CPwQtftDQfPDBPBCfDDDCDptszcpVVddcRczVLVdccRGrLWs
FqlSnhlqhmhMbHqqSQlHbcrRrsWzRdzdWVzLRGRrVF
MbQmSnHZhqZMQMTJCttjCgPCwfgDwT
CCSpvHtZHSwftFtdtbfR
QJmNPmjjJNgNVNSzDlmRqbWlqWWfcqfWqbwfqR
MDhJzmSMDmsZrLhssrvh
ZhznnrLzcHhHSjsjSBSsBnSS
dTwqDdqDRQjNdwqjldggDvBJfmBfTSBbBSvfSJsmff
DjCldNglVwFVgZHHHzhCMcLhMC
vBnShjwwSshmQPmtJLpJtn
rDLFCWrClWCMWWVrbFVJqpQqpHmtbzJPQzJmzb
ZMCCDCMNrTWTrgScgGRhsvcsGLSG
LQpJglQQRjQsppfsQbjfbQlBgBhFhrvghhZCdPZZZthPgv
zVHDMSWVVMVWDzmnVMHDSMMzZvNFFrFvPCdmdFdNdrBPZhhd
ncqqSzMVCcGWVSCTWCDcVTffLLLbJsLLsRLblRQTps
zjGzLQtFzzRgwwLhVrqw
dfClCdHZsmffZDWlBZHCDBmhJbqTgbwgqbTnwrgrqRbT
HsdwPCsWDpDsBpfdWdHldWpsGvvccPvGcvzQvFQvccjNztQt
wmVVgFPrFdwJrlNHQHSHCCHL
tWBtvnBqZZMpcvmmqMBRCQQLCLWCHfNQQCSGWL
BBsnmcpqPswFsTws
BQRpFPJJJJPmPRqZNFVhcczHHzggwjBhghgzHw
snTsTLtrlvSSSslsGdcwmjhgggvjHhmH
nSsWWTtCbbDSnlRRZCfFRNZmCVJf
tRRMCWLtJWQLqLrmLHVLqmqh
JszPjSbGbsnGnSZprVpFhvFqvhrqZZ
zgbGSDBbPsTgbDBzzSDnDnPTcWlWJCQlNttNwwwMcMctcW
hlVRvPvzqqtRdwRRJsst
HHVNVBMBjHLTjVjwDjsbjJwbdmbbss
NBZHMCNVCCpgLTWggBpgNLTvqCPnGhQhCCGlqlhfcvvGfn
mwbfbfbDCqRJZRbCSvmfWTQFczTznnnFTFnrzJsz
BdhHlLjpjjjncSprnsSFWS
ljhVBPjSdHPRfZRZDvVRZM
tGqbqBSsntRgNqwNNVVHVN
hclFvJZvCDFppDpZpHNggMTwdlrMQNVgHM
CCFmcZLDFpvzZhCFJvZvmwjSRWsBLWsnfWjRRGGfnsst
GdGQQFdcMPwMdLFvWsNWFDLfss
SqjhtjnrbVznSztSqtzpjztVvTmNNmmfMMfDDMDDNTqfgsqv
rVhhZjppVrhpVzRbjSnzHPMwlJCJQdcRPPlPPcHJ
JVQLVgVZghFtFlhghtvSzsddmrdvssmzSWtd
HTMJCBMCjnwNBnCbTNwMdWfzvzsrsvffWbdsmfPr
BGnnpDnTjjHJwDBNpqlFQVQFQclcRFQqpR
BRhbrQDttbTTtRDtTRRzLHWZLZHGSqWLCBNWqLNL
fwFPPSjmsmJGLsNH
dvfSdvfVMjPTttTzczgTcd
dZgggwzgvsggtdstZTZgdfnhSJSSJDDhnDBdppnGnhSp
VQWRQWVCRLFGnThJCpFJ
LbmmbQVcHcmmlWjmVlVQNVRzvwwZvTrsrNwNwzZrMvfsqt
lDZQSlHDbLccRPQhCNhG
gtsntgvdvBvvqgsTgBggdrWRNzPhWczPbWcdWCccGGGP
sTBttvrFnnMTMJngbqfLlZLpwFVljwppZZDl
zNNNgqpgmLgqlHBHsMGslH
WdWFrFwhcwWRwhddcRWcdQbcDDslzBDszsHbGBDfbHfzVlVl
ZvhRrvPQwvWFQRZvFdJttSPgCmNppCNzJnJS
fCzRRNGfqNRvwpQhwrGcwZZT
gJnStgMmLhdHndSSTjcTrTpcmrjjcrrw
FFJBbdddFPPhFFNWCF
btrHRSBBSNLLRPLwhbhpqpfWhQppWZ
zCzTvvmgDvgDZhqWZZthtDZh
ttTjMsvCgRRLRSsBRG
LsSFFTTDWdCsmFTlLSsLDDRRQCvhpRQGNGQBJBhGGMNB
zqPtqZnjPPrPvJHBMHrJrMpv
VbqfjZfwgtfjPgZPgtwDLTLcTlcFdWLdcdVTJF
pfMCDmpHbdMQQdQFFG
gdjldRsVFRntQnqR
rlJVsWgWPWjsslSpDbScmSDPHfCd
lnFFGgBFBslDFGbFSjnNTjjppSrQHhnT
zcvmCRcvZmcZzWpTQhQrrTSPtHWH
CRccrZJmdJlwDJwgswGg
hllrrDzggGppgSSLNWgW
jlTlPwwqjjntVpWWPNnP
wjjJqvQjJjQJbTjlFqhBMzfDDmMCGBMHDCGb
jvQPhhtCRtfmqHHjqHHJsl
FFSTcBTBTMwFGCTwMTcGwTVnsHSJzqqJJJplmlpJHszZZzZD
dLMdVMNGBdGFMTNTRRLrQWCQhgWQbhgf
gdRgdgzzrvrzggDwgDGpPLzrbNljMTsbWWjWjZbTjLZMWcWj
tFfCQHJJnJMJTJjNNMjl
HmtffVttqHQmBCBQCqfFnCwRqpDvPRrGppRggNzdwgzp
DHSqzQbzWlRLDzMZNpVLgnpNLggw
cZcdTmPPthPdsvvdhPGTvJgwnpgjjTgNNwMVngNBjNfn
PPdJPvrtGtcFdFFchDRHDqHzZWSQQCrQWQ
BcgnLBLsFvRnGRRRlzfJbbPJzwHPwPFz
hCDjWMDVNfVllfzddw
qqMqpWCMjDTWNWTBLpgsgLvZwtGLLg
zczPgpGzhnbmbchhHwqwhSwfwHCFWw
VJdmVLlLdVJSJWHSTFwH
rlttQLVLdvvZpgcGbmDrzGMD
WSvtpqqtqccttVQpVvJNJSVNCmTlnCWwTTnWlBBBjwCBTlTP
ZgfPHfPfMHsDCwnlGBwTMGBM
rgdffZhPrrLsdLZpvcFSJJNvpJhcJv
qVdqJGvzgJzJgwzgWvdJzpblcRRWmLFFcLBmllFRRMRFRH
TGGSsSssNPTSLlRLcPHMmnPB
tTjTZtNGhrCjQNCjQQDTCSjZvfJbdgqrdpwqfVzwgzvdvVgb
VTmwcTVSMHwbMwbDVBTcMpJfpfnWqdJbZpJldfsjZn
hNtPhtzFzPQGCCGFFCGtnqQqWZWplsjWdlnlldJn
vRCRzvvFFFvhrRthPtLrtNGSwBVDScDSgHHjwwcBgSgTSL
dWCsWbWWchblsmbWVZqqsSpsGfBqBVBB
DtTtjPJrgjjtTTwgPwwjrTgnLqSBZQLqngQppqnfBVQfGp
PJPwwtDwHGGJtJRFHmhCFRCvdmHR
mMsMJSCjllsSSmBBclsMsJHDbcHqqbHpqHGbDZHbqHpb
RnQnGVnzGzFQgzWzpzvpqDHW
QVhRTfGLLFGTTFFwhnQVNfFwJsJsMjsBMrlsjrJlPSPlTrls
JNMJSVSGVCjnWZMZWWcH
gLTcqbqhqbbgzgnjpnjjWHnP
wqlbcrfTwrvcLBwwRtJwsNRstRsCCN
MlBssQBchZDLNJZgmvGg
fdzHMfHSzSprfgSvvJbmvDGNDW
PCHTRfjHnzHMzzfrCPCpMTlFhcFstqVwVCFllQcBtqss
TtFnnFJfDhtdfJJcFtfnsfcFjBjLDjHrDLrCjMjwCLLrZjrS
qQmWmQzvWpRQGvgpGGRGRzmWwZMwBLCHMZjbBBCLwrHSLrqr
MRllgRWWMlsJFnlFclJT
SRRrRDRBRTdbdMRZBZMprTCJCnWGvChJGzLSWWzsGhCs
wwqHPtFwjwTHLHvGTsGW
FlPtqTNVcTVtwtmjRbBZfQbfZbQmRRMR
WSWfQttffsHSfRRRStfnCsQQqlJpbhnrnmNzJbzqNbbrpmnb
FGFPddBcBwDPzpzbWlpzDbbh
ZPdPPLMFdGwFFGdwGdZwcZgTtSTVCsRRSgSRTQWTTtCTtH
vHsfGHTvSvHHHsGHctMgtHrJwbJJwrjgbrdzjWCrdrrw
hqZRLmmZpFhcLhFmrzJQbzzmQQJWJJbm
LNZFcpPlhBRhqDDllRtnMssGfBsnttGTnttT
VDVrLrZZcjrhhFrZppGlglGMPFwFWNQw
bzszSBHBWNGcscpN
TJqBqSfTBBqBHzJqddBqzcLnLjnhCRTvvRrnDrvrvZRn
GLzrNWbtMptHDmNDglgmlD
fZtcfCRvtBcQjdjgmmjj
RhBhhqfSPPpttrnPnVVW
BhVRJGwWqtHjZqTDLZ
gQnfpBdPNpQrPNSfBdndnpTTDFZttDLLzZzTzCLNLZZD
mQQPsgrldpgdBQgSbGVcmcRwGMWhwVwW
DrLCctBCLQtSSQcLbcQHWvvvlWHHnWlWBlNRRB
wqdmpgqsZhzGphwwpZGsppRvfnJsWfHWvfFfWFsfvlNN
mwmhVppTqpGqpNZpqTbSLLttDrDDtPQTtr
qwqmgnglDnlgtQzQJzJQhmWQ
pTpTpssdsVvNsdTSZGdSdjvCRcqcRcVWVczhWChtchzWcR
sGTvPqZvSGdZZGdsvNGdPHrFHFBDlDLwPgBFLLBB
BBBGsGGBrBBrqWVqRnWBBBWpzFwMhjMFSFPzzSwPFPpzzFvg
HtCdDdDctZDtbHCffcbddbNfvjvFSPFjMhMgLwPgjbFhjFFj
NJTDdltNgCNDZJJZCDJZDfJtrWWnQGBqlRVVlrBsnlrqqmnr
PwZhgbZSWSqqGznv
tTPVVmptcsrNrsTNpjRzqfHvvGfGWjfjqGzHWn
RVRtVDRmsRtrctmJDtgBBhBhbFgJPFFMFJgP
jPzzCCPzTtTfzrRtgSNVRHvFQVvbpQppVN
sSnDlBGBwJbFNplVlN
cLwSwdMhSwcBcsBZgWjCTCWfCLffrg
RSNPvTTNqFTSvNrSBvBGJGzmFMslgCMJCgmzlc
fDVfpptLWQfnVLffVHbQDQCclJzGGCtGmmGJmzMshzGh
VfQnWZfZDbdnVHWcfWnfHWVvPrTSNZqSwSqPjjvBwRqrNS
FLRpmRwcpjfzjSnD
tGvPNvBnPQggPQQvPgNHDjSSjDzzthjzfHrjlT
JGqvWNCCGQBWGBQvVLsCMMRLRnRMnwMc
fGJbzgBffCGpPGDVnG
mcTccshvbbdRNRsNjdLjnVlHVnHLqVpDpDqD
wdmsWvWssbZTcWvRhfzMQtrzMgrfrZJgfQ
NfSbvZHZNRSbQbbQgZrMjhLwMrjLjwHLCmmh
NTWdJBFcWJFcdsFJqcqPwqmjpMrLCMpLMwLP
dNJctnFBVfSGgvnfZz
GSnRJfGfRJgMDMGWnfzdmptpFJppLvwLwvLt
hbjZzrQbblqcLtpwlHvFplTH
qrzqbschrQCqqjPcCVcCGDfGMWDgWNGDDSfgnf
vmMpCdTndCvMdmnFcCRJWBJGcZJRJB
NDNwGzshPLrwVVNsjswhGzjFSfFFQQRSJWRBFcFRfsWFQB
NwNhNjVzhhzzrgzdqqvqtnqvlqdggG
MdPLVSSlMMVMmlLBBLFdvZNWqWztStttRRNqzqNGTq
DhJfhghhCgwChJgJwHHzbsHpnZRtTWqqfZRGTnWTZtNqNRWR
hwHpJbprwpQhDHDCbCCzsClBvrLMVFPvmPlMMVMdLrvj
DssDrqRsWsNfzfsWLRzjgTdBlgzFpMlgTFTglT
ttCZnSQmSQmgjGQGQgDlBp
bhDnCmbwVmCwwtZttPwbRWsRJcqWJfcfsfrqVrqq
ldBgTMTRvBDVnCCCTdSRTqNjbjSbPPPPqtfPqtPJFJ
cZHZrszLrrrZHrbNjNtbJCfqNJLt
GZzCzWZGGsGzmzZcmGssZzZVvnVdBDddRRDnVlWgRTDdBM
RjNrrjwGDDqqGJsHtzpMHHGz
QCbWgbShmBCCPClmmWFHzJzTbDdsMJsTtpTD
fffQfnSCWDBfhCDLRrNrwcrqVqwNqn
zmRrDRzqjmLLHzDjLsHLflJlVVJlWWTDTfdMtlWJ
pPQQnbvSpvNbgfgfVtMVJfgdtG
SnpnVFcPnNnPvpNSFNSbhHLhrjhCqRsRBRrHCLhzmC
CZZzlnCZNlGGcbVrbtVlMtct
MgFQDFgQRLLHhJgDFqQJQLgdtVTrttSrPSmcbmTtvSqvVSTV
hFQDDfMDfLgHwWfBzWwwsZGW
bHVDdHVHTPMvnSQnWSDQgDmm
GhrCJfbfrhfbRJcqGqlwZtnBRtBWSQgQWWnWQW
lfcCrqJhlfFqphpplNCrNVMPMPLbsLPLzFVHVLsVdz
VDhFCZhtFdPqwwcp
SvnvHNNnTvbwNNgnHwTHgwBTLcdqmmfmqLGmmTRLPfpdGP
BNWsHJgSnwgMMgMBBWMDVJjtjZrDJZzztJhjQr
HDsSHLRnpjbpbbRDbqLjLjjGGVffMVGMdvnfMcNvfBBGcB
TCzQQztwwNTMqMdBVv
hCQWmtCzZthPPZPrLjSbJqjSjLLFjLpr
ZrrZqJDcZSCFLLHBFcjjHF
TgvnDTlTtQwgBfwwwzLjGLdF
VbnVngMtvDTTVMQDQMDQlsbZJChCmCPhprrZqhqZSZPJ
glMGHBJTJJTplgwcCgcqcFhhbWncFm
sSswtPfRDmWcCqfchq
RZSdSzsVzNPSwSSQsdzSSQpGLjJTMpBGrJrLLrplZBpG
WQqqwLqQlnlWDwtbVbtCNfVbpV
dFTRjBPhcBgBrFhTPhrbVptJpNNbbtJCbJSL
hjcmcRmgPPcRcPDmHHzGLWmsDmzH
rWFmrRmmccSZJWvSLZTH
hDPhGbhSjtbpqJLvJHjLHTqj
pnplBlfBPPhlgfDbDhglPMMrwrRRSSncwccQzddzmC
LbccJCGzbcCJcfGczcnmNnvNmZNLSDZZWPWS
dwstRhTsrsFddPZqvNWP
BBggRrQstBwBRTHWTprRCHHGVljfCGCfcljHjbGV
FHVBSVDvnsFDwwSVwwvGVSMFWhWcWptMWchWMtPPcWtNNWcj
TgqJrJTRmRCNrbcLjprLnp
qQTlfdlZQgmfqqnFVznvQwvnsBsV
TGpDDMQGMZNtfvDJdtWd
jbrmstmllRmNvVhmmvJVhv
tbrRzFFLlRrjFlLlTQgLQwwLMwgTZBTB
QFgFWQQfSgLFGmtnnVmqCPWmPH
TTzjgTbRRqnRsCPCsP
NDMMgZjzcJvbjhMcjZbbbJJNpdpBfBvSBBQwBSQLQSpSplBG
zcRNsQSSMjRsNNZZFBLQHHFFBPWF
tvwCtgvqLJNnNBCH
fNNwqrqNMpTrDlcs
MMHMVPRJHJWvqzWctbtQQdQz
DFfNFffDnTllfTfFfmzsjqcdtQGQpbddQQbssn
mlFNCgFNNNLrmLFCThhhzJBvhSJPVhMgMh
PWjhljbHFhjbFMWhjbPfhbTGZvlGcGlCLvvwtGCNZGvc
SRqBqBrmQWQrgQrrqrJBLZNccLNZmTCtvTGtCvCt
rJDzDSSBrzdqQWDPHFMjMFdjHMVnbM
qqLwvvtrLFqqfqrjjjdBZfBCBBJdlT
ZGZpRZHbQDzDWRRRVdBzSSlBdzjjzdJJ
ZGpgNDQmWGDRmRpZMQbvPPtnnFnLsstFmnFrPL
TdhcfZhdZZdpdbPWttCWrrCN
MBMMqRLgpGpFFWbNsvLwvCPCCP
mpBMnBRMBGqJfZcfZZHZlhfm
CdmGdnMcMwHjhDtFFnrj
vPbVbPBPPpgpgWJpvTjqDZZqSHqVZShrDj
BppjjgvbJjbpNbzPfNcGCLlCRcmLLflllGcc
qDtgVttGFtlslStS
gCZbbHCjvJbZjCbJhHhHJrZcslJcLzLllcLNFssMSsTlSM
CWbWrZgWBQQBBpfdPm
hstPtCGtltlTClllPJLScVdPdJjLPJMV
NHRbDZDQSDFFjjdJ
RqbQpgBmqZvqZNQqgZmmbszpTtthtCswhjslwwpTWC
CVdwBJJdppbbwdBVrJbrJbGPlMFSLrjrPjmPFFmPRRDF
NNWHHhNZTcQWhnNFlmSSlRmLjnPPRF
qWsccHTZccsNsZcvTcNtStpBtbdVwpfBwbVCBq
lPQHNJhMPMPFlNMHBqZBwQwQwQZwcCqw
bWddDzbWbftdDSDbgttgnSDWccLwcvBczqcqGZzLccZTZwwc
spWrssWrnDtDpfSWDtsFqlFPjNMjRJVVNNPJNp
bCCfcWVLTHfSSdHwhH
sGQSZSzQJmmQsphwHHHsndnpHN
zPSqrmZPFCvFTbWMLV
tLtVBGLJqGqVGbzGSCsSsSqQsFvZCSQv
gRgdWlHTBHgjjHlWpWjWjrwdCfQRZFSssQQQZmQmMSvZfFMQ
lPHlpWgjTldprNWHNNdHjTctcLbVcnNJJGbVzBhnbhhJ
zVrSwzzJbVrbqFCVVVwVCztWDDtfTZsWDZTLZZmSWsDm
bpgHlgBbbGGGglBGRNvMpWfTDjmDfWDjfRZZWLtmZs
bGbvQHMpQccFJPPh
VGqCPmPjfGqCdMqVMhjhmPChDJDJzvrrbrBvrdrpnJDpJDQr
TSRsgHRSFHTlHvJvBDvvzlptbv
ZFLTsRRgZTgWscHTfWNWNPPBfGqmmMfV
TvTrrrCVCVwqjPrWfWhjfH
RRmgmnggltRgNpzRsdfqWWjdFdvNHfdh
zZlRzDGGZmbmmZbvGJVccwCMVcVVTLwDwC
QPsNlvvvSccbbNQcSPvDVSvzTLLCgRVzCJgTJpgCpphgzh
MDqHwFrMffgFpgpJLzTz
ZtdrffBrdqmBBmfwMtDtQPPPbjcNvnllnlbNtScn
HbbbcpTHHMMqNTCddCVBQvgPzJPJWQBQjvpBvQ
FFrDGtntFFwhrRFDFthfRhRmSJPJvvJZjZjWJJvJQJnvWjjg
rtfFfLmLRmNgdHqcLNHd
FpFHCFWtFSnCWnBfJJfgMJDGHDGGsG
rhrLrrhLrbtZThLfgsfGNDfgTgNcDs
QmPjbdqjmbbbrmhQqQZrZStRdlnnFdlRzVVVWlnpzR
bBMwwjzhbjhssvsGZBSZLr
JFtnDtRzJtffJHWNtHncRRrvGZvSnllZZZsgvlnvVvlv
RRPHPHFPHHdcHtzNfMQhdCwbqCmbMChhqq
pWGdFSWwwjLdvgNNvggl
mTNbmRPHmmVNmvZhnhBssBlhnb
HPTzRPffJJNzjCFpDWDz
MHlgzsqHlbmzgsHzlsbcRWPdPtjZFqhGGdrPrjPJGrVP
vpwwvQwCnhNQpSnLdVtrrZGZtZjdVSdJ
hfffwvTpvLwDpCLvDnQDHbmRRTcWRHMWWHWMmWMW
WHlNHWWldjpwntnWBPpPQFZFBFhZBZCZ
TqqvgvmgfmvDVLLfqqLsrFBRhrrBFJQBGPgPZGCR
mcDbcDmzLcmDDzfVzTQNjNzNztdzjNdwSHlH

102
2022/day3/src/main.rs Normal file
View File

@ -0,0 +1,102 @@
fn get_split_rucksack_items(list: &str) -> (Vec<char>, Vec<char>) {
let all_chars: Vec<_> = list.chars().collect();
let half_index = all_chars.len() / 2;
let halves = all_chars.split_at(half_index);
assert_eq!(halves.0.len(), halves.1.len());
(halves.0.to_vec(), halves.1.to_vec())
}
fn get_rucksack_items(list: &str) -> Vec<char> {
list.chars().collect()
}
fn get_priority(item: char) -> u32 {
let is_uppercase = item.is_ascii_uppercase();
let char = if is_uppercase {
item.to_ascii_lowercase()
} else {
item
};
let priority = match char {
'a' => 1,
'b' => 2,
'c' => 3,
'd' => 4,
'e' => 5,
'f' => 6,
'g' => 7,
'h' => 8,
'i' => 9,
'j' => 10,
'k' => 11,
'l' => 12,
'm' => 13,
'n' => 14,
'o' => 15,
'p' => 16,
'q' => 17,
'r' => 18,
's' => 19,
't' => 20,
'u' => 21,
'v' => 22,
'w' => 23,
'x' => 24,
'y' => 25,
'z' => 26,
_ => 0,
};
if is_uppercase {
priority + 26
} else {
priority
}
}
fn find_same_item(a: Vec<char>, b: Vec<char>) -> char {
for ch in a {
if b.contains(&ch) {
return ch;
}
}
panic!("We should have already found the item")
}
fn find_same_item_in_three(a: &Vec<char>, b: &Vec<char>, c: &Vec<char>) -> char {
for ch in a {
if b.contains(&ch) && c.contains(&ch) {
return *ch;
}
}
panic!("We should have already found the common item");
}
fn main() {
let file_str = include_str!("input.txt");
let sum: u32 = file_str
.lines()
.map(|line| get_split_rucksack_items(line))
.map(|(a, b)| find_same_item(a, b))
.map(|item| get_priority(item))
.sum();
let sacks: Vec<Vec<char>> = file_str
.lines()
.map(|line| get_rucksack_items(line))
.collect();
let group_sum: u32 = sacks
.chunks(3)
.map(|chunk| find_same_item_in_three(&chunk[0], &chunk[1], &chunk[2]))
.map(|item| get_priority(item))
.sum();
println!("Part 1 Priority Sum: {}", sum);
println!("Part 2 Group Sum: {}", group_sum);
}

8
2022/day4/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day4"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

63
2022/day4/README.md Normal file
View File

@ -0,0 +1,63 @@
# Day 4: Camp Cleanup
## Part 1
Space needs to be cleared before the last supplies can be unloaded from the ships, and so several Elves have been assigned the job of cleaning up sections of the camp. Every section has a unique ID number, and each Elf is assigned a range of section IDs.
However, as some of the Elves compare their section assignments with each other, they've noticed that many of the assignments overlap. To try to quickly find overlaps and reduce duplicated effort, the Elves pair up and make a big list of the section assignments for each pair (your puzzle input).
For example, consider the following list of section assignment pairs:
2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8
For the first few pairs, this list means:
Within the first pair of Elves, the first Elf was assigned sections 2-4 (sections 2, 3, and 4), while the second Elf was assigned sections 6-8 (sections 6, 7, 8).
The Elves in the second pair were each assigned two sections.
The Elves in the third pair were each assigned three sections: one got sections 5, 6, and 7, while the other also got 7, plus 8 and 9.
This example list uses single-digit section IDs to make it easier to draw; your actual list might contain larger numbers. Visually, these pairs of section assignments look like this:
<pre>
.234..... 2-4
.....678. 6-8
.23...... 2-3
...45.... 4-5
....567.. 5-7
......789 7-9
.2345678. 2-8
..34567.. 3-7
.....6... 6-6
...456... 4-6
.23456... 2-6
...45678. 4-8
</pre>
Some of the pairs have noticed that one of their assignments fully contains the other. For example, 2-8 fully contains 3-7, and 6-6 is fully contained by 4-6. In pairs where one assignment fully contains the other, one Elf in the pair would be exclusively cleaning sections their partner will already be cleaning, so these seem like the most in need of reconsideration. In this example, there are 2 such pairs.
**In how many assignment pairs does one range fully contain the other?**
## Part 2
It seems like there is still quite a bit of duplicate work planned. Instead, the Elves would like to know the number of pairs that overlap at all.
In the above example, the first two pairs (2-4,6-8 and 2-3,4-5) don't overlap, while the remaining four pairs (5-7,7-9, 2-8,3-7, 6-6,4-6, and 2-6,4-8) do overlap:
* 5-7,7-9 overlaps in a single section, 7.
* 2-8,3-7 overlaps all of the sections 3 through 7.
* 6-6,4-6 overlaps in a single section, 6.
* 2-6,4-8 overlaps in sections 4, 5, and 6.
So, in this example, the number of overlapping assignment pairs is 4.
**In how many assignment pairs do the ranges overlap?**

1000
2022/day4/src/input.txt Normal file

File diff suppressed because it is too large Load Diff

66
2022/day4/src/main.rs Normal file
View File

@ -0,0 +1,66 @@
#[derive(Debug, PartialEq, PartialOrd)]
struct Range {
low: u32,
high: u32,
}
impl From<&str> for Range {
fn from(s: &str) -> Self {
let parts: Vec<&str> = s.split("-").collect();
let low: u32 = parts[0].parse().unwrap();
let high: u32 = parts[1].parse().unwrap();
Range { low, high }
}
}
impl Range {
fn contains(&self, other: &Range) -> bool {
self.low <= other.low && self.high >= other.high
|| other.low <= self.low && other.high >= self.high
}
fn overlap(&self, other: &Range) -> bool {
let range_a = self.low..=self.high;
let range_b = other.low..=other.high;
range_a.contains(&other.low)
|| range_a.contains(&other.high)
|| range_b.contains(&self.low)
|| range_b.contains(&self.high)
}
}
// ----------------------------------------------------------------------------
fn parse_ranges(line: &str) -> (Range, Range) {
let ranges: Vec<&str> = line.split(',').collect();
let range_a = Range::from(ranges[0]);
let range_b = Range::from(ranges[1]);
(range_a, range_b)
}
fn main() {
let file_str = include_str!("input.txt");
let count = file_str
.lines()
.map(|line| parse_ranges(line))
.map(|(range_a, range_b)| range_a.contains(&range_b))
.filter(|contains| *contains == true)
.collect::<Vec<bool>>()
.len();
let overlap_count = file_str
.lines()
.map(|line| parse_ranges(line))
.map(|(range_a, range_b)| range_a.overlap(&range_b))
.filter(|contains| *contains == true)
.collect::<Vec<bool>>()
.len();
println!("Part 1: fully contained pairs: {}", count);
println!("Part 2: overlapping pairs: {}", overlap_count);
}

8
2022/day5/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day5"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

128
2022/day5/README.md Normal file
View File

@ -0,0 +1,128 @@
# Day 5: Supply Stacks ---
## Part 1
The expedition can depart as soon as the final supplies have been unloaded from the ships. Supplies are stored in stacks of marked crates, but because the needed supplies are buried under many other crates, the crates need to be rearranged.
The ship has a giant cargo crane capable of moving crates between stacks. To ensure none of the crates get crushed or fall over, the crane operator will rearrange them in a series of carefully-planned steps. After the crates are rearranged, the desired crates will be at the top of each stack.
The Elves don't want to interrupt the crane operator during this delicate procedure, but they forgot to ask her which crate will end up where, and they want to be ready to unload them as soon as possible so they can embark.
They do, however, have a drawing of the starting stacks of crates and the rearrangement procedure (your puzzle input). For example:
<pre>
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
</pre>
In this example, there are three stacks of crates. Stack 1 contains two crates: crate Z is on the bottom, and crate N is on top. Stack 2 contains three crates; from bottom to top, they are crates M, C, and D. Finally, stack 3 contains a single crate, P.
Then, the rearrangement procedure is given. In each step of the procedure, a quantity of crates is moved from one stack to a different stack. In the first step of the above rearrangement procedure, one crate is moved from stack 2 to stack 1, resulting in this configuration:
<pre>
[D]
[N] [C]
[Z] [M] [P]
1 2 3
</pre>
In the second step, three crates are moved from stack 1 to stack 3. Crates are moved one at a time, so the first crate to be moved (D) ends up below the second and third crates:
<pre>
[Z]
[N]
[C] [D]
[M] [P]
1 2 3
</pre>
Then, both crates are moved from stack 2 to stack 1. Again, because crates are moved one at a time, crate C ends up below crate M:
<pre>
[Z]
[N]
[M] [D]
[C] [P]
1 2 3
</pre>
Finally, one crate is moved from stack 1 to stack 2:
<pre>
[Z]
[N]
[D]
[C] [M] [P]
1 2 3
</pre>
The Elves just need to know which crate will end up on top of each stack; in this example, the top crates are C in stack 1, M in stack 2, and Z in stack 3, so you should combine these together and give the Elves the message CMZ.
**After the rearrangement procedure completes, what crate ends up on top of each stack?**
## Part 2
As you watch the crane operator expertly rearrange the crates, you notice the process isn't following your prediction.
Some mud was covering the writing on the side of the crane, and you quickly wipe it away. The crane isn't a CrateMover 9000 - it's a CrateMover 9001.
The CrateMover 9001 is notable for many new and exciting features: air conditioning, leather seats, an extra cup holder, and the ability to pick up and move multiple crates at once.
Again considering the example above, the crates begin in the same configuration:
<pre>
[D]
[N] [C]
[Z] [M] [P]
1 2 3
</pre>
Moving a single crate from stack 2 to stack 1 behaves the same as before:
<pre>
[D]
[N] [C]
[Z] [M] [P]
1 2 3
</pre>
However, the action of moving three crates from stack 1 to stack 3 means that those three moved crates stay in the same order, resulting in this new configuration:
<pre>
[D]
[N]
[C] [Z]
[M] [P]
1 2 3
</pre>
Next, as both crates are moved from stack 2 to stack 1, they retain their order as well:
<pre>
[D]
[N]
[C] [Z]
[M] [P]
1 2 3
</pre>
Finally, a single crate is still moved from stack 1 to stack 2, but now it's crate C that gets moved:
<pre>
[D]
[N]
[Z]
[M] [C] [P]
1 2 3
</pre>
In this example, the CrateMover 9001 has put the crates in a totally different order: MCD.
Before the rearrangement process finishes, update your simulation so that the Elves know where they should stand to be ready to unload the final supplies. **After the rearrangement procedure completes, what crate ends up on top of each stack?**

514
2022/day5/src/input.txt Normal file
View File

@ -0,0 +1,514 @@
[Q] [P] [P]
[G] [V] [S] [Z] [F]
[W] [V] [F] [Z] [W] [Q]
[V] [T] [N] [J] [W] [B] [W]
[Z] [L] [V] [B] [C] [R] [N] [M]
[C] [W] [R] [H] [H] [P] [T] [M] [B]
[Q] [Q] [M] [Z] [Z] [N] [G] [G] [J]
[B] [R] [B] [C] [D] [H] [D] [C] [N]
1 2 3 4 5 6 7 8 9
move 3 from 6 to 2
move 5 from 6 to 7
move 6 from 2 to 5
move 1 from 9 to 7
move 1 from 1 to 9
move 1 from 5 to 3
move 1 from 2 to 5
move 3 from 4 to 5
move 10 from 7 to 3
move 1 from 4 to 9
move 6 from 8 to 7
move 4 from 7 to 8
move 1 from 7 to 3
move 1 from 1 to 2
move 1 from 2 to 8
move 1 from 9 to 1
move 3 from 9 to 4
move 4 from 8 to 3
move 4 from 7 to 1
move 4 from 4 to 6
move 2 from 8 to 7
move 9 from 3 to 8
move 2 from 7 to 4
move 3 from 4 to 9
move 4 from 1 to 9
move 4 from 3 to 9
move 2 from 1 to 4
move 1 from 4 to 6
move 3 from 3 to 2
move 1 from 2 to 8
move 1 from 2 to 7
move 3 from 6 to 2
move 2 from 6 to 7
move 4 from 2 to 3
move 3 from 7 to 9
move 2 from 5 to 6
move 15 from 9 to 4
move 4 from 9 to 2
move 12 from 5 to 4
move 9 from 8 to 5
move 25 from 4 to 7
move 1 from 4 to 7
move 1 from 4 to 8
move 2 from 2 to 5
move 1 from 4 to 2
move 23 from 7 to 6
move 2 from 5 to 2
move 22 from 6 to 8
move 4 from 5 to 9
move 1 from 7 to 9
move 2 from 6 to 4
move 2 from 4 to 7
move 25 from 8 to 3
move 1 from 2 to 1
move 3 from 2 to 3
move 1 from 6 to 8
move 1 from 1 to 8
move 1 from 2 to 8
move 1 from 8 to 1
move 4 from 5 to 7
move 1 from 8 to 4
move 5 from 9 to 8
move 5 from 8 to 9
move 1 from 8 to 5
move 3 from 5 to 4
move 3 from 9 to 1
move 30 from 3 to 4
move 3 from 1 to 4
move 2 from 9 to 5
move 4 from 7 to 9
move 16 from 4 to 8
move 6 from 3 to 9
move 3 from 7 to 3
move 19 from 4 to 7
move 8 from 9 to 4
move 1 from 1 to 9
move 13 from 7 to 9
move 3 from 7 to 8
move 3 from 5 to 9
move 4 from 8 to 3
move 2 from 7 to 3
move 14 from 9 to 4
move 10 from 3 to 1
move 12 from 4 to 8
move 6 from 1 to 9
move 1 from 1 to 2
move 1 from 7 to 1
move 6 from 9 to 3
move 17 from 8 to 6
move 10 from 8 to 5
move 1 from 7 to 8
move 1 from 9 to 5
move 2 from 3 to 1
move 4 from 5 to 9
move 1 from 8 to 7
move 6 from 9 to 7
move 4 from 4 to 2
move 3 from 4 to 6
move 4 from 5 to 9
move 4 from 9 to 3
move 1 from 2 to 4
move 4 from 4 to 7
move 3 from 5 to 3
move 1 from 4 to 5
move 5 from 1 to 2
move 1 from 1 to 9
move 7 from 2 to 7
move 1 from 5 to 7
move 8 from 3 to 5
move 20 from 6 to 7
move 9 from 7 to 9
move 2 from 2 to 9
move 2 from 3 to 1
move 2 from 1 to 3
move 2 from 3 to 4
move 2 from 4 to 6
move 1 from 3 to 9
move 1 from 4 to 9
move 1 from 6 to 9
move 2 from 5 to 8
move 2 from 8 to 5
move 1 from 6 to 7
move 2 from 5 to 8
move 6 from 9 to 5
move 2 from 8 to 6
move 11 from 9 to 2
move 1 from 6 to 5
move 11 from 2 to 5
move 1 from 6 to 4
move 7 from 5 to 9
move 7 from 9 to 1
move 1 from 4 to 9
move 28 from 7 to 5
move 1 from 7 to 5
move 5 from 5 to 9
move 5 from 9 to 3
move 6 from 1 to 8
move 1 from 1 to 7
move 5 from 3 to 2
move 1 from 7 to 8
move 7 from 8 to 1
move 1 from 9 to 4
move 2 from 2 to 5
move 22 from 5 to 3
move 1 from 7 to 8
move 1 from 4 to 7
move 1 from 8 to 9
move 1 from 9 to 4
move 14 from 5 to 7
move 5 from 5 to 9
move 19 from 3 to 4
move 1 from 2 to 9
move 2 from 2 to 5
move 1 from 5 to 1
move 6 from 1 to 7
move 2 from 7 to 6
move 1 from 1 to 9
move 2 from 5 to 8
move 8 from 4 to 5
move 3 from 4 to 7
move 3 from 3 to 5
move 2 from 8 to 9
move 16 from 7 to 5
move 9 from 4 to 6
move 22 from 5 to 3
move 1 from 5 to 8
move 1 from 8 to 7
move 10 from 3 to 4
move 1 from 5 to 4
move 10 from 4 to 5
move 8 from 5 to 2
move 5 from 2 to 7
move 5 from 7 to 1
move 4 from 7 to 6
move 3 from 9 to 7
move 2 from 2 to 3
move 3 from 5 to 1
move 6 from 9 to 7
move 5 from 7 to 8
move 6 from 1 to 5
move 6 from 3 to 4
move 4 from 4 to 2
move 1 from 4 to 6
move 5 from 8 to 7
move 3 from 2 to 3
move 1 from 1 to 4
move 1 from 1 to 9
move 2 from 2 to 1
move 2 from 4 to 3
move 4 from 3 to 7
move 3 from 7 to 3
move 13 from 6 to 1
move 1 from 9 to 2
move 6 from 3 to 5
move 8 from 1 to 4
move 1 from 2 to 7
move 9 from 4 to 9
move 7 from 5 to 1
move 2 from 5 to 6
move 1 from 1 to 4
move 1 from 4 to 3
move 2 from 1 to 2
move 5 from 3 to 6
move 2 from 6 to 1
move 13 from 7 to 6
move 2 from 3 to 4
move 2 from 2 to 9
move 2 from 7 to 8
move 6 from 9 to 2
move 1 from 9 to 3
move 1 from 5 to 2
move 7 from 1 to 2
move 1 from 6 to 7
move 1 from 4 to 8
move 1 from 3 to 1
move 1 from 7 to 8
move 7 from 1 to 9
move 4 from 8 to 6
move 1 from 5 to 3
move 9 from 9 to 5
move 1 from 1 to 2
move 14 from 2 to 7
move 2 from 9 to 3
move 13 from 5 to 3
move 24 from 6 to 9
move 6 from 3 to 5
move 14 from 7 to 9
move 1 from 4 to 1
move 20 from 9 to 7
move 9 from 3 to 8
move 15 from 9 to 6
move 1 from 5 to 8
move 1 from 2 to 3
move 14 from 6 to 3
move 2 from 3 to 4
move 2 from 3 to 6
move 13 from 7 to 1
move 8 from 3 to 5
move 1 from 3 to 9
move 8 from 5 to 4
move 4 from 5 to 2
move 10 from 1 to 3
move 6 from 4 to 5
move 4 from 5 to 1
move 3 from 1 to 6
move 7 from 8 to 2
move 4 from 4 to 3
move 13 from 3 to 6
move 3 from 8 to 1
move 3 from 7 to 8
move 3 from 8 to 4
move 1 from 4 to 2
move 2 from 3 to 4
move 1 from 5 to 7
move 4 from 7 to 1
move 2 from 3 to 5
move 3 from 2 to 1
move 1 from 4 to 7
move 7 from 2 to 4
move 2 from 4 to 3
move 1 from 7 to 5
move 4 from 9 to 5
move 1 from 4 to 2
move 3 from 2 to 9
move 8 from 1 to 7
move 1 from 3 to 5
move 7 from 5 to 7
move 10 from 6 to 4
move 1 from 5 to 1
move 4 from 1 to 3
move 9 from 7 to 6
move 3 from 1 to 8
move 12 from 4 to 6
move 5 from 4 to 6
move 2 from 9 to 3
move 3 from 8 to 7
move 1 from 1 to 3
move 3 from 7 to 8
move 5 from 7 to 5
move 1 from 7 to 5
move 2 from 3 to 1
move 2 from 8 to 7
move 3 from 5 to 1
move 1 from 9 to 7
move 1 from 8 to 3
move 4 from 7 to 8
move 4 from 5 to 9
move 4 from 1 to 7
move 3 from 8 to 6
move 1 from 8 to 1
move 1 from 7 to 1
move 1 from 5 to 8
move 1 from 8 to 7
move 7 from 3 to 1
move 3 from 9 to 1
move 1 from 9 to 3
move 28 from 6 to 3
move 3 from 7 to 8
move 2 from 8 to 2
move 1 from 2 to 7
move 2 from 6 to 1
move 18 from 3 to 9
move 5 from 3 to 4
move 2 from 7 to 4
move 2 from 1 to 8
move 1 from 2 to 6
move 7 from 6 to 4
move 4 from 4 to 3
move 3 from 8 to 1
move 4 from 9 to 8
move 1 from 4 to 8
move 9 from 1 to 6
move 5 from 1 to 3
move 4 from 6 to 7
move 7 from 6 to 3
move 5 from 8 to 1
move 12 from 3 to 6
move 7 from 6 to 4
move 4 from 3 to 5
move 5 from 6 to 7
move 12 from 4 to 3
move 6 from 1 to 4
move 4 from 4 to 2
move 14 from 9 to 8
move 17 from 3 to 2
move 5 from 4 to 9
move 1 from 9 to 6
move 5 from 2 to 1
move 1 from 9 to 8
move 5 from 1 to 6
move 2 from 2 to 6
move 12 from 2 to 4
move 6 from 7 to 2
move 3 from 7 to 6
move 3 from 9 to 8
move 5 from 4 to 7
move 4 from 2 to 6
move 3 from 6 to 8
move 5 from 8 to 2
move 7 from 6 to 8
move 1 from 7 to 3
move 6 from 4 to 3
move 1 from 8 to 1
move 1 from 5 to 7
move 2 from 6 to 8
move 13 from 8 to 2
move 3 from 5 to 4
move 1 from 1 to 2
move 3 from 6 to 2
move 1 from 1 to 4
move 4 from 4 to 8
move 8 from 3 to 1
move 2 from 4 to 8
move 15 from 2 to 4
move 16 from 8 to 3
move 1 from 8 to 6
move 1 from 7 to 2
move 8 from 1 to 2
move 1 from 6 to 8
move 6 from 3 to 1
move 3 from 3 to 8
move 6 from 3 to 1
move 6 from 2 to 9
move 2 from 1 to 4
move 1 from 8 to 5
move 8 from 2 to 9
move 8 from 1 to 4
move 3 from 8 to 6
move 21 from 4 to 7
move 1 from 9 to 7
move 2 from 6 to 8
move 1 from 5 to 1
move 1 from 3 to 9
move 8 from 9 to 4
move 1 from 1 to 7
move 1 from 1 to 4
move 1 from 6 to 8
move 1 from 9 to 3
move 2 from 9 to 5
move 2 from 5 to 3
move 1 from 9 to 4
move 3 from 8 to 2
move 1 from 1 to 4
move 4 from 4 to 9
move 3 from 3 to 2
move 5 from 9 to 1
move 17 from 7 to 1
move 1 from 9 to 1
move 2 from 2 to 4
move 1 from 4 to 2
move 8 from 2 to 9
move 5 from 4 to 5
move 6 from 4 to 8
move 20 from 1 to 6
move 2 from 9 to 8
move 1 from 2 to 9
move 2 from 8 to 7
move 8 from 7 to 8
move 4 from 5 to 9
move 14 from 8 to 7
move 1 from 5 to 7
move 7 from 9 to 1
move 3 from 6 to 4
move 3 from 9 to 7
move 12 from 6 to 7
move 22 from 7 to 9
move 2 from 2 to 5
move 10 from 1 to 7
move 1 from 4 to 1
move 2 from 6 to 1
move 1 from 1 to 3
move 2 from 4 to 8
move 2 from 8 to 6
move 1 from 3 to 8
move 1 from 4 to 1
move 2 from 5 to 3
move 1 from 8 to 4
move 2 from 3 to 7
move 19 from 9 to 7
move 1 from 1 to 4
move 2 from 9 to 1
move 2 from 1 to 6
move 1 from 6 to 5
move 42 from 7 to 8
move 1 from 7 to 6
move 2 from 4 to 8
move 7 from 6 to 8
move 2 from 1 to 5
move 2 from 9 to 5
move 14 from 8 to 3
move 22 from 8 to 2
move 3 from 5 to 6
move 10 from 8 to 6
move 5 from 8 to 9
move 12 from 6 to 7
move 2 from 5 to 1
move 5 from 3 to 2
move 7 from 3 to 5
move 2 from 5 to 1
move 2 from 3 to 7
move 4 from 1 to 2
move 1 from 5 to 7
move 1 from 5 to 4
move 1 from 6 to 2
move 1 from 9 to 2
move 9 from 7 to 3
move 1 from 4 to 1
move 3 from 7 to 5
move 4 from 3 to 2
move 5 from 2 to 3
move 2 from 5 to 2
move 34 from 2 to 9
move 1 from 1 to 5
move 15 from 9 to 3
move 2 from 3 to 2
move 1 from 5 to 4
move 7 from 3 to 8
move 3 from 9 to 2
move 6 from 9 to 4
move 5 from 9 to 3
move 4 from 4 to 6
move 1 from 6 to 8
move 1 from 3 to 5
move 6 from 3 to 2
move 1 from 4 to 9
move 2 from 4 to 2
move 4 from 5 to 8
move 1 from 5 to 6
move 1 from 7 to 6
move 1 from 9 to 6
move 1 from 7 to 2
move 12 from 8 to 7
move 2 from 7 to 3
move 4 from 6 to 9
move 7 from 9 to 4
move 9 from 3 to 9
move 11 from 7 to 4
move 3 from 9 to 6
move 1 from 4 to 1
move 15 from 4 to 3
move 2 from 4 to 1
move 3 from 1 to 4
move 17 from 3 to 7
move 4 from 3 to 7
move 7 from 9 to 2
move 3 from 4 to 1
move 4 from 6 to 9
move 1 from 9 to 6
move 1 from 3 to 1
move 5 from 7 to 9
move 8 from 9 to 4
move 1 from 1 to 6
move 6 from 4 to 9
move 4 from 2 to 3
move 1 from 4 to 3
move 1 from 4 to 9
move 1 from 1 to 7
move 1 from 7 to 9
move 3 from 6 to 2
move 9 from 2 to 3
move 1 from 9 to 4
move 1 from 1 to 5
move 12 from 7 to 6
move 4 from 9 to 8

96
2022/day5/src/main.rs Normal file
View File

@ -0,0 +1,96 @@
struct Move {
items: usize,
from: usize,
to: usize,
}
impl From<&str> for Move {
fn from(s: &str) -> Self {
let parts: Vec<&str> = s.split_ascii_whitespace().collect();
let items: usize = parts[1].parse().unwrap();
let from: usize = parts[3].parse().unwrap();
let to: usize = parts[5].parse().unwrap();
Move { items, from, to }
}
}
impl Move {
fn apply(&self, layout: &mut Vec<Vec<char>>) {
for _ in 0..self.items {
if let Some(item) = layout[self.from].pop() {
layout[self.to].push(item);
}
}
}
fn apply_multiple(&self, layout: &mut Vec<Vec<char>>) {
let item_count = self.items;
let max = layout[self.from].len();
let min = max.checked_sub(item_count).unwrap_or(0);
let from = layout.get_mut(self.from).unwrap();
// Clone this so we can borrow immutably
let from2 = from.clone();
let (rem, to_move) = from2.split_at(min);
from.clear();
from.append(&mut rem.to_vec());
layout[self.to].append(&mut to_move.to_vec());
}
}
// ----------------------------------------------------------------------------
fn get_initial_layout() -> Vec<Vec<char>> {
vec![
Vec::new(),
vec!['B', 'Q', 'C'],
vec!['R', 'Q', 'W', 'Z'],
vec!['B', 'M', 'R', 'L', 'V'],
vec!['C', 'Z', 'H', 'V', 'T', 'W'],
vec!['D', 'Z', 'H', 'B', 'N', 'V', 'G'],
vec!['H', 'N', 'P', 'C', 'J', 'F', 'V', 'Q'],
vec!['D', 'G', 'T', 'R', 'W', 'Z', 'S'],
vec!['C', 'G', 'M', 'N', 'B', 'W', 'Z', 'P'],
vec!['N', 'J', 'B', 'M', 'W', 'Q', 'F', 'P'],
]
}
fn get_position_string(layout: &Vec<Vec<char>>) -> String {
let mut s = String::new();
for i in 1..=9usize {
if let Some(ch) = layout[i].last() {
s.push(*ch);
}
}
s
}
fn main() {
let file_str = include_str!("input.txt");
let parts: Vec<&str> = file_str.split("\n\n").collect();
let moves = parts[1];
let mut layout = get_initial_layout();
moves.lines().for_each(|line| {
Move::from(line).apply(&mut layout);
});
let top_crates = get_position_string(&layout);
let mut layout = get_initial_layout();
moves
.lines()
.for_each(|line| Move::from(line).apply_multiple(&mut layout));
let top_crates_multiple = get_position_string(&layout);
println!("Part 1: Top crates after moves: {}", top_crates);
println!(
"Part 2: Top crates after bulk container moves: {}",
top_crates_multiple
);
}

8
2022/day6/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day6"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

50
2022/day6/README.md Normal file
View File

@ -0,0 +1,50 @@
# Day 6: Tuning Trouble
## Part 1
The preparations are finally complete; you and the Elves leave camp on foot and begin to make your way toward the star fruit grove.
As you move through the dense undergrowth, one of the Elves gives you a handheld device. He says that it has many fancy features, but the most important one to set up right now is the communication system.
However, because he's heard you have significant experience dealing with signal-based systems, he convinced the other Elves that it would be okay to give you their one malfunctioning device - surely you'll have no problem fixing it.
As if inspired by comedic timing, the device emits a few colorful sparks.
To be able to communicate with the Elves, the device needs to lock on to their signal. The signal is a series of seemingly-random characters that the device receives one at a time.
To fix the communication system, you need to add a subroutine to the device that detects a start-of-packet marker in the datastream. In the protocol being used by the Elves, the start of a packet is indicated by a sequence of four characters that are all different.
The device will send your subroutine a datastream buffer (your puzzle input); your subroutine needs to identify the first position where the four most recently received characters were all different. Specifically, it needs to report the number of characters from the beginning of the buffer to the end of the first such four-character marker.
For example, suppose you receive the following datastream buffer:
mjqjpqmgbljsphdztnvjfqwrcgsmlb
After the first three characters (mjq) have been received, there haven't been enough characters received yet to find the marker. The first time a marker could occur is after the fourth character is received, making the most recent four characters mjqj. Because j is repeated, this isn't a marker.
The first time a marker appears is after the seventh character arrives. Once it does, the last four characters received are jpqm, which are all different. In this case, your subroutine should report the value 7, because the first start-of-packet marker is complete after 7 characters have been processed.
Here are a few more examples:
* bvwbjplbgvbhsrlpgdmjqwftvncz: first marker after character 5
* nppdvjthqldpwncqszvftbrmjlhg: first marker after character 6
* nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg: first marker after character 10
* zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw: first marker after character 11
**How many characters need to be processed before the first start-of-packet marker is detected?**
## Part 2
Your device's communication system is correctly detecting packets, but still isn't working. It looks like it also needs to look for messages.
A start-of-message marker is just like a start-of-packet marker, except it consists of 14 distinct characters rather than 4.
Here are the first positions of start-of-message markers for all of the above examples:
* mjqjpqmgbljsphdztnvjfqwrcgsmlb: first marker after character 19
* bvwbjplbgvbhsrlpgdmjqwftvncz: first marker after character 23
* nppdvjthqldpwncqszvftbrmjlhg: first marker after character 23
* nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg: first marker after character 29
* zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw: first marker after character 26
**How many characters need to be processed before the first start-of-message marker is detected?**

1
2022/day6/src/input.txt Normal file
View File

@ -0,0 +1 @@
cmpmbppqmqsqzzrrswrrnqrnqqjzjvzzqvzvjvnnlclrrjhrrrnggmgwwdhhfttmmjrjzrzrhrbrgbrbsbjbcjjvpjjcvjvttfwffjtffqqqldqllhthhljhllfffbfbzbczzznmznnrrtgrgppdcppdfpfjjrggpjgjwgjwgghdggzzshzhrhttmhhdqhqsqgglhljjbggjhggfsfvfggrmggwwbwvvwssqtqzqlqvlqqvtthjhjrjssclscsszhzbztbbdhdbbqfbqqvdqdjjjspsqslsnlljnljjhttdtbdttjpjggtfftlldpdzzqhzqqcwwvggmgmppmhpmpddgjjbzbmzmllndldblbwbswsbbmzzwnnpdndzznmnjnjmnnzwwrqwrqrvqvqmmbmhmzzdqqfnqqgnqqfppmnnqzzvvcfclcrrzfzrzttchttshsphshddrgdggvwgvwwjjzbbprrgwrrcttwbwpwfffqppwnpwpqwwwbmwwjrjprrrsfrfdfrddvdzvzqzgzmgmpgpmmpspdssdlsldsdwssgzgddttqpphllvbvccjzjppffsjsbbvnbvbttgwtgtftzzlhzzjvzvsvtsttfrfrsswpwnwccqtqrqqrhqhjhccpfpgpjgpprnprrscctddqmdqqncqctqqrpqrprwpwnwnrnccmfmdfmfdfnfdnnphhbhttsszgssvhhprprnrsrrvggdllvfvrvbrbsrbrpphhqbbhllpttjmttrstszzwllbsbzzgmzgzbzcbcbjcbbjdjpjtttwggqhhpzpzszqqzhqqhrhlrrrvnrnqrqgrqggzccnnjrrcmmzvmmvtmtltvvlzlmmbnmmbbclljnjhhbjbhbjbbfcbfcfbbqwwftfhttwvwhhwfwcffwvwmmwtwftfjttwdtwdtwttqnttmdtdjtdjjlzjzhjhwwnbbmdmhhjmhmjjwmmpsmmhrrfnnqrqjrrpmpjpzpbzpztppswsmsnnlnppscsgcgsccsfcctbtcctvcvhvjhhccppbrbcrbrmbmvmllnmllgfgmgdmmslmlrmllhttgrrsttlmmnrrrlqqsjjddzzsbsdbbrjbjvbbfwwwglljplpglltlztzvtzzmbzbmbmcchlchcnhccbhhhzrrglgmgwwwwrddvmmvdvvpjpnpspmpsmpsscrrphpdhdllrsspcspsqslsspbbmcbmmdhdwhwpphfhmmfhmhjmjrrhtrtffsddwsddwccvncczlzjzdjzddszdsstgtbthhjhddwppvhvvvwrvwrrpspjpvjjsmsccszzgpzzmjzmzvmvrmmgbglgppbfppvvqffgdgtgpgdgnghhbhgbbpbdbrrjrtjtggvzzvttwbwlbwbttrbttvdttpctcrtrccddfrrmqqjrqqsvqsqzsslnlggmrggnllvdvbvmbmsmwmfmvvdwvwbbnddvfvzzjppbpgpvgppblbzznsscwssqppgbbfwwfmfzzqqgnnjnffvbfvbbfllbhlltvtnvnbnsnddcjcbjbbjpbbhhjghhqjjlttnmmhwmhwwddlppsjppgtthllsclcvvlfvvvlzvlvcccrhrrvqrvvzrvzrrmqqbtbnnwssvhvtttnsttrnnghgdggmgdmmnbnhbhdbddvppvhvlvttzmttljlflvfvpfpwffqbffjllnvlltslsttrvrdrmddtwdwmmlplhlnlffmzzrssvsgsffzjfjcffrcrppzfzbbtltjljtjftfmmmrjmjqmjqmjqmjqjsqqhzzhdhrrcwwbcltfjdgmhvmqmmsclsdgmdqzcvzznwgtdbzgvlpzvdqrvwpmndtzmdpznnplmbvvmffdpbjztvzpwffvqbwmvbmtwjrdpngrftvgznmtzwzmsrvpgpzjcdwvnqplfgncgcdtjbhcqztgqpdhwlmrjbzhcfhnzqmpzzghzpfzbgwmlqztnbdnntgdcfssgzqndhfwdtrbpzbmqjgjflmcllscjnnnrzzsjhnwptjlbhpcwwhsvqqlvjzghnwvzmwtbjgwfgmpdfcjfswvqzwdbnvlwfbmdcjvgjcdhjfbjccsjqrgdrhrjnhgpvvfjqvfwqpgmgfsbsnlrfnbtpzljmzrjmjlldgbvvwbnpqgsnzzmswtwgshdlwhsttdjlhnnlgbprwltbppttctttftrmbjccvwtljqffrcpwnwjgcwjnhmphfsnbfdnfbvzqqlwbnjjdvplrjbflcrwjtrngwzznzhsmnwzfbpjrdmjlwzvrvrblrscjlrmswjpbrtjjbsgzwjnfwwgmnbbppqfnlmfsbpwbdnjmrcvqdhhvrrvmghlbbpfsqzsnbjvrvthnrhlttsnlbgvsdvsmncdglrgpsqjqthnlrhnzpnnjgvrnmdnrtjbmlppfppnmgjhtbzpztdmclgbqjzsgfjllplpnnmjhgpcfcpcmbnwjsdmfmrqvqvjfsrnqhbrzdvwcsmmjvqpjnzbgrhwcwggvvjzbrswplgvbbqhdlqptzjvzcznspjbpvfmgbcfjbgmztmqtlzmzzzpmcdmmvhvnphpcfwcmwqwwqvmwpwhhnspmhrdmjblzhhlphwldfclsfjbzhjglvllldnmtjtwqtztfcvjdngslhnsmmlwlpzdbrrthtwfpjfvfljddplfgnhcnwwmmpgwwspnsprsvprccwvvljwbqwrzqjmwfrnnjbrfsrglnrwdfnsswqwsbpplgnfnvvvhqwmtgsdwmvnzmbjpbscdtcrmsllljwlntjzpwqvvnznmfddtgrmqbdsczhtvjdwrwvjccrqnjlnqbvqhhvnmqmrmnqllcjzcjgzwctrntjsnhrwmcqzrwzzqgqlmbqczlgtmtwlztclhwcjsgbdlfrppwrpbnpgsjfhprvzjwnpdwsjwmdcbmljclcgcnsqcpzgvrrbnnhjhblgnpcbzbcdmgjmpmpcwwdngmggmfqcjcwrzblsfmrslbblhdlwjqrrgtnvcfsccbdgnjcztrblrwbrvdzcnnshwzzvgcqwpqmjzhzlllbtzmcqpnwwqqlcjtrrzfmdpmpblmwztwqdgbmtfggjwnmffzvszgdmhfvflthzmwqgqvgmldzpbwbdvrjldhbnzsthqsczttbbthzgzmmrcmzmzmjfrhbtmsbqrbnsnzzfpvwlwpszdptljqphrdznhbwbfdfhsrqnmlqdcdgbrbsmgwwbbjsmwhzgmqtmfbndzlmlvmrrvrmqbjqbhhqtvvgbhbmsrtljwmtnhtpwjvlrgqljvgpsfrwgdfbcwlmvfdrrlgwvvzvcftwpjhcplgwvqbzftjfbmmcpvrrsvbnwqdhtlsfcjzlrmwvgvgwpbffsrrpdpssqhqrqdglnwcqznzlqqvjzpsdnpwfqtfjqhqwvlfpwrqqmntcnnbfprlwrfdwstvbpjmjdbcdffmwvqbsdnvcgrtccvcfzpwjscmrtbbjjnmlcztbldfnwbqcpqlshthrcbdrfldcmhtgwrgqhnnglbzgdgglzjbgjtdvgzgrspjtbhpmzvpplgjpjbthmjtwqqzsslnfrtmpznbqvmccqccrtdvrssmdgrptsjglvrmlcwfllptczvpgwbdfbrnpzdzmpfjwdhqlsqlzlzrwcsmhcmjhhfhfvcdrzhsmqbwcfshslsnswpslbjnrzqllwbnddhrngmjqtnvhrjpcpmggvgqbwtwcmbvhnwggdrzfgmhhvpqzbvlghsvgmhngwdsrwlzffbpzqmfzvbhbjvqlcswhctpcqnptrvlwblnvpfbzsjnsdjnhqbzddsnthhcfbcvmqgfmvztlcwjbmdtgvgwqbqgdrvbgbnbcnqwzfzqpsgbvtwlphgvqlzshndcbffzcbllgzrzrnhdvqnvtndhcdslqbbhcdftlmnltmsmgfcgvmpbsljdbthjtqlfbmczznwcvfcsnftsnpzcwfqbfhjpswzfzfswfgtzplppsglsdncblddsmftmfdmmnsjjgg

50
2022/day6/src/main.rs Normal file
View File

@ -0,0 +1,50 @@
fn find_num_chars_before_marker(chars: &Vec<char>, marker_size: usize) -> usize {
let mut iter = chars.iter().enumerate();
'outer: for (i, _) in &mut iter {
// Look marker_size -1 characters forward so we can check for duplicate characters
let mut cursor: Vec<char> = Vec::new();
for n in 0..marker_size {
cursor.push(*chars.get(i + n).unwrap());
}
cursor.sort_unstable();
// If there's a duplicate character, go forward
for (n, ch) in cursor.iter().enumerate() {
if let Some(other) = cursor.get(n + 1) {
if ch == other {
continue 'outer;
}
}
}
// Since we are looking farther than the current iteration,
// we need to add the marker size that to the returned index
return i + marker_size;
}
panic!("Marker not found");
}
fn find_packet_marker(chars: &Vec<char>) -> usize {
find_num_chars_before_marker(chars, 4)
}
fn find_message_marker(chars: &Vec<char>) -> usize {
find_num_chars_before_marker(chars, 14)
}
fn main() {
let file_str = include_str!("input.txt");
let chars: Vec<char> = file_str.chars().collect();
println!(
"Part 1: Number of characters before start-of-packet marker: {}",
find_packet_marker(&chars)
);
println!(
"Part 2: Number of characters before start-of-message marker: {}",
find_message_marker(&chars)
);
}

8
2022/day7/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day7"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

101
2022/day7/README.md Normal file
View File

@ -0,0 +1,101 @@
# Day 7: No Space Left On Device
## Part 1
You can hear birds chirping and raindrops hitting leaves as the expedition proceeds. Occasionally, you can even hear much louder sounds in the distance; how big do the animals get out here, anyway?
The device the Elves gave you has problems with more than just its communication system. You try to run a system update:
$ system-update --please --pretty-please-with-sugar-on-top
Error: No space left on device
Perhaps you can delete some files to make space for the update?
You browse around the filesystem to assess the situation and save the resulting terminal output (your puzzle input). For example:
$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k
The filesystem consists of a tree of files (plain data) and directories (which can contain other directories or files). The outermost directory is called /. You can navigate around the filesystem, moving into or out of directories and listing the contents of the directory you're currently in.
Within the terminal output, lines that begin with $ are commands you executed, very much like some modern computers:
* cd means change directory. This changes which directory is the current directory, but the specific result depends on the argument:
* cd x moves in one level: it looks in the current directory for the directory named x and makes it the current directory.
* cd .. moves out one level: it finds the directory that contains the current directory, then makes that directory the current directory.
* cd / switches the current directory to the outermost directory, /.
* ls means list. It prints out all of the files and directories immediately contained by the current directory:
* 123 abc means that the current directory contains a file named abc with size 123.
* dir xyz means that the current directory contains a directory named xyz.
Given the commands and output in the example above, you can determine that the filesystem looks visually like this:
- / (dir)
- a (dir)
- e (dir)
- i (file, size=584)
- f (file, size=29116)
- g (file, size=2557)
- h.lst (file, size=62596)
- b.txt (file, size=14848514)
- c.dat (file, size=8504156)
- d (dir)
- j (file, size=4060174)
- d.log (file, size=8033020)
- d.ext (file, size=5626152)
- k (file, size=7214296)
Here, there are four directories: / (the outermost directory), a and d (which are in /), and e (which is in a). These directories also contain files of various sizes.
Since the disk is full, your first step should probably be to find directories that are good candidates for deletion. To do this, you need to determine the total size of each directory. The total size of a directory is the sum of the sizes of the files it contains, directly or indirectly. (Directories themselves do not count as having any intrinsic size.)
The total sizes of the directories above can be found as follows:
- The total size of directory e is 584 because it contains a single file i of size 584 and no other directories.
- The directory a has total size 94853 because it contains files f (size 29116), g (size 2557), and h.lst (size 62596), plus file i indirectly (a contains e which contains i).
- Directory d has total size 24933642.
- As the outermost directory, / contains every file. Its total size is 48381165, the sum of the size of every file.
To begin, find all of the directories with a total size of at most 100000, then calculate the sum of their total sizes. In the example above, these directories are a and e; the sum of their total sizes is 95437 (94853 + 584). (As in this example, this process can count files more than once!)
**Find all of the directories with a total size of at most 100000. What is the sum of the total sizes of those directories?**
## Part 2
Now, you're ready to choose a directory to delete.
The total disk space available to the filesystem is 70000000. To run the update, you need unused space of at least 30000000. You need to find a directory you can delete that will free up enough space to run the update.
In the example above, the total size of the outermost directory (and thus the total amount of used space) is 48381165; this means that the size of the unused space must currently be 21618835, which isn't quite the 30000000 required by the update. Therefore, the update still requires a directory with total size of at least 8381165 to be deleted before it can run.
To achieve this, you have the following options:
* Delete directory e, which would increase unused space by 584.
* Delete directory a, which would increase unused space by 94853.
* Delete directory d, which would increase unused space by 24933642.
* Delete directory /, which would increase unused space by 48381165.
Directories e and a are both too small; deleting them would not free up enough space. However, directories d and / are both big enough! Between these, choose the smallest: d, increasing unused space by 24933642.
**Find the smallest directory that, if deleted, would free up enough space on the filesystem to run the update. What is the total size of that directory?**

1083
2022/day7/src/input.txt Normal file

File diff suppressed because it is too large Load Diff

275
2022/day7/src/main.rs Normal file
View File

@ -0,0 +1,275 @@
#![allow(dead_code)]
use std::collections::HashMap;
const MAX_DIR_SIZE: u128 = 100_000;
const TOTAL_DISK_SPACE: u128 = 70_000_000;
const MIN_SPACE_REQUIRED: u128 = 30_000_000;
#[derive(Debug)]
struct File {
name: String,
size: u128,
}
impl File {
fn new<T: ToString + ?Sized>(size: &T, name: &T) -> Self {
let size = size.to_string().parse::<u128>().unwrap();
let name = name.to_string();
File { name, size }
}
}
// ----------------------------------------------------------------------------
#[derive(Debug)]
struct Dir {
parent: String,
name: String,
files: Vec<File>,
subdirs: Vec<String>,
}
impl Dir {
fn new<T: ToString + ?Sized>(parent: &T, name: &T) -> Self {
Dir {
parent: parent.to_string(),
name: name.to_string(),
files: Vec::new(),
subdirs: Vec::new(),
}
}
fn add_file(&mut self, file: File) {
self.files.push(file);
}
fn add_subdir(&mut self, path: String) {
self.subdirs.push(path);
}
fn get_loose_files_size(&self) -> u128 {
self.files
.iter()
.map(|file| file.size)
.reduce(|accum, item| accum + item)
.unwrap_or(0)
}
}
// ----------------------------------------------------------------------------
#[derive(Debug)]
enum LineType {
Cd(String),
Ls,
Dir(String),
FileAndSize(String, String),
}
use LineType::*;
impl LineType {
fn from(line: &str) -> LineType {
let parts: Vec<&str> = line.split_ascii_whitespace().collect();
match parts[0] {
"$" => match parts[1] {
"cd" => Cd(parts[2].to_string()),
"ls" => Ls,
_ => panic!("Invalid command"),
},
"dir" => Dir(parts[1].to_string()),
_ => FileAndSize(parts[0].to_string(), parts[1].to_string()),
}
}
}
// ----------------------------------------------------------------------------
#[derive(Debug)]
struct DirMap {
current_path: String,
map: HashMap<String, Dir>,
}
impl DirMap {
fn new() -> Self {
let current_path = "/".to_string();
let mut map: HashMap<String, Dir> = HashMap::new();
map.insert(current_path.clone(), Dir::new("", ""));
DirMap { current_path, map }
}
fn cd<T: ToString + ?Sized>(&mut self, new_dir: &T) {
let current_path = self.current_path.clone();
let new = new_dir.to_string();
match new.as_str() {
"/" => {
self.current_path = new.to_string();
}
".." => {
let mut dir_parts: Vec<&str> = current_path.split('/').collect();
let _ = dir_parts.pop();
self.current_path = dir_parts.join("/");
}
_ => {
self.current_path.push('/');
self.current_path.push_str(&new);
}
}
}
fn dir<T: ToString + ?Sized>(&mut self, dir: &T) {
let parent = self.current_path.clone();
let name = dir.to_string();
let mut full_path = parent.clone();
full_path.push('/');
full_path.push_str(&name);
// Add the new Dir to the path map
if !self.map.contains_key(&full_path) {
self.map.insert(full_path.clone(), Dir::new(&parent, &name));
}
// Add the new Dir to the list of subdirectories to the Dir mapped to the current path
self.map
.get_mut(&self.current_path)
.expect(&format!(
"This dir ({}) should already exist",
&self.current_path
))
.add_subdir(full_path.clone());
}
fn parse(&mut self, item: LineType) {
match item {
Cd(s) => self.cd(&s),
Ls => {}
Dir(s) => self.dir(&s),
FileAndSize(size, name) => {
self.map
.get_mut(&self.current_path)
.expect(&format!(
"This dir ({}) should already exist",
&self.current_path
))
.add_file(File::new(&size, &name));
}
}
}
}
// ----------------------------------------------------------------------------
fn get_path_size_map(dir_map: &DirMap) -> HashMap<String, u128> {
let mut size_map: HashMap<String, u128> = HashMap::new();
// Get the sizes of the leaf node directories
dir_map
.map
.iter()
.filter(|(_, v)| v.subdirs.len() == 0)
.for_each(|(k, v)| {
size_map.insert(k.to_string(), v.get_loose_files_size());
});
// Calculate dir sizes by the length of the path from largest to smallest,
// so we can start with the lowest branches of the tree when calculating folder sizes
let mut branch_paths: Vec<&String> = dir_map
.map
.iter()
.filter(|(_, v)| v.subdirs.len() > 0)
.map(|(k, _)| k)
.collect();
branch_paths.sort();
branch_paths.reverse();
branch_paths.into_iter().for_each(|path| {
let dir = dir_map.map.get(path).unwrap();
let base_size = dir.get_loose_files_size();
let subdir_size: u128 = dir
.subdirs
.iter()
.map(|sub| {
*size_map
.get(sub)
.expect("Dir {} should already have had its size calculated")
})
.reduce(|accum, item| accum + item)
.unwrap_or(0);
size_map.insert(path.to_string(), base_size + subdir_size);
});
size_map
}
fn calculate_needed_space(used_space: u128) -> u128 {
MIN_SPACE_REQUIRED - (TOTAL_DISK_SPACE - used_space)
}
fn find_size_of_dir(min_size: u128, size_map: &HashMap<String, u128>) -> u128 {
size_map
.iter()
.map(|(_, v)| *v)
.filter(|v| *v > min_size)
.min()
.unwrap()
}
fn calculate_sum_of_dirs(size_map: &HashMap<String, u128>) -> u128 {
size_map
.iter()
.filter(|(_, v)| **v < MAX_DIR_SIZE)
.fold(0u128, |acc, (_, v)| acc + *v)
}
fn main() {
let file_str = include_str!("input.txt");
let mut path_map = DirMap::new();
file_str
.lines()
.map(|line| LineType::from(line))
.for_each(|cmd| path_map.parse(cmd));
let size_map = get_path_size_map(&path_map);
let size_sum = calculate_sum_of_dirs(&size_map);
let used_space = *size_map.get("/").unwrap();
let smallest_dir = find_size_of_dir(calculate_needed_space(used_space), &size_map);
println!("Part 1: Sum of dirs 100K or smaller {:#?}", size_sum);
println!("Part 2: Size of smallest dir to delete: {}", smallest_dir);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_size_of_dir() {
let mut size_map: HashMap<String, u128> = HashMap::new();
size_map.insert("//e".to_string(), 584);
size_map.insert("//a".to_string(), 94853);
size_map.insert("//d".to_string(), 24933642);
size_map.insert("/".to_string(), 48381165);
let res = find_size_of_dir(8381165, &size_map);
assert_eq!(res, 24933642);
}
#[test]
fn test_calculate_needed_space() {
let res = calculate_needed_space(48381165);
assert_eq!(res, 8381165);
}
}

9
2022/day8/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "day8"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aoc-shared = { path = "../aoc-shared"}

73
2022/day8/README.md Normal file
View File

@ -0,0 +1,73 @@
# Day 8: Treetop Tree House
## Part 1
The expedition comes across a peculiar patch of tall trees all planted carefully in a grid. The Elves explain that a previous expedition planted these trees as a reforestation effort. Now, they're curious if this would be a good location for a tree house.
First, determine whether there is enough tree cover here to keep a tree house **hidden**. To do this, you need to count the number of trees that are **visible from outside the grid** when looking directly along a row or column.
The Elves have already launched a quadcopter to generate a map with the height of each tree (your puzzle input). For example:
30373
25512
65332
33549
35390
Each tree is represented as a single digit whose value is its height, where 0 is the shortest and 9 is the tallest.
A tree is **visible** if all of the other trees between it and an edge of the grid are **shorter** than it. Only consider trees in the same row or column; that is, only look up, down, left, or right from any given tree.
All of the trees around the edge of the grid are **visible** - since they are already on the edge, there are no trees to block the view. In this example, that only leaves the **interior nine trees** to consider:
* The top-left 5 is **visible** from the left and top. (It isn't visible from the right or bottom since other trees of height 5 are in the way.)
* The top-middle 5 is **visible** from the top and right.
* The top-right 1 is not visible from any direction; for it to be visible, there would need to only be trees of height **0** between it and an edge.
* The left-middle 5 is **visible**, but only from the right.
* The center 3 is not visible from any direction; for it to be visible, there would need to be only trees of at most height 2 between it and an edge.
* The right-middle 3 is **visible** from the right.
* In the bottom row, the middle 5 is **visible**, but the 3 and 4 are not.
With 16 trees visible on the edge and another 5 visible in the interior, a total of 21 trees are visible in this arrangement.
**Consider your map; how many trees are visible from outside the grid?**
## Part 2
Content with the amount of tree cover available, the Elves just need to know the best spot to build their tree house: they would like to be able to see a lot of trees.
To measure the viewing distance from a given tree, look up, down, left, and right from that tree; stop if you reach an edge or at the first tree that is the same height or taller than the tree under consideration. (If a tree is right on the edge, at least one of its viewing distances will be zero.)
The Elves don't care about distant trees taller than those found by the rules above; the proposed tree house has large eaves to keep it dry, so they wouldn't be able to see higher than the tree house anyway.
In the example above, consider the middle 5 in the second row:
30373
25512
65332
33549
35390
* Looking up, its view is not blocked; it can see 1 tree (of height 3).
* Looking left, its view is blocked immediately; it can see only 1 tree (of height 5, right next to it).
* Looking right, its view is not blocked; it can see 2 trees.
* Looking down, its view is blocked eventually; it can see 2 trees (one of height 3, then the tree of height 5 that blocks its view).
A tree's scenic score is found by multiplying together its viewing distance in each of the four directions. For this tree, this is 4 (found by multiplying 1 * 1 * 2 * 2).
However, you can do even better: consider the tree of height 5 in the middle of the fourth row:
30373
25512
65332
33549
35390
* Looking up, its view is blocked at 2 trees (by another tree with a height of 5).
* Looking left, its view is not blocked; it can see 2 trees.
* Looking down, its view is also not blocked; it can see 1 tree.
* Looking right, its view is blocked at 2 trees (by a massive tree of height 9).
This tree's scenic score is 8 (2 * 2 * 1 * 2); this is the ideal spot for the tree house.
Consider each tree on your map. **What is the highest scenic score possible for any tree?**

99
2022/day8/src/input.txt Normal file
View File

@ -0,0 +1,99 @@
211332213033101124130110410025404035324540506465522424325025442423205322144201114032433102223133301
311023320242030112033354205533003100224166354233554634221041635230051410343235342432112434034030100
001223204433022013103305410222315554032366506021405002315044463420051033302201255133143124420412122
013132233012344225535033304112253201303421563422623305021204605543621044544210352330412212401012131
123203213200414113431324051024435265606056206220330353405664413252121241340014021504043322022404322
300314334303200324110001011065050624136654044030061620050042314252632633325011034021521210022442213
300312304313121233203544305130444460463436450145663611020201513406316245230444434551201440322230302
121213330224031553422231036233163250606241600057176176344004346462440003006410044502531341130240114
301324240431503125500116062453142425154655731122643437177477550414605433012615301235013252120302340
003232040401112004305510155520121504621467762731313536577767114335412665224212525123530315344321124
020011211014152120140622132315236133565515235564134376673433256457543305603063000545505055054420401
120232244154134255122415053246324763251764537642172244222741232566733246632230131225000041540131403
340032215420250553142064146064564173357273533153247735663417273646632371434553560636420004452544143
043414443322552422161330440067615566131775467414772511621257632542341175313336105314043250123012200
012111021442304652102413106134662444516476275112834287667673516365611433432545515260120211024041202
032102521544554062032010572477745124332575337882847632625227237576235753415421361112101043554053100
311444312333365122206150371721763624374376873885257652577482877454566142635223501265056342151423503
144251432134413522432634164521765222778875228537684473757528335574576764563372055450540131505303034
000255023251250523115357427615753523575838766845363763466455836854431647317161446453545305422435355
245002340133321145325367575315512257574665372575562748686454783577847666453745464626164131031332100
050553025366530325021416326145857322624322772785872882346577742678858344161622134432426516051344250
152311521001545435344376115464326457845848454437444432763844343744467358574522513450314302061503452
432454304206244265363237124475585684786823237698738473868377345823852284311544625730363140211242142
454020453313433443537657634364823277466449658493374864768899457268665377243765726567464021363445250
552431324265025566426217457328875767435899547855738449793664649385627243287213716374361136462440243
031052136256223525442167246873557667773568893448343999893549698865743526327856612255315524012102000
345323665312406654514446384583427637865769666594853994657493368533935635676521153437537311305202142
342110244050561175476152877378374945653376889649978659538759435748334872266574665131763066015150414
145433434262576274652174742347844566354377337849447759743936477456984862853785777171357505003212025
310242523113472175765257374582489598876797985649454666865333776554339348242882833175411762344652012
434056456416337446635277274487757585458766758586996458774953698859555746353645282477417311113216435
045021105500376267478536827836355597677975786498896678587684858536744539776275465227567675153251405
300142642025442446482242442484398879535896799784784778494989949379689755588234538855243763305416321
353622636633651765254457642339454687946896697548485487765646998666995567567726837277556747624363451
202435626512143732835284377793378475946599964657457656969997944856356445774883877827536725303005505
135650034646464156744647526498458647549464945549765974544889665765659884799642263733421214426362624
150435334074657468688563599355379375877984576587798777599554755799738577897957837453257132312302144
512443536422754252577234434969994856586456545889988865785958887667666384435563246262331235420111143
466652116227352685834266983738374448949754669575866999669685556447597478636534623278751113456645060
021164506132145534653735865996437996949669685788777975556657797445847474955965558246253533611024642
231050262356423276576326937834369549887967896966756856658985767688875977398375688846413232324304226
435212106653324768273769678978879679954786766976999558656777959955869577458834883774845467247506214
160366254415742474477255579484597574496859676569755788769767586676674847997944768266836256767533110
241513312227373552852675497876868858749576878555778658557589787666975955754559662763784164711060064
351110451267671255426564695657766766686759856878789989756858799968497958544598723587586767222266454
316062153252225354662464658785786565488858687886778777967566595898554596936489753547456317121214424
212536666162371857232636965378959948576758567679878996998888878797474958786685542845571126616220264
510024546261143787272349466837799649568665658866988878698565865894746985377749787572341577611344166
004351216364728646844848837567468684779987996888767898677985599854955668566559858835633322134522334
336463436447757363543649949947564678786988588988866877968758989665477866657945447564627357126653146
026065162577657624222467836757949464596556769778678999898769595755945784554668326364364774614112042
503221631577514777533445365468588455658986887687687789867975758885748889857396423825776253156736650
546513661435242553764893754934757584678877997789877686967898678564676598335965867335727137112215030
611265646576763532336777659499858694897877758999678876979977887874768566899568336424484421461153426
354632527555434648642259948845976658869997857679769998977895558994584876439733545486722237134252244
520066365142477526347774786479494548687879769997669786998678978895445886967346756354286727222124503
036426316533162875778686487545896556958758868879977868686688986574849753898677468557551537174650421
560265634575463724567588788767856667457699558755596657566679586798788873437533663746231724155125525
154560626115545678446889538386759776485985597568577777558958786887687647784334647726551367164130624
435604614267661345622839365943384759557699679885767759599566796964556464635883224855517743254442610
015330201727631536234389975658784474799697966578756955569957997995994446883848582283235113446522166
352230033476456648636532764835957899749588885668565677958598595585884536843566635235535143233400362
154324641154514622554238347338736749648497879886988865566875744965765539565765428586545254520653004
453036521326216338225852566856869755589995557886678566578454876595677374667726383554235644733043120
255116155525323462526438743774389777499948654465588776697977856998545943966845458742427155331033531
025560625413477123376683438634566738565665455954779575658546654745567665935272473226176343466230234
024466546555224254763532784959665896878967666774886569787656978898736887735524866681527476335351660
431553605003462632355435287785653379467565865846957764769957785898849746583877462511543675401304331
245166660214751253743856378267388633494584489567844846476445548983654883554368632374551522612226505
540335146233545626252387487873545495675665748448745979949594735654895943368867237133447443126433414
234255620120615565122843883767337363659787964676878598696674776783394766454355878652417710601552535
155234425620263264536252385765564357733857634857584669678763477778599626835456677357151640115601402
415011642631335751527728632365876445738339479934933867368973986563564488774233653717376514142421112
331553124665647777751514436356443477749885879596563793484897353687466437233338475237523161110142051
125403316650422145565532565656426288343597345985455577884935753554564626425235737254643554446160112
244245221040325667524534344843767845646457957737955963874753776775484255785447725731356435212213414
502435004653346035253622224342447486734347953679733888847856349544574634822773162422363261331201024
324222044306505016426445557827266762373537588855883779693953564587846832687121422621334643504041214
242441310622432165134457161657567575877727367394894947493553362876526782815233251471504221505502531
404413131464141606677317644575735753536548433834477734384655752565382465763337735513154564140342251
301100110415420444111615617662387653344875842557335485555688447688575465433323177644556524120212234
121350153052662132322721116134216553883566368426252878468274827563855654437763154152652520055535413
300411255204026610413574577661773545843284364682683778487466278862352135457325560155622450041155414
201513150243444362415017756317333176455677876825338686288332246436653511332623525023535335010251403
442151212200240012240515354421652475542422627327336365453756577274176715121634500306606230505005442
221142355114024136331532344422671215757576745773483847686535252141745132161123140234155444022141343
303111241400254212624566606371413763653433175765433383216314527571326314157614031441404441454123113
244200502534242261362202215053674434622174351252464554756217534657676575631240166556655421245234022
033140410031001244605126654665654443346166177754221527272665473526726632645640155606531431321003203
333144020203540344460212034601443662327775175627432461421467275253741652534221451541150344324122432
003441144232331144321240262132134156264312772115415535174111161372132213423063330000551314401242014
431244213034140532345020014016302213467251277744712151733426334265042000625105541402423314424042442
032332242311014553503456362533135654462331252577334743117656122022210110152631423434352520024421043
102103002322052451100230340420161635556642503226271246652053202351054222634613532434255202434131242
203130013133233045044204223404060632403351664241443631454330322650226245651432113040525413323340210
030124200340221230241225521446452652313241114064226552054332165233441366221221035421132414124314402
120112413030344114412231514332254000023525634236200334160045616312416360423100451201322404023012301
212011312011233130523111525121303414244121320644050343211556336246463215444025331411002041412122121
002023323443102242311523000140150506160522004635222556200251663551444551235250440223242010414011021

339
2022/day8/src/main.rs Normal file
View File

@ -0,0 +1,339 @@
use aoc_shared::impl_grid_newtype;
use aoc_shared::grid::Grid as BaseGrid;
use std::collections::HashSet;
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Hash)]
enum VisibleDirection {
Top,
Bottom,
Left,
Right,
}
use VisibleDirection::*;
#[derive(Debug, Default)]
struct Tree {
height: usize,
visible: HashSet<VisibleDirection>,
}
impl Tree {
fn new(height: usize) -> Self {
Tree {
height,
..Tree::default()
}
}
fn is_visible(&self) -> bool {
!self.visible.is_empty()
}
fn set_visible(&mut self, dir: VisibleDirection) -> &mut Self {
self.visible.insert(dir);
self
}
fn set_all_visible(&mut self) -> &mut Self {
self.set_visible(Top)
.set_visible(Bottom)
.set_visible(Left)
.set_visible(Right)
}
}
// ----------------------------------------------------------------------------
// Here is the trick for using a library type as if it were
// local (so you can directly implement methods).
// 1. Wrap the type in a unit struct
// 2. Implement the Deref trait for the wrapped struct
#[derive(Debug)]
pub struct Grid<T>(BaseGrid<T>);
impl_grid_newtype!(Grid, BaseGrid<Tree>, Tree);
impl Grid<Tree> {
pub fn from_file_str(file_str: &'static str) -> Grid<Tree> {
let lines: Vec<&str> = file_str.lines().collect();
let width = lines[0].len();
let mut grid: Grid<Tree> = Grid::new(width);
for line in lines {
let mut row: Vec<Tree> = line
.chars()
.map(|ch| Tree::new(ch.to_digit(10).unwrap() as usize))
.collect();
grid.vec.append(&mut row);
}
grid
}
fn mark_outer_trees_visible(&mut self) -> &mut Self {
fn set_row_visible(row: &mut [Tree]) {
row.iter_mut().for_each(|tree| {
tree.set_all_visible();
})
}
// Set top/bottom rows as visible
set_row_visible(self.get_row(0));
let last_row = self.num_rows() - 1;
set_row_visible(self.get_row(last_row));
// Set left/right cols as visible
self.get_column_indexes(0).into_iter().for_each(|id| {
self.vec[id].set_all_visible();
});
self.get_column_indexes(self.num_cols() - 1)
.into_iter()
.for_each(|id| {
self.vec[id].set_all_visible();
});
self
}
fn mark_visible(&mut self, dir: VisibleDirection) -> &mut Self {
let indexes: Vec<Vec<usize>> = match dir {
Top | Bottom => {
// Skip outer columns, as those are already marked visible
(1..(self.num_cols() - 1))
.map(|c| self.get_column_indexes(c))
.map(|column| {
if dir == Bottom {
column.into_iter().rev().collect()
} else {
column
}
})
.collect()
}
Left | Right => {
// Skip first and last rows, as those are already marked visible
(1..(self.num_rows() - 1))
.map(|r| self.get_row_indexes(r))
.map(|row| {
if dir == Right {
row.into_iter().rev().collect()
} else {
row
}
})
.collect()
}
};
for row_or_col in indexes {
let mut tallest = 0usize;
for idx in row_or_col {
let tree = self.get_mut(idx).unwrap();
if tallest < tree.height {
tree.set_visible(dir);
tallest = tree.height;
}
}
}
self
}
pub fn mark_visible_trees(&mut self) {
self.mark_outer_trees_visible()
.mark_visible(Top)
.mark_visible(Right)
.mark_visible(Bottom)
.mark_visible(Left);
}
pub fn get_visible_trees(&self) -> usize {
self.vec
.iter()
.filter(|tree| tree.is_visible())
.collect::<Vec<&Tree>>()
.len()
}
fn get_surrounding_trees(
&self,
reference: usize,
) -> (Vec<usize>, Vec<usize>, Vec<usize>, Vec<usize>) {
let (x, y) = self.idx_xy(reference);
let mut top = self.get_column_indexes(x); // col[0..=x]
let bottom = top.split_off(y + 1); // col[(x+1)..]
let mut left = self.get_row_indexes(y); // row[0..=y]
let right = left.split_off(x + 1); // row[(y+1)..]
// Remove the index for the current tree
let _ = top.pop();
let _ = left.pop();
// Reverse the top and left so the perspective is from the reference
top.reverse();
left.reverse();
(top, right, bottom, left)
}
fn get_viewing_distances(&self, reference: usize) -> [usize; 4] {
let (t, r, b, l) = self.get_surrounding_trees(reference);
let ref_tree_height = self.get(reference).unwrap().height;
[t, r, b, l]
.iter()
.map(|search| {
let mut count = 0usize;
for i in search {
let height = match self.get(*i) {
Some(h) => h.height,
None => 0,
};
count += 1;
if ref_tree_height <= height {
break;
}
}
count
})
.collect::<Vec<usize>>()
.try_into()
.unwrap()
}
fn get_scenic_score(&self, reference: usize) -> usize {
let [t, r, b, l] = self.get_viewing_distances(reference);
t * r * b * l
}
pub fn get_max_scenic_score(&self) -> usize {
self.vec
.iter()
.enumerate()
.map(|(idx, _)| idx)
.map(|idx| self.get_scenic_score(idx))
.max()
.unwrap()
}
}
// ----------------------------------------------------------------------------
fn main() {
let file_str = include_str!("input.txt");
let mut grid = Grid::from_file_str(file_str);
grid.mark_visible_trees();
let visible_num = grid.get_visible_trees();
let scenic_score = grid.get_max_scenic_score();
println!("Part 1: Number of visible trees: {}", visible_num);
println!("Part 2: Max scenic score: {}", scenic_score);
}
#[cfg(test)]
mod tests {
use super::*;
fn get_data() -> &'static str {
include_str!("test-input.txt")
}
#[test]
fn test_row_first_index() {
let grid = Grid::from_file_str(get_data());
assert_eq!(grid.row_first_idx(1), 5);
assert_eq!(grid.row_first_idx(0), 0);
assert_eq!(grid.row_first_idx(2), 10);
}
#[test]
fn test_row_last_index() {
let grid = Grid::from_file_str(get_data());
assert_eq!(grid.row_last_idx(0), 4);
assert_eq!(grid.row_last_idx(1), 9);
}
#[test]
fn test_get_column_indexes() {
let grid = Grid::from_file_str(get_data());
assert_eq!(grid.num_cols(), 5);
assert_eq!(grid.get_column_indexes(0), vec![0, 5, 10, 15, 20]);
assert_eq!(grid.get_column_indexes(1), vec![1, 6, 11, 16, 21]);
assert_eq!(grid.get_column_indexes(4), vec![4, 9, 14, 19, 24]);
}
#[test]
fn test_outer_visible_trees() {
let mut grid = Grid::from_file_str(get_data());
grid.mark_outer_trees_visible();
assert_eq!(grid.get_visible_trees(), 16usize);
}
#[test]
fn test_visible_trees() {
let mut grid = Grid::from_file_str(get_data());
grid.mark_visible_trees();
let visible = [(1usize, 1usize), (2, 1), (1, 2), (4, 3), (2, 3)];
for (x, y) in visible {
let idx = grid.xy_idx(x, y);
assert!(
grid.vec[idx].is_visible(),
"Tree {}({},{}) should be visible: {:#?}",
idx,
x,
y,
grid.vec[idx]
);
}
assert_eq!(grid.get_visible_trees(), 21usize);
}
#[test]
fn test_get_surrounding_trees() {
let grid = Grid::from_file_str(get_data());
let (t, r, b, l) = grid.get_surrounding_trees(7);
assert_eq!(t, vec![2]);
assert_eq!(r, vec![8, 9]);
assert_eq!(b, vec![12, 17, 22]);
assert_eq!(l, vec![6, 5]);
}
#[test]
fn test_get_viewing_distances() {
let grid = Grid::from_file_str(get_data());
assert_eq!(grid.get_viewing_distances(7), [1, 2, 2, 1]);
assert_eq!(grid.get_viewing_distances(17), [2, 2, 1, 2]);
}
#[test]
fn test_get_scenic_score() {
let grid = Grid::from_file_str(get_data());
assert_eq!(grid.get_scenic_score(7), 4);
assert_eq!(grid.get_scenic_score(17), 8);
assert_eq!(grid.get_max_scenic_score(), 8);
}
}

View File

@ -0,0 +1,5 @@
30373
25512
65332
33549
35390

9
2022/day9/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "day9"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aoc-shared = { path = "../aoc-shared"}

684
2022/day9/README.md Normal file
View File

@ -0,0 +1,684 @@
# Day 9: Rope Bridge
## Part 1
This rope bridge creaks as you walk along it. You aren't sure how old it is, or whether it can even support your weight.
It seems to support the Elves just fine, though. The bridge spans a gorge which was carved out by the massive river far below you.
You step carefully; as you do, the ropes stretch and twist. You decide to distract yourself by modeling rope physics; maybe you can even figure out where not to step.
Consider a rope with a knot at each end; these knots mark the head and the tail of the rope. If the head moves far enough away from the tail, the tail is pulled toward the head.
Due to nebulous reasoning involving Planck lengths, you should be able to model the positions of the knots on a two-dimensional grid. Then, by following a hypothetical series of motions (your puzzle input) for the head, you can determine how the tail will move.
Due to the aforementioned Planck lengths, the rope must be quite short; in fact, the head (H) and tail (T) must always be touching (diagonally adjacent and even overlapping both count as touching):
....
.TH.
....
....
.H..
..T.
....
...
.H. (H covers T)
...
If the head is ever two steps directly up, down, left, or right from the tail, the tail must also move one step in that direction so it remains close enough:
..... ..... .....
.TH.. -> .T.H. -> ..TH.
..... ..... .....
... ... ...
.T. .T. ...
.H. -> ... -> .T.
... .H. .H.
... ... ...
Otherwise, if the head and tail aren't touching and aren't in the same row or column, the tail always moves one step diagonally to keep up:
..... ..... .....
..... ..H.. ..H..
..H.. -> ..... -> ..T..
.T... .T... .....
..... ..... .....
..... ..... .....
..... ..... .....
..H.. -> ...H. -> ..TH.
.T... .T... .....
..... ..... .....
You just need to work out where the tail goes as the head follows a series of motions. Assume the head and the tail both start at the same position, overlapping.
For example:
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2
This series of motions moves the head right four steps, then up four steps, then left three steps, then down one step, and so on. After each step, you'll need to update the position of the tail if the step means the head is no longer adjacent to the tail. Visually, these motions occur as follows (s marks the starting position as a reference point):
== Initial State ==
......
......
......
......
H..... (H covers T, s)
== R 4 ==
......
......
......
......
TH.... (T covers s)
......
......
......
......
sTH...
......
......
......
......
s.TH..
......
......
......
......
s..TH.
== U 4 ==
......
......
......
....H.
s..T..
......
......
....H.
....T.
s.....
......
....H.
....T.
......
s.....
....H.
....T.
......
......
s.....
== L 3 ==
...H..
....T.
......
......
s.....
..HT..
......
......
......
s.....
.HT...
......
......
......
s.....
== D 1 ==
..T...
.H....
......
......
s.....
== R 4 ==
..T...
..H...
......
......
s.....
..T...
...H..
......
......
s.....
......
...TH.
......
......
s.....
......
....TH
......
......
s.....
== D 1 ==
......
....T.
.....H
......
s.....
== L 5 ==
......
....T.
....H.
......
s.....
......
....T.
...H..
......
s.....
......
......
..HT..
......
s.....
......
......
.HT...
......
s.....
......
......
HT....
......
s.....
== R 2 ==
......
......
.H.... (H covers T)
......
s.....
......
......
.TH...
......
s.....
After simulating the rope, you can count up all of the positions the tail visited at least once. In this diagram, s again marks the starting position (which the tail also visited) and # marks other positions the tail visited:
..##..
...##.
.####.
....#.
s###..
So, there are 13 positions the tail visited at least once.
Simulate your complete hypothetical series of motions. **How many positions does the tail of the rope visit at least once?**
## Part 2 ##
A rope snaps! Suddenly, the river is getting a lot closer than you remember. The bridge is still there, but some of the ropes that broke are now whipping toward you as you fall through the air!
The ropes are moving too quickly to grab; you only have a few seconds to choose how to arch your body to avoid being hit. Fortunately, your simulation can be extended to support longer ropes.
Rather than two knots, you now must simulate a rope consisting of ten knots. One knot is still the head of the rope and moves according to the series of motions. Each knot further down the rope follows the knot in front of it using the same rules as before.
Using the same series of motions as the above example, but with the knots marked H, 1, 2, ..., 9, the motions now occur as follows:
== Initial State ==
......
......
......
......
H..... (H covers 1, 2, 3, 4, 5, 6, 7, 8, 9, s)
== R 4 ==
......
......
......
......
1H.... (1 covers 2, 3, 4, 5, 6, 7, 8, 9, s)
......
......
......
......
21H... (2 covers 3, 4, 5, 6, 7, 8, 9, s)
......
......
......
......
321H.. (3 covers 4, 5, 6, 7, 8, 9, s)
......
......
......
......
4321H. (4 covers 5, 6, 7, 8, 9, s)
== U 4 ==
......
......
......
....H.
4321.. (4 covers 5, 6, 7, 8, 9, s)
......
......
....H.
.4321.
5..... (5 covers 6, 7, 8, 9, s)
......
....H.
....1.
.432..
5..... (5 covers 6, 7, 8, 9, s)
....H.
....1.
..432.
.5....
6..... (6 covers 7, 8, 9, s)
== L 3 ==
...H..
....1.
..432.
.5....
6..... (6 covers 7, 8, 9, s)
..H1..
...2..
..43..
.5....
6..... (6 covers 7, 8, 9, s)
.H1...
...2..
..43..
.5....
6..... (6 covers 7, 8, 9, s)
== D 1 ==
..1...
.H.2..
..43..
.5....
6..... (6 covers 7, 8, 9, s)
== R 4 ==
..1...
..H2..
..43..
.5....
6..... (6 covers 7, 8, 9, s)
..1...
...H.. (H covers 2)
..43..
.5....
6..... (6 covers 7, 8, 9, s)
......
...1H. (1 covers 2)
..43..
.5....
6..... (6 covers 7, 8, 9, s)
......
...21H
..43..
.5....
6..... (6 covers 7, 8, 9, s)
== D 1 ==
......
...21.
..43.H
.5....
6..... (6 covers 7, 8, 9, s)
== L 5 ==
......
...21.
..43H.
.5....
6..... (6 covers 7, 8, 9, s)
......
...21.
..4H.. (H covers 3)
.5....
6..... (6 covers 7, 8, 9, s)
......
...2..
..H1.. (H covers 4; 1 covers 3)
.5....
6..... (6 covers 7, 8, 9, s)
......
...2..
.H13.. (1 covers 4)
.5....
6..... (6 covers 7, 8, 9, s)
......
......
H123.. (2 covers 4)
.5....
6..... (6 covers 7, 8, 9, s)
== R 2 ==
......
......
.H23.. (H covers 1; 2 covers 4)
.5....
6..... (6 covers 7, 8, 9, s)
......
......
.1H3.. (H covers 2, 4)
.5....
6..... (6 covers 7, 8, 9, s)
Now, you need to keep track of the positions the new tail, 9, visits. In this example, the tail never moves, and so it only visits 1 position. However, be careful: more types of motion are possible than before, so you might want to visually compare your simulated rope to the one above.
Here's a larger example:
R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20
These motions occur as follows (individual steps are not shown):
== Initial State ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........H.............. (H covers 1, 2, 3, 4, 5, 6, 7, 8, 9, s)
..........................
..........................
..........................
..........................
..........................
== R 5 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........54321H......... (5 covers 6, 7, 8, 9, s)
..........................
..........................
..........................
..........................
..........................
== U 8 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
................H.........
................1.........
................2.........
................3.........
...............54.........
..............6...........
.............7............
............8.............
...........9.............. (9 covers s)
..........................
..........................
..........................
..........................
..........................
== L 8 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
........H1234.............
............5.............
............6.............
............7.............
............8.............
............9.............
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................
== D 3 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
.........2345.............
........1...6.............
........H...7.............
............8.............
............9.............
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................
== R 17 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
................987654321H
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................
== D 10 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........s.........98765
.........................4
.........................3
.........................2
.........................1
.........................H
== L 25 ==
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
H123456789................
== U 20 ==
H.........................
1.........................
2.........................
3.........................
4.........................
5.........................
6.........................
7.........................
8.........................
9.........................
..........................
..........................
..........................
..........................
..........................
...........s..............
..........................
..........................
..........................
..........................
..........................
Now, the tail (9) visits 36 positions (including s) at least once:
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
..........................
#.........................
#.............###.........
#............#...#........
.#..........#.....#.......
..#..........#.....#......
...#........#.......#.....
....#......s.........#....
.....#..............#.....
......#............#......
.......#..........#.......
........#........#........
.........########.........
Simulate your complete series of motions on a larger rope with ten knots. **How many positions does the tail of the rope visit at least once?**

2000
2022/day9/src/input.txt Normal file

File diff suppressed because it is too large Load Diff

198
2022/day9/src/main.rs Normal file
View File

@ -0,0 +1,198 @@
use std::collections::HashSet;
use aoc_shared::{Location, Direction};
use aoc_shared::Direction::*;
struct Move {
dir: Direction,
amount: isize,
}
impl Move {
fn from_line(line: &str) -> Self {
let parts: Vec<&str> = line.split_ascii_whitespace().collect();
let dir = match parts[0] {
"U" => Up,
"D" => Down,
"L" => Left,
"R" => Right,
_ => panic!("Invalid direction!"),
};
let amount = parts[1].parse::<isize>().unwrap();
Move { dir, amount }
}
}
// ---------------------------------------------------------------------------
#[derive(Debug, Default)]
struct Rope {
knots: Vec<Location>,
knot_count: usize,
head_visited: HashSet<Location>,
tail_visited: HashSet<Location>,
}
impl Rope {
pub fn new(knot_count: usize) -> Self {
let mut rope = Self::default();
rope.knot_count = knot_count;
rope.head_visited.insert(Location::default());
rope.tail_visited.insert(Location::default());
rope.knots.resize_with(knot_count, Location::default);
rope
}
pub fn get_knot(&self, idx: usize) -> Location {
self.knots[idx]
}
pub fn is_tail(&self, idx: usize) -> bool {
idx == (self.knot_count - 1)
}
pub fn move_head(&mut self, moves: Move) {
for _ in 0..moves.amount {
let mut x = self.knots[0].x;
let mut y = self.knots[0].y;
match moves.dir {
Up => {
y += 1;
}
Down => {
y -= 1;
}
Left => {
x -= 1;
}
Right => {
x += 1;
}
}
let to = Location::new(x, y);
self.knots[0] = to;
for i in 1..self.knot_count {
self.move_knot(i, i - 1);
}
}
}
fn must_move(&mut self, current: usize, prev: usize) -> bool {
let distance = self.get_knot(current).get_distance(self.get_knot(prev));
distance >= 2.0
}
fn move_knot(&mut self, c: usize, p: usize) {
if !self.must_move(c, p) {
return;
}
let mut current = self.get_knot(c);
let prev = self.get_knot(p);
if current.y != prev.y {
if prev.y - current.y < 0 {
current.y -= 1;
} else {
current.y += 1;
}
}
if current.x != prev.x {
if prev.x - current.x < 0 {
current.x -= 1;
} else {
current.x += 1;
}
}
self.knots[c] = current;
if self.is_tail(c) {
self.tail_visited.insert(current);
}
}
fn get_tail_pos_count(&self) -> usize {
self.tail_visited.len()
}
}
// ----------------------------------------------------------------------------
fn main() {
let file_str = include_str!("input.txt");
let mut rope = Rope::new(2);
file_str
.lines()
.map(Move::from_line)
.for_each(|m| rope.move_head(m));
let tail_positions = rope.get_tail_pos_count();
println!(
"Part 1: Number of tail movements with 2 knots: {}",
tail_positions
);
let mut rope = Rope::new(10);
file_str
.lines()
.map(Move::from_line)
.for_each(|m| rope.move_head(m));
let tail_positions = rope.get_tail_pos_count();
println!(
"Part 2: Number of tail movements with 10 knots: {}",
tail_positions
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_location_get_distance() {
let a = Location::new(0, 0);
assert_eq!(a.get_distance(Location::new(0, 0)), 0.0);
assert_eq!(a.get_distance(Location::new(1, 0)), 1.0);
assert_eq!(a.get_distance(Location::new(1, 1)), 2.0f64.sqrt());
}
#[test]
fn test_get_tail_position_count() {
let file_str = include_str!("test-input.txt");
let mut rope = Rope::new(2);
file_str
.lines()
.map(Move::from_line)
.for_each(|m| rope.move_head(m));
assert_eq!(rope.get_tail_pos_count(), 13);
}
#[test]
fn test_get_tail_position_count_10_knots() {
let file_str = include_str!("test-input2.txt");
let mut rope = Rope::new(10);
file_str
.lines()
.map(Move::from_line)
.for_each(|m| rope.move_head(m));
assert_eq!(rope.get_tail_pos_count(), 36);
}
}

View File

@ -0,0 +1,8 @@
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2

View File

@ -0,0 +1,8 @@
R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20