This commit is contained in:
BlackDemonFire 2023-12-15 12:35:50 +01:00
parent 9d8c5708fc
commit dd5792817e
Signed by: lucy
SSH key fingerprint: SHA256:5NG0Um+vQQHuWkYn+Vd84YFm10edFBJiOIpOuHjl8UE
12 changed files with 395 additions and 0 deletions

15
Cargo.lock generated
View file

@ -2,6 +2,10 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aoc_utils"
version = "0.1.0"
[[package]]
name = "d01t1"
version = "0.1.0"
@ -73,3 +77,14 @@ version = "0.1.0"
[[package]]
name = "d09t2"
version = "0.1.0"
[[package]]
name = "d10t1"
version = "0.1.0"
dependencies = [
"aoc_utils",
]
[[package]]
name = "d10t2"
version = "0.1.0"

View file

@ -2,6 +2,7 @@
resolver = "2"
members = [
"aoc_utils",
"d01t1",
"d01t2",
"d02t1",
@ -20,4 +21,6 @@ members = [
"d08t2",
"d09t1",
"d09t2",
"d10t1",
"d10t2",
]

8
aoc_utils/Cargo.toml Normal file
View file

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

33
aoc_utils/src/lib.rs Normal file
View file

@ -0,0 +1,33 @@
#[must_use]
pub fn dec_if_pos(input: usize) -> usize {
if input > 0 {
input - 1
} else {
input
}
}
#[must_use]
pub fn inc_if_lt(input: usize, max: usize) -> usize {
if input < max {
input + 1
} else {
input
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_dec() {
assert_eq!(dec_if_pos(0), 0);
assert_eq!(dec_if_pos(1), 0);
}
#[test]
fn test_inc() {
assert_eq!(inc_if_lt(3, 3), 3);
assert_eq!(inc_if_lt(2, 3), 3);
}
}

9
d10t1/Cargo.toml Normal file
View file

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

5
d10t1/demo_input.txt Normal file
View file

@ -0,0 +1,5 @@
..F7.
.FJ|.
SJ.L7
|F--J
LJ...

94
d10t1/src/main.rs Normal file
View file

@ -0,0 +1,94 @@
use std::fs::read_to_string;
fn main() {
let input = read_to_string("input.txt").unwrap();
println!("d10t1: {}", d10t1(&input));
}
pub fn d10t1(input: &str) -> isize {
let field = input
.lines()
.map(str::chars)
.map(std::iter::Iterator::collect::<Vec<_>>)
.collect::<Vec<_>>();
let mut distances = vec![vec![-1; field[0].len()]; field.len()];
let mut starting_position: Option<(usize, usize)> = None;
for (y, line) in field.iter().enumerate() {
for (x, field) in line.iter().enumerate() {
if *field == 'S' {
starting_position = Some((x, y));
distances[y][x] = 0;
}
}
}
let starting_position = starting_position.unwrap();
traverse(&mut distances, &field, starting_position);
*distances.iter().flat_map(|a| a.iter()).max().unwrap()
}
fn traverse(distances: &mut [Vec<isize>], field: &Vec<Vec<char>>, position: (usize, usize)) {
let height = field.len() - 1;
let width = field[0].len() - 1;
let mut locations_to_check = vec![position];
while let Some((x, y)) = locations_to_check.pop() {
let starting_value = distances[y][x];
assert_ne!(
starting_value, -1,
"traverse should only be called on locations that have already been set."
);
if x != 0 && (distances[y][x - 1] == -1 || distances[y][x - 1] > starting_value) {
match (field[y][x], field[y][x - 1]) {
('|' | 'L' | 'F', _) | (_, '.' | '|' | 'J' | '7') => {}
('.', _) | (_, 'S') => unreachable!(),
('-' | 'J' | '7' | 'S', '-' | 'L' | 'F') => {
distances[y][x - 1] = starting_value + 1;
locations_to_check.push((x - 1, y));
}
_ => unimplemented!(),
}
}
if x < width && (distances[y][x + 1] == -1 || distances[y][x + 1] > starting_value) {
match (field[y][x], field[y][x + 1]) {
('|' | 'J' | '7', _) | (_, '.' | '|' | 'L' | 'F') => {}
('.', _) | (_, 'S') => unreachable!(),
('-' | 'L' | 'F' | 'S', '-' | 'J' | '7') => {
distances[y][x + 1] = starting_value + 1;
locations_to_check.push((x + 1, y));
}
_ => unimplemented!(),
}
}
if y != 0 && (distances[y - 1][x] == -1 || distances[y - 1][x] > starting_value) {
match (field[y][x], field[y - 1][x]) {
('-' | 'F' | '7', _) | (_, '.' | '-' | 'J' | 'L') => {}
('.', _) | (_, 'S') => unreachable!(),
('|' | 'L' | 'J' | 'S', '|' | 'F' | '7') => {
distances[y - 1][x] = starting_value + 1;
locations_to_check.push((x, y - 1));
}
_ => unimplemented!(),
}
}
if y < height && (distances[y + 1][x] == -1 || distances[y + 1][x] > starting_value) {
match (field[y][x], field[y + 1][x]) {
('-' | 'L' | 'J', _) | (_, '.' | '-' | '7' | 'F') => {}
('.', _) | (_, 'S') => unreachable!(),
('|' | 'F' | '7' | 'S', '|' | 'L' | 'J') => {
distances[y + 1][x] = starting_value + 1;
locations_to_check.push((x, y + 1));
}
_ => unimplemented!(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_d10t1() {
let input = include_str!("../demo_input.txt");
assert_eq!(d10t1(input), 8);
}
}

8
d10t2/Cargo.toml Normal file
View file

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

10
d10t2/demo_input.txt Normal file
View file

@ -0,0 +1,10 @@
FF7FSF7F7F7F7F7F---7
L|LJ||||||||||||F--J
FL-7LJLJ||||||LJL-77
F--JF--7||LJLJ7F7FJ-
L---JF-JLJ.||-FJLJJ7
|F|F-JF---7F7-L7L|7|
|FFJF7L7F-JF7|JL---7
7-L-JL7||F7|L7F-7F7|
L.L7LFJ|||||FJL7||LJ
L7JLJL-JLJLJL--JLJ.L

10
d10t2/demo_input_2.txt Normal file
View file

@ -0,0 +1,10 @@
.F----7F7F7F7F-7....
.|F--7||||||||FJ....
.||.FJ||||||||L7....
FJL7L7LJLJ||LJ.L-7..
L--J.L7...LJS7F-7L7.
....F-J..F7FJ|L7L7L7
....L7.F7||L7|.L7L7|
.....|FJLJ|FJ|F7|.LJ
....FJL-7.||.||||...
....L---J.LJ.LJLJ...

9
d10t2/demo_input_3.txt Normal file
View file

@ -0,0 +1,9 @@
...........
.S-------7.
.|F-----7|.
.||.....||.
.||.....||.
.|L-7.F-J|.
.|..|.|..|.
.L--J.L--J.
...........

191
d10t2/src/main.rs Normal file
View file

@ -0,0 +1,191 @@
use std::fs::read_to_string;
fn main() {
let input = read_to_string("input.txt").unwrap();
println!("d10t2: {}", d10t2(&input));
}
pub fn d10t2(input: &str) -> usize {
let mut field = input
.lines()
.map(str::chars)
.map(std::iter::Iterator::collect::<Vec<_>>)
.collect::<Vec<_>>();
let mut distances = vec![vec![-1; field[0].len()]; field.len()];
let starting_position = field
.iter()
.enumerate()
.flat_map(|(y, line)| line.iter().enumerate().map(move |(x, c)| (x, y, c)))
.find(|&(_x, _y, c)| *c == 'S')
.map(|(x, y, _c)| (x, y))
.unwrap();
distances[starting_position.1][starting_position.0] = 0;
traverse(&mut distances, &mut field, starting_position);
get_enclosed(&distances, &field)
}
fn get_effective_char_for_start(distances: &[Vec<isize>]) -> char {
let starting_position = distances
.iter()
.enumerate()
.flat_map(|(y, line)| line.iter().enumerate().map(move |(x, c)| (x, y, c)))
.find(|&(_x, _y, c)| *c == 0)
.map(|(x, y, _c)| (x, y))
.unwrap();
let bounds = (distances[0].len() - 1, distances.len() - 1);
let (x, y) = starting_position;
let top = if y == 0 {
false
} else {
distances[y - 1][x] == 1
};
let bottom = if y == bounds.1 {
false
} else {
distances[y + 1][x] == 1
};
let left = if x == 0 {
false
} else {
distances[y][x - 1] == 1
};
let right = if x == bounds.0 {
false
} else {
distances[y][x + 1] == 1
};
match (top, bottom, left, right) {
(true, true, false, false) => '|',
(false, false, true, true) => '-',
(true, false, true, false) => 'J',
(true, false, false, true) => 'L',
(false, true, true, false) => '7',
(false, true, false, true) => 'F',
_ => unreachable!(),
}
}
fn get_enclosed(distances: &[Vec<isize>], field: &[Vec<char>]) -> usize {
let mut result = 0;
let s_char = get_effective_char_for_start(distances);
let unique_y_changes = |x: usize, until: usize| -> usize {
field[0..until]
.iter()
.enumerate()
.filter(|(idx, _)| distances[*idx][x] != -1)
.map(|(_, s)| s[x])
.collect::<String>()
.replace('S', s_char.to_string().as_str())
.replace('|', "")
.replace("FL", "")
.replace("FJ", "-")
.replace("7L", "-")
.replace("7J", "")
.replace('.', "")
.len()
};
let unique_x_changes = |y: usize, until: usize| -> usize {
field[y][0..until]
.iter()
.enumerate()
.filter(|(idx, _)| distances[y][*idx] != -1)
.map(|(_, c)| *c)
.collect::<String>()
.replace('S', s_char.to_string().as_str())
.replace('-', "")
.replace("F7", "")
.replace("FJ", "|")
.replace("L7", "|")
.replace("LJ", "")
.replace('.', "")
.len()
};
for (y, line) in distances.iter().enumerate() {
for (x, _d) in line.iter().enumerate() {
if distances[y][x] == -1 {
if unique_x_changes(y, x) % 2 == 1 && unique_y_changes(x, y) % 2 == 1 {
result += 1;
}
}
}
}
result
}
fn traverse(distances: &mut [Vec<isize>], field: &mut Vec<Vec<char>>, position: (usize, usize)) {
let height = field.len() - 1;
let width = field[0].len() - 1;
let mut locations_to_check = vec![position];
while let Some((x, y)) = locations_to_check.pop() {
let starting_value = distances[y][x];
assert_ne!(
starting_value, -1,
"traverse should only be called on locations that have already been set."
);
if x != 0 && (distances[y][x - 1] == -1 || distances[y][x - 1] > starting_value) {
match (field[y][x], field[y][x - 1]) {
('|' | 'L' | 'F', _) | (_, '.' | '|' | 'J' | '7') => {}
('.', _) | (_, 'S') => unreachable!(),
('-' | 'J' | '7' | 'S', '-' | 'L' | 'F') => {
distances[y][x - 1] = starting_value + 1;
locations_to_check.push((x - 1, y));
}
_ => unimplemented!(),
}
}
if x < width && (distances[y][x + 1] == -1 || distances[y][x + 1] > starting_value) {
match (field[y][x], field[y][x + 1]) {
('|' | 'J' | '7', _) | (_, '.' | '|' | 'L' | 'F') => {}
('.', _) | (_, 'S') => unreachable!(),
('-' | 'L' | 'F' | 'S', '-' | 'J' | '7') => {
distances[y][x + 1] = starting_value + 1;
locations_to_check.push((x + 1, y));
}
_ => unimplemented!(),
}
}
if y != 0 && (distances[y - 1][x] == -1 || distances[y - 1][x] > starting_value) {
match (field[y][x], field[y - 1][x]) {
('-' | 'F' | '7', _) | (_, '.' | '-' | 'J' | 'L') => {}
('.', _) | (_, 'S') => unreachable!(),
('|' | 'L' | 'J' | 'S', '|' | 'F' | '7') => {
distances[y - 1][x] = starting_value + 1;
locations_to_check.push((x, y - 1));
}
_ => unimplemented!(),
}
}
if y < height && (distances[y + 1][x] == -1 || distances[y + 1][x] > starting_value) {
match (field[y][x], field[y + 1][x]) {
('-' | 'L' | 'J', _) | (_, '.' | '-' | '7' | 'F') => {}
('.', _) | (_, 'S') => unreachable!(),
('|' | 'F' | '7' | 'S', '|' | 'L' | 'J') => {
distances[y + 1][x] = starting_value + 1;
locations_to_check.push((x, y + 1));
}
_ => unimplemented!(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_d10t2() {
let input = include_str!("../demo_input.txt");
assert_eq!(d10t2(input), 10);
}
#[test]
fn test_d10t2_2() {
let input = include_str!("../demo_input_2.txt");
assert_eq!(d10t2(input), 8);
}
#[test]
fn test_d10t2_3() {
let input = include_str!("../demo_input_3.txt");
assert_eq!(d10t2(input), 4);
}
}