try getting it to be optimized so it only needs to query one map

This commit is contained in:
Frederik
2023-12-08 20:19:22 +01:00
parent 5099a3005c
commit f7dc13c433

View File

@@ -4,7 +4,7 @@ use crate::*;
pub struct Day05; pub struct Day05;
impl Day for Day05 { impl Day for Day05 {
const DAY_NUM: u8 = 05; const DAY_NUM: u8 = 5;
type Input = String; type Input = String;
type Output = usize; type Output = usize;
@@ -77,6 +77,12 @@ impl DayPart2 for Day05 {
let target_seeds = data.next().unwrap(); let target_seeds = data.next().unwrap();
println!("targets: {}", target_seeds); println!("targets: {}", target_seeds);
let dict = parse_to_maps(data); let dict = parse_to_maps(data);
let dict = Map::combine_maps(dict);
let dict = {
let mut m = HashMap::new();
m.insert(Kind::Seed, dict);
m
};
let result = target_seeds let result = target_seeds
.trim() .trim()
.strip_prefix("seeds: ") .strip_prefix("seeds: ")
@@ -93,12 +99,11 @@ impl DayPart2 for Day05 {
println!("that is {} of positions to check", end-start); println!("that is {} of positions to check", end-start);
println!("======================================================================================================="); println!("=======================================================================================================");
let min = (start..end) let min = (start..end)
.into_iter()
.map(|seed_pos| { .map(|seed_pos| {
// println!("Starting to map Seed pos to location: {}", seed_pos); // println!("Starting to map Seed pos to location: {}", seed_pos);
let target = map_seed_to_position(seed_pos, &dict); let target = map_seed_to_position(seed_pos, &dict);
// println!("Got pos from seed: {}=>{}", seed_pos, target); // println!("Got pos from seed: {}=>{}", seed_pos, target);
// dbg!(target); dbg!(target);
target target
}) })
.min() .min()
@@ -123,12 +128,14 @@ impl DayPart2 for Day05 {
fn parse_to_maps<'a>(data: impl Iterator<Item = &'a str>) -> HashMap<Kind, Map> { fn parse_to_maps<'a>(data: impl Iterator<Item = &'a str>) -> HashMap<Kind, Map> {
let mut dict = HashMap::new(); let mut dict = HashMap::new();
for (_, lines) in (&data.group_by(|x| x.len() > 0)) for (x, lines) in (&data.group_by(|x| x.len() > 0)).into_iter()
.into_iter() //.filter(|(x, _)| *x)
.filter(|(x, _)| *x)
{ {
let lines = lines.collect::<Vec<_>>(); let lines = lines.collect::<Vec<_>>();
dbg!(&lines); dbg!(&x, &lines);
if !x {
continue;
}
let map = Map::from_vec(lines); let map = Map::from_vec(lines);
dbg!(&map); dbg!(&map);
dict.insert(map.from, map); dict.insert(map.from, map);
@@ -154,11 +161,13 @@ fn map_seed_to_position(var_name: usize, dict: &HashMap<Kind, Map>) -> usize {
use data::*; use data::*;
use itertools::Itertools; use itertools::Itertools;
mod data { mod data {
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Map { pub struct Map {
pub from: Kind, pub from: Kind,
pub to: Kind, pub to: Kind,
ranges: Vec<Range>, pub ranges: Vec<Range>,
} }
impl Map { impl Map {
@@ -171,7 +180,98 @@ mod data {
return target; return target;
} }
} }
return source; source
}
pub fn combine_maps(maps: HashMap<Kind, Map>) -> Map {
let mut maps = maps;
dbg!("combining following maps to a single one: ", &maps);
let mut current: Map = maps.remove(&Kind::Seed).unwrap();
let mut kind = current.to;
while kind != Kind::Location {
dbg!("current kind:", &kind);
let to = maps.get(&kind).unwrap();
current = Map::combine_two_maps(&current, to);
kind = current.to;
}
current
}
pub fn combine_two_maps(from: &Map, to: &Map) -> Map {
dbg!("combining these two maps to one:", from, to);
let from_kind = from.from;
let to_kind = to.to;
let mut ranges = Vec::<Range>::new();
'from_ranges: for range in &from.ranges {
let mut map_start = range.destination_start;
let mut map_end = range.length + map_start - 1;
let mut map_length = range.length;
'to_ranges: for to_range in &to.ranges {
let to_source_start = to_range.source_start;
let to_source_len = to_range.length;
let to_range_end = to_source_start + to_source_len - 1;
let to_source_end = map_start + map_length;
if to_source_start <= map_start {
let offset_from_this_range = map_start - to_source_start;
if to_range_end < to_source_end {
dbg!(
"from range fits fully into target range",
offset_from_this_range
);
let new_range = Range {
destination_start: to_range.destination_start
+ offset_from_this_range,
source_start: range.source_start,
length: map_length,
};
ranges.push(new_range);
continue 'from_ranges;
} else if to_range_end < map_start {
dbg!("from range is not inside this range at all");
continue 'to_ranges;
} else {
dbg!("from range fits partially into this range");
let length = 0;
let new_range = Range {
destination_start: to_range.destination_start
+ offset_from_this_range,
source_start: range.source_start,
length,
};
map_start += offset_from_this_range;
map_length -= length;
ranges.push(new_range);
dbg!("There was a range that could not completely be mapped, so only the start got mapped...", &range, &to_range);
continue 'to_ranges;
}
} else if to_range.source_start <= map_end {
dbg!("from range fits partially into this range");
let offset = map_end - to_range.source_start;
let new_range = Range {
destination_start: to_range.destination_start + offset,
source_start: to_range.source_start,
length: offset,
};
ranges.push(new_range);
dbg!("There was a range that could not completely be mapped, so only the end got mapped...", &range, &to_range);
}
}
}
let map = Self {
from: from_kind,
to: to_kind,
ranges,
};
dbg!(
"combined two maps into one:",
from,
to,
"were combined into: ",
&map
);
map
} }
} }
impl<T> From<T> for Map impl<T> From<T> for Map
@@ -180,6 +280,7 @@ mod data {
{ {
fn from(value: T) -> Self { fn from(value: T) -> Self {
let value = value.as_ref(); let value = value.as_ref();
dbg!(&value);
let mut values = value.trim().lines(); let mut values = value.trim().lines();
let mut map_name = values let mut map_name = values
.next() .next()
@@ -224,9 +325,9 @@ mod data {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Range { pub struct Range {
destination_start: usize, pub destination_start: usize,
source_start: usize, pub source_start: usize,
length: usize, pub length: usize,
} }
impl Range { impl Range {
fn get_mapped(&self, source: usize) -> Option<usize> { fn get_mapped(&self, source: usize) -> Option<usize> {
@@ -260,27 +361,26 @@ mod my_tests {
use test::Bencher; use test::Bencher;
fn get_sample_map() -> HashMap<Kind, Map> { fn get_sample_map() -> HashMap<Kind, Map> {
let data: String = Day05::get_test_data(); let data: String = Day05::get_test_data();
dbg!("Test data:", &data);
let mut data = data.lines().map(|x| x.trim()); let mut data = data.lines().map(|x| x.trim());
let target_seeds = data.next().unwrap(); let target_seeds = data.next().unwrap();
println!("targets: {}", target_seeds); dbg!("targets: {}", target_seeds);
let dict = parse_to_maps(data); parse_to_maps(data)
dict
} }
fn get_sample_map_real() -> HashMap<Kind, Map> { fn get_sample_map_real() -> HashMap<Kind, Map> {
let data: String = read_input(05); let data: String = read_input(5);
let mut data = data.lines().map(|x| x.trim()); let mut data = data.lines().map(|x| x.trim());
let target_seeds = data.next().unwrap(); let target_seeds = data.next().unwrap();
println!("targets: {}", target_seeds); println!("targets: {}", target_seeds);
let dict = parse_to_maps(data); parse_to_maps(data)
dict
} }
#[bench] #[bench]
fn bench_mapping(b: &mut Bencher) { fn bench_mapping(b: &mut Bencher) {
let mapper = get_sample_map(); let mapper = get_sample_map();
b.iter(|| { b.iter(|| {
(0..10000) (0..10000).for_each(|x| {
.into_iter() map_seed_to_position(x, &mapper);
.for_each(|x| {map_seed_to_position(x, &mapper);}) })
}) })
} }
#[bench] #[bench]
@@ -306,10 +406,107 @@ mod my_tests {
} }
#[bench] #[bench]
fn bench_parsing2_real(b: &mut Bencher) { fn bench_parsing2_real(b: &mut Bencher) {
let data: String = read_input(05); let data: String = read_input(5);
let mut data = data.lines().map(|x| x.trim()); let mut data = data.lines().map(|x| x.trim());
let target_seeds = data.next().unwrap(); let target_seeds = data.next().unwrap();
println!("targets: {}", target_seeds); println!("targets: {}", target_seeds);
b.iter(|| parse_to_maps(data.clone())) b.iter(|| parse_to_maps(data.clone()))
} }
#[test]
fn test_parsing_combined() {
let maps = get_sample_map();
let map = Map::combine_maps(maps);
dbg!(map);
assert!(false);
}
#[test]
fn test_parsing_combined2() {
let maps = {
let mut d = HashMap::new();
d.insert(
Kind::Seed,
Map {
from: Kind::Seed,
to: Kind::Light,
ranges: vec![
Range {
source_start: 10,
destination_start: 50,
length: 5,
},
Range {
source_start: 60,
destination_start: 20,
length: 5,
},
],
},
);
d.insert(
Kind::Light,
Map {
from: Kind::Light,
to: Kind::Location,
ranges: vec![
Range {
source_start: 50,
destination_start: 150,
length: 5,
},
Range {
source_start: 20,
destination_start: 210,
length: 5,
},
],
},
);
d
};
let expected = Map {
from: Kind::Seed,
to: Kind::Location,
ranges: vec![
Range {
source_start: 10,
destination_start: 150,
length: 5,
},
Range {
source_start: 60,
destination_start: 210,
length: 5,
},
],
};
let map = Map::combine_maps(maps);
dbg!("result of the combining: ", &map);
assert_eq!(map, expected);
panic!("i want to see the results");
}
#[test]
fn test_parsing_combined3() {
let maps = get_sample_map();
let map = Map::combine_maps(maps.clone());
dbg!("result of the combining: ", &map);
(0..1000).for_each(|x| {
let normal = map_seed_to_position(x, &maps);
let combined = map.get_mapped(x);
assert_eq!(normal, combined);
});
}
#[bench]
fn bench_parsing_combined(b: &mut Bencher) {
b.iter(|| {
let maps = get_sample_map();
let map = Map::combine_maps(maps);
dbg!(map);
})
}
} }