From 5a812be6f204d7701759f8d04fc33b8cb384e092 Mon Sep 17 00:00:00 2001 From: dobiadi <50926840+dobiadi@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:21:12 +0100 Subject: [PATCH] Day5 Rust --- day5/rust/.gitignore | 1 + day5/rust/Cargo.lock | 7 ++ day5/rust/Cargo.toml | 8 ++ day5/rust/src/main.rs | 194 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 day5/rust/.gitignore create mode 100644 day5/rust/Cargo.lock create mode 100644 day5/rust/Cargo.toml create mode 100644 day5/rust/src/main.rs diff --git a/day5/rust/.gitignore b/day5/rust/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/day5/rust/.gitignore @@ -0,0 +1 @@ +target diff --git a/day5/rust/Cargo.lock b/day5/rust/Cargo.lock new file mode 100644 index 0000000..b21cc6a --- /dev/null +++ b/day5/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/day5/rust/Cargo.toml b/day5/rust/Cargo.toml new file mode 100644 index 0000000..1ec6963 --- /dev/null +++ b/day5/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day5/rust/src/main.rs b/day5/rust/src/main.rs new file mode 100644 index 0000000..03736ba --- /dev/null +++ b/day5/rust/src/main.rs @@ -0,0 +1,194 @@ +use std::collections::HashSet; + +struct Map { + source: usize, + destination: usize, + ranges: Vec, +} + +#[derive(Clone, Debug)] +struct Range { + source_start: usize, + destination_start: usize, + length: usize, +} + +fn main() { + let stdin = std::io::stdin(); + + let mut firstline = true; + let mut seeds: Vec = Vec::new(); + let mut maps = Vec::new(); + + let mut src = 0; + let mut dst = 0; + for line in stdin.lines() { + let line = line.unwrap(); + + if firstline { + if line.len() == 0 { + firstline = false; + continue; + } + + line.split_once(":") + .unwrap() + .1 + .trim() + .split(" ") + .map(|e| e.parse().unwrap()) + .for_each(|e| seeds.push(e)); + + continue; + } + + if line.len() == 0 { + src += 1; + } else if src == dst { + dst += 1; + maps.push(create_map(src, dst)); + } else { + let nums: Vec = line.split(" ").map(|e| e.parse().unwrap()).collect(); + + let range = Range { + source_start: nums[1], + destination_start: nums[0], + length: nums[2], + }; + + maps.last_mut().unwrap().ranges.push(range); + } + } + + let mut reduced = reduce_maps(&maps[0], &maps[1]).unwrap(); + + for i in 2..maps.len() { + reduced = reduce_maps(&reduced, &maps[i]).unwrap(); + } + + // Part 1 + + let mut min = usize::max_value(); + + for seed in &seeds { + let value = lookup_map(*seed, &reduced); + if value < min { + min = value; + } + } + + println!("{}", min); + + // Part 2 + let mut part2 = usize::max_value(); + + // Create a new map from seeds + let mut seed_map = create_map(11, 0); + + + for i in (0..seeds.len()).step_by(2) { + seed_map.ranges.push(Range { + source_start: seeds[i], + destination_start: seeds[i], + length: seeds[i+1], + }) + } + + let seed_range_reduced = reduce_maps(&seed_map, &reduced).unwrap(); + + for range in &seed_range_reduced.ranges { + let mut found = false; + for srange in &seed_map.ranges { + if range.source_start >= srange.source_start && range.source_start < srange.source_start + srange.length { + found = true; + } + } + if !found { + continue; + } + let value = lookup_map(range.source_start, &seed_range_reduced); + + if value < part2 { + part2 = value; + } + } + + println!("{}", part2); +} + +fn create_map(source: usize, destination: usize) -> Map { + Map { + source, + destination, + ranges: Vec::new(), + } +} + +fn lookup_map(value: usize, map: &Map) -> usize { + let mut new_value = value; + + for range in &map.ranges { + if value >= range.source_start && value < range.source_start + range.length { + new_value = range.destination_start + (value - range.source_start); + break; + } + } + + return new_value; +} + +fn lookup_map_inverse(value: usize, map: &Map) -> usize { + let mut new_value = value; + + for range in &map.ranges { + if value >= range.destination_start && value < range.destination_start + range.length { + new_value = range.source_start + (value - range.destination_start); + break; + } + } + + return new_value; +} + +fn reduce_maps(source: &Map, destination: &Map) -> Option { + if source.destination != destination.source { + println!("Incompatible maps"); + return None; + } + + let mut breakpoints = HashSet::new(); + + for range in &source.ranges { + breakpoints.insert(range.source_start); + breakpoints.insert(range.source_start + range.length); + } + + for range in &destination.ranges { + breakpoints.insert(lookup_map_inverse(range.source_start, &source)); + breakpoints.insert(lookup_map_inverse( + range.source_start + range.length, + &source, + )); + } + + let mut breakpoints: Vec<_> = breakpoints.into_iter().collect(); + breakpoints.sort(); + + let mut new_ranges = Vec::new(); + + for i in 0..breakpoints.len() - 1 { + new_ranges.push(Range { + source_start: breakpoints[i], + destination_start: lookup_map(lookup_map(breakpoints[i], &source), &destination), + length: breakpoints[i + 1] - breakpoints[i], + }) + } + + let map = Map { + source: source.source, + destination: destination.destination, + ranges: new_ranges, + }; + + return Some(map); +}