mirror of
https://github.com/anthonyoteri/advent-of-code-2023.git
synced 2026-06-05 18:56:53 -04:00
@@ -6,3 +6,4 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
indicatif = { version = "0.17.7", features = ["rayon"] }
|
||||||
|
|||||||
+137
-37
@@ -1,15 +1,17 @@
|
|||||||
|
use indicatif::ProgressIterator;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::BinaryHeap;
|
||||||
|
|
||||||
const SOIL: &'static str = "seed-to-soil";
|
const SOIL: &str = "seed-to-soil";
|
||||||
const FERT: &'static str = "soil-to-fertilizer";
|
const FERT: &str = "soil-to-fertilizer";
|
||||||
const WATER: &'static str = "fertilizer-to-water";
|
const WATER: &str = "fertilizer-to-water";
|
||||||
const LIGHT: &'static str = "water-to-light";
|
const LIGHT: &str = "water-to-light";
|
||||||
const TEMP: &'static str = "light-to-temperature";
|
const TEMP: &str = "light-to-temperature";
|
||||||
const HUMIDITY: &'static str = "temperature-to-humidity";
|
const HUMIDITY: &str = "temperature-to-humidity";
|
||||||
const LOC: &'static str = "humidity-to-location";
|
const LOC: &str = "humidity-to-location";
|
||||||
|
|
||||||
fn extract_seeds(input: &str) -> Vec<usize> {
|
fn extract_seeds(input: &str) -> Vec<usize> {
|
||||||
let line = input.lines().nth(0).unwrap();
|
let line = input.lines().next().unwrap();
|
||||||
let (_, values) = line.split_once(':').unwrap();
|
let (_, values) = line.split_once(':').unwrap();
|
||||||
values
|
values
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
@@ -30,8 +32,8 @@ fn extract_map_lines(input: &str, key: &'static str) -> Vec<String> {
|
|||||||
lines
|
lines
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup(input: &str, source: usize, map: &'static str) -> usize {
|
fn lookup(maps: &BTreeMap<&'static str, Vec<String>>, source: usize, map: &'static str) -> usize {
|
||||||
let map_lines = extract_map_lines(input, map);
|
let map_lines = maps.get(map).unwrap();
|
||||||
|
|
||||||
for line in map_lines {
|
for line in map_lines {
|
||||||
let values: Vec<usize> = line
|
let values: Vec<usize> = line
|
||||||
@@ -52,39 +54,118 @@ fn lookup(input: &str, source: usize, map: &'static str) -> usize {
|
|||||||
source
|
source
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_location(input: &str, seed: usize) -> usize {
|
fn rev_lookup(maps: &BTreeMap<&'static str, Vec<String>>, dest: usize, map: &'static str) -> usize {
|
||||||
dbg!(&seed);
|
let map_lines = maps.get(map).unwrap();
|
||||||
let soil = lookup(input, seed, SOIL);
|
|
||||||
dbg!(&soil);
|
|
||||||
|
|
||||||
let fert = lookup(input, soil, FERT);
|
for line in map_lines {
|
||||||
dbg!(&fert);
|
let values: Vec<usize> = line
|
||||||
let water = lookup(input, fert, WATER);
|
.split_whitespace()
|
||||||
dbg!(&water);
|
.map(|s| s.parse::<usize>().unwrap())
|
||||||
let light = lookup(input, water, LIGHT);
|
.collect();
|
||||||
dbg!(&light);
|
|
||||||
let temp = lookup(input, light, TEMP);
|
|
||||||
dbg!(&temp);
|
|
||||||
let humidity = lookup(input, temp, HUMIDITY);
|
|
||||||
dbg!(&humidity);
|
|
||||||
let loc = lookup(input, humidity, LOC);
|
|
||||||
dbg!(&loc);
|
|
||||||
|
|
||||||
loc
|
let dest_range_start = values[0];
|
||||||
|
let source_range_start = values[1];
|
||||||
|
let range_length = values[2];
|
||||||
|
|
||||||
|
let dest_range_end = dest_range_start + range_length;
|
||||||
|
if dest >= dest_range_start && dest < dest_range_end {
|
||||||
|
return source_range_start + (dest - dest_range_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_location(maps: &BTreeMap<&'static str, Vec<String>>, seed: usize) -> usize {
|
||||||
|
let soil = lookup(maps, seed, SOIL);
|
||||||
|
|
||||||
|
let fert = lookup(maps, soil, FERT);
|
||||||
|
let water = lookup(maps, fert, WATER);
|
||||||
|
let light = lookup(maps, water, LIGHT);
|
||||||
|
let temp = lookup(maps, light, TEMP);
|
||||||
|
let humidity = lookup(maps, temp, HUMIDITY);
|
||||||
|
|
||||||
|
|
||||||
|
lookup(maps, humidity, LOC)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rev_lookup_location(maps: &BTreeMap<&'static str, Vec<String>>, loc: usize) -> usize {
|
||||||
|
let humidity = rev_lookup(maps, loc, LOC);
|
||||||
|
let temp = rev_lookup(maps, humidity, HUMIDITY);
|
||||||
|
let light = rev_lookup(maps, temp, TEMP);
|
||||||
|
let water = rev_lookup(maps, light, LIGHT);
|
||||||
|
let fert = rev_lookup(maps, water, WATER);
|
||||||
|
let soil = rev_lookup(maps, fert, FERT);
|
||||||
|
|
||||||
|
|
||||||
|
rev_lookup(maps, soil, SOIL)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_maps(input: &str) -> BTreeMap<&'static str, Vec<String>> {
|
||||||
|
let mut maps = BTreeMap::new();
|
||||||
|
maps.insert(SOIL, extract_map_lines(input, SOIL));
|
||||||
|
maps.insert(FERT, extract_map_lines(input, FERT));
|
||||||
|
maps.insert(WATER, extract_map_lines(input, WATER));
|
||||||
|
maps.insert(LIGHT, extract_map_lines(input, LIGHT));
|
||||||
|
maps.insert(TEMP, extract_map_lines(input, TEMP));
|
||||||
|
maps.insert(HUMIDITY, extract_map_lines(input, HUMIDITY));
|
||||||
|
maps.insert(LOC, extract_map_lines(input, LOC));
|
||||||
|
maps
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &str) -> u32 {
|
fn part_1(input: &str) -> u32 {
|
||||||
|
let maps = extract_maps(input);
|
||||||
let seeds = extract_seeds(input);
|
let seeds = extract_seeds(input);
|
||||||
let mut locs = Vec::new();
|
let mut locs = Vec::new();
|
||||||
for seed in seeds {
|
for seed in seeds {
|
||||||
locs.push(lookup_location(input, seed));
|
locs.push(lookup_location(&maps, seed));
|
||||||
}
|
}
|
||||||
locs.iter().min().unwrap().clone() as u32
|
*locs.iter().min().unwrap() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &str) -> usize {
|
||||||
|
let maps = extract_maps(input);
|
||||||
|
let seed_pairs = extract_seeds(input);
|
||||||
|
|
||||||
|
let mut ranges = Vec::new();
|
||||||
|
for chunk in seed_pairs.chunks(2) {
|
||||||
|
let start = chunk[0];
|
||||||
|
let size = chunk[1];
|
||||||
|
ranges.push(start..start + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut h2l = maps.get(LOC).unwrap().iter().collect::<BinaryHeap<_>>();
|
||||||
|
|
||||||
|
let line = h2l.pop().unwrap();
|
||||||
|
let values: Vec<usize> = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|s| s.parse::<usize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dest_range_start = values[0];
|
||||||
|
let range_length = values[2];
|
||||||
|
|
||||||
|
let rng = 0..dest_range_start + range_length;
|
||||||
|
|
||||||
|
rng.into_iter()
|
||||||
|
.progress()
|
||||||
|
.find(|loc| {
|
||||||
|
let seed = rev_lookup_location(&maps, *loc);
|
||||||
|
for range in &ranges {
|
||||||
|
if range.contains(&seed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
// 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input = include_str!("../input.txt");
|
let input = include_str!("../input.txt");
|
||||||
println!("Part 1: {}", part_1(input));
|
println!("Part 1: {}", part_1(input));
|
||||||
|
println!("Part 2: {}", part_2(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -108,20 +189,33 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_lookup_location() {
|
fn test_lookup_location() {
|
||||||
let input = include_str!("../test-input.txt");
|
let input = include_str!("../test-input.txt");
|
||||||
|
let maps = extract_maps(input);
|
||||||
|
|
||||||
assert_eq!(lookup_location(input, 79), 82);
|
assert_eq!(lookup_location(&maps, 79), 82);
|
||||||
assert_eq!(lookup_location(input, 14), 43);
|
assert_eq!(lookup_location(&maps, 14), 43);
|
||||||
assert_eq!(lookup_location(input, 55), 86);
|
assert_eq!(lookup_location(&maps, 55), 86);
|
||||||
assert_eq!(lookup_location(input, 13), 35);
|
assert_eq!(lookup_location(&maps, 13), 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_reverse_lookup() {
|
||||||
|
let input = include_str!("../test-input.txt");
|
||||||
|
let maps = extract_maps(input);
|
||||||
|
|
||||||
|
assert_eq!(rev_lookup_location(&maps, 82), 79);
|
||||||
|
assert_eq!(rev_lookup_location(&maps, 43), 14);
|
||||||
|
assert_eq!(rev_lookup_location(&maps, 86), 55);
|
||||||
|
assert_eq!(rev_lookup_location(&maps, 35), 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lookup() {
|
fn test_lookup() {
|
||||||
let input = include_str!("../test-input.txt");
|
let input = include_str!("../test-input.txt");
|
||||||
assert_eq!(lookup(input, 79, SOIL), 81);
|
let maps = extract_maps(input);
|
||||||
assert_eq!(lookup(input, 14, SOIL), 14);
|
assert_eq!(lookup(&maps, 79, SOIL), 81);
|
||||||
assert_eq!(lookup(input, 55, SOIL), 57);
|
assert_eq!(lookup(&maps, 14, SOIL), 14);
|
||||||
assert_eq!(lookup(input, 13, SOIL), 13);
|
assert_eq!(lookup(&maps, 55, SOIL), 57);
|
||||||
|
assert_eq!(lookup(&maps, 13, SOIL), 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -129,4 +223,10 @@ mod tests {
|
|||||||
let input = include_str!("../test-input.txt");
|
let input = include_str!("../test-input.txt");
|
||||||
assert_eq!(part_1(input), 35);
|
assert_eq!(part_1(input), 35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_2() {
|
||||||
|
let input = include_str!("../test-input.txt");
|
||||||
|
assert_eq!(part_2(input), 46);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user