Skip to content

Instantly share code, notes, and snippets.

@codemonkey76
Created December 12, 2023 05:04
Show Gist options
  • Save codemonkey76/67509aa1831a8ab83b5015ae1492d657 to your computer and use it in GitHub Desktop.
Save codemonkey76/67509aa1831a8ab83b5015ae1492d657 to your computer and use it in GitHub Desktop.
Advent Of Code - 2023 - Day 5 - Optimized Solution in Rust
use std::fs;
use std::collections::HashMap;
use std::time::Instant;
use itertools::Itertools;
fn apply_mapping(current: u32, map: &Mapping) -> u32 {
let mut value: u32 = current;
for entity in &map.mappings {
if value >= entity.src && value < entity.src + entity.range {
value = entity.dest + (value - entity.src);
break;
}
}
return value;
}
fn apply_range_mappings(ranges: &mut Vec<(u32, u32)>, maps: &HashMap<String, Mapping>) -> Vec<(u32, u32)> {
let mut ranges_clone = ranges.clone();
for map_name in ["soil", "fertilizer", "water", "light", "temperature", "humidity", "location"] {
let mapping = maps.get(map_name).unwrap();
ranges_clone = apply_range_mapping(&mut ranges_clone, mapping);
}
ranges_clone
}
fn apply_range_mapping(ranges: &mut Vec<(u32, u32)>, map: &Mapping) -> Vec<(u32,u32)> {
let mut new_ranges = vec![];
let mut i = 0;
while i < ranges.len() {
let mut matched = false;
for entity in &map.mappings {
let entity_range = (entity.src, entity.src+entity.range);
let os = ranges[i].0.max(entity_range.0);
let oe = ranges[i].1.min(entity_range.1);
if os < oe {
new_ranges.push((os - entity.src+entity.dest, oe-entity.src+entity.dest));
matched = true;
// Check these again for other matches
if os > ranges[i].0 { ranges.push((ranges[i].0, os)); }
if ranges[i].1 > oe { ranges.push((oe, ranges[i].1)); }
// If a match found we can break
break;
}
}
if !matched { new_ranges.push((ranges[i].0, ranges[i].1)); }
i+=1;
}
new_ranges
}
fn read_file(file: &str) -> Vec<String> {
fs::read_to_string(file)
.expect("Unable to open file")
.split("\n\n")
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect::<Vec<String>>()
}
fn parse_seeds(seeds: String) -> Vec<u32> {
seeds
.split_once(": ")
.unwrap()
.1
.split_whitespace()
.map(|num| num.parse::<u32>().unwrap())
.collect()
}
fn parse_maps(mut groups: Vec<String>) -> HashMap<String, Mapping> {
let mut maps:HashMap<String, Mapping> = HashMap::new();
while let Some(item) = groups.pop() {
let mut contents = item.split('\n').filter(|str| !str.is_empty()).map(|str| str.to_string()).collect::<Vec<String>>();
let map_row = contents.remove(0);
let (_, _, to) = map_row.split_once(' ').unwrap().0.split('-').collect_tuple().unwrap();
let mappings : Vec<MapRange> = contents
.iter()
.map(|line| {
MapRange::from(line)
})
.collect::<Vec<MapRange>>();
maps.insert(to.to_string(), Mapping { mappings });
}
maps
}
#[derive(Debug)]
struct Mapping {
mappings: Vec<MapRange>
}
#[derive(Debug)]
struct MapRange {
src: u32,
dest: u32,
range: u32
}
impl From<(u32,u32,u32)> for MapRange {
fn from(value: (u32, u32, u32)) -> Self {
MapRange {
src: value.1,
dest: value.0,
range: value.2
}
}
}
impl From<&String> for MapRange {
fn from(value: &String) -> Self {
MapRange::from(
value
.split(' ')
.map(|num| num.parse::<u32>().unwrap())
.collect_tuple::<(u32,u32,u32)>()
.unwrap()
)
}
}
fn part1(seeds: &Vec<u32>, maps: &HashMap<String, Mapping>) -> u32 {
let mut part1 = u32::MAX;
for seed in seeds {
let mut current = *seed;
for map_name in ["soil", "fertilizer", "water", "light", "temperature", "humidity", "location"] {
let mapping = maps.get(map_name).unwrap();
current = apply_mapping(current, mapping);
}
part1 = part1.min(current);
}
part1
}
fn part2(seeds: &Vec<u32>, maps: &HashMap<String, Mapping>) -> u32 {
let mut ranges: Vec<(u32, u32)> = vec![];
for seed_pair in seeds.chunks(2) {
ranges.push((seed_pair[0], seed_pair[0] + seed_pair[1] - 1));
}
ranges = apply_range_mappings(&mut ranges, maps);
ranges.sort();
ranges[0].0
}
fn main() {
let start = Instant::now();
let mut groups = read_file("d5");
let seeds = parse_seeds(groups.remove(0));
let maps = parse_maps(groups);
let parse_duration = start.elapsed();
let part1 = part1(&seeds, &maps);
let part_1_duration = start.elapsed();
let part2 = part2(&seeds, &maps);
let part_2_duration = start.elapsed();
println!("Parse:");
println!("Time elapsed: {:?}", parse_duration);
println!("Part 1: {}", part1);
println!("Time elapsed: {:?}", part_1_duration);
println!("Part 2: {:?}", part2);
println!("Time elapsed: {:?}", part_2_duration);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment