Day 5 to kill your computer
This commit is contained in:
parent
6b7afc5a93
commit
48cfa80dec
133
src/day5/mod.rs
133
src/day5/mod.rs
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use log::{debug, info};
|
use log::{debug, info, trace};
|
||||||
|
|
||||||
use super::utils::Part;
|
use super::utils::Part;
|
||||||
|
|
||||||
|
|
@ -9,14 +9,19 @@ use super::utils::Part;
|
||||||
struct Range {
|
struct Range {
|
||||||
range_start: u64,
|
range_start: u64,
|
||||||
src_range_start: u64,
|
src_range_start: u64,
|
||||||
length: u64
|
length: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Range {
|
impl Range {
|
||||||
fn map(&self, n: u64) -> Option<u64> {
|
fn map(&self, n: u64) -> Option<u64> {
|
||||||
if (self.src_range_start..(self.src_range_start+self.length)).contains(&n) {
|
if (self.src_range_start..(self.src_range_start + self.length)).contains(&n) {
|
||||||
debug!("matching range {} -> {} [{:?}]", n, self.range_start + n - self.src_range_start, self);
|
trace!(
|
||||||
return Some(self.range_start + n - self.src_range_start )
|
"matching range {} -> {} [{:?}]",
|
||||||
|
n,
|
||||||
|
self.range_start + n - self.src_range_start,
|
||||||
|
self
|
||||||
|
);
|
||||||
|
return Some(self.range_start + n - self.src_range_start);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -25,17 +30,19 @@ impl Range {
|
||||||
struct Map {
|
struct Map {
|
||||||
start_domain: String,
|
start_domain: String,
|
||||||
target_domain: String,
|
target_domain: String,
|
||||||
ranges: Vec<Range>
|
ranges: Vec<Range>,
|
||||||
}
|
}
|
||||||
impl Map {
|
impl Map {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Map { ..Default::default() }
|
Map {
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&self, n: u64) -> u64 {
|
fn map(&self, n: u64) -> u64 {
|
||||||
for range in &self.ranges {
|
for range in &self.ranges {
|
||||||
if let Some(value) = range.map(n) {
|
if let Some(value) = range.map(n) {
|
||||||
return value
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n
|
n
|
||||||
|
|
@ -45,77 +52,103 @@ impl Map {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Dataset {
|
struct Dataset {
|
||||||
seeds: Vec<u64>,
|
seeds: Vec<u64>,
|
||||||
maps: HashMap<String, Map>
|
maps: HashMap<String, Map>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dataset {
|
impl Dataset {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Dataset { ..Default::default() }
|
Dataset {
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve(lines: Vec<String>, part: Part) -> u64 {
|
pub fn solve(lines: Vec<String>, part: Part) -> u64 {
|
||||||
let parts : Vec<String> = lines.into_iter()
|
let parts: Vec<String> = lines.into_iter().filter(|l| !l.is_empty()).collect();
|
||||||
.filter(|l| !l.is_empty())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut dataset = Dataset::new();
|
let mut dataset = Dataset::new();
|
||||||
debug!("{:?}", parts);
|
debug!("{:?}", parts);
|
||||||
|
|
||||||
let (seeds_line, other_lines) = parts.split_at(1);
|
let (seeds_line, other_lines) = parts.split_at(1);
|
||||||
dataset.seeds = seeds_line.first().unwrap().split(' ').skip(1).map(|e| e.parse().unwrap()).collect();
|
dataset.seeds = seeds_line
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.split(' ')
|
||||||
|
.skip(1)
|
||||||
|
.map(|e| e.parse().unwrap())
|
||||||
|
.collect();
|
||||||
debug!("Seeds : {:?}", dataset.seeds);
|
debug!("Seeds : {:?}", dataset.seeds);
|
||||||
|
|
||||||
let mut current_map : Map = Map::new();
|
let mut current_map: Map = Map::new();
|
||||||
let regex_map_header = Regex::new(r"^(\w*)-to-(\w*)").unwrap();
|
let regex_map_header = Regex::new(r"^(\w*)-to-(\w*)").unwrap();
|
||||||
for line in other_lines {
|
for line in other_lines {
|
||||||
if let Some(captures) = regex_map_header.captures(line) {
|
if let Some(captures) = regex_map_header.captures(line) {
|
||||||
if !current_map.ranges.is_empty() {
|
if !current_map.ranges.is_empty() {
|
||||||
debug!("New mapping detected, saving the last one");
|
debug!("New mapping detected, saving the last one");
|
||||||
dataset.maps.insert(current_map.start_domain.to_owned(), current_map);
|
dataset
|
||||||
|
.maps
|
||||||
|
.insert(current_map.start_domain.to_owned(), current_map);
|
||||||
current_map = Map::new();
|
current_map = Map::new();
|
||||||
}
|
}
|
||||||
current_map.start_domain = captures[1].to_owned();
|
current_map.start_domain = captures[1].to_owned();
|
||||||
current_map.target_domain = captures[2].to_owned();
|
current_map.target_domain = captures[2].to_owned();
|
||||||
}else{
|
} else {
|
||||||
let components : [u64; 3] = line.split(' ').map(|e| e.parse().unwrap()).collect::<Vec<_>>().try_into().unwrap();
|
let components: [u64; 3] = line
|
||||||
|
.split(' ')
|
||||||
|
.map(|e| e.parse().unwrap())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
debug!("new range: {:?}", components);
|
debug!("new range: {:?}", components);
|
||||||
current_map.ranges.push(
|
current_map.ranges.push(Range {
|
||||||
Range {
|
range_start: components[0],
|
||||||
range_start: components[0],
|
src_range_start: components[1],
|
||||||
src_range_start: components[1],
|
length: components[2],
|
||||||
length: components[2]
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataset.maps.insert(current_map.start_domain.to_owned(), current_map);
|
dataset
|
||||||
|
.maps
|
||||||
|
.insert(current_map.start_domain.to_owned(), current_map);
|
||||||
|
|
||||||
info!("Loaded {} mapping categories", dataset.maps.len());
|
info!("Loaded {} mapping categories", dataset.maps.len());
|
||||||
for (src, map) in &dataset.maps {
|
for (src, map) in &dataset.maps {
|
||||||
info!("{} -> {} with {} ranges", src, map.target_domain, map.ranges.len());
|
info!(
|
||||||
|
"{} -> {} with {} ranges",
|
||||||
|
src,
|
||||||
|
map.target_domain,
|
||||||
|
map.ranges.len()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match part {
|
if let Part::Two = part {
|
||||||
Part::One => {
|
// Convert the seeds to the new format !
|
||||||
let mut min_location = u64::MAX;
|
let original_seeds = dataset.seeds;
|
||||||
for seed in dataset.seeds {
|
let mut new_seeds : Vec<u64> = Vec::new();
|
||||||
let mut stage = "seed";
|
|
||||||
let mut value = seed;
|
|
||||||
while let Some(map) = dataset.maps.get(stage) {
|
|
||||||
debug!("Stage {} -> {}", stage, map.target_domain);
|
|
||||||
value = map.map(value);
|
|
||||||
stage = &map.target_domain;
|
|
||||||
}
|
|
||||||
min_location = min_location.min(value);
|
|
||||||
info!("Final stage seed {} -> location {}", seed, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
min_location
|
for chunk in original_seeds.chunks_exact(2) {
|
||||||
},
|
let range = chunk[0]..(chunk[0]+chunk[1]);
|
||||||
Part::Two => todo!()
|
// FIXME : don't do that it will eat all your memory: new_seeds.append(&mut range.collect::<Vec<u64>>());
|
||||||
|
}
|
||||||
|
debug!("New seeds: {:?}", new_seeds);
|
||||||
|
|
||||||
|
dataset.seeds = new_seeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut min_location = u64::MAX;
|
||||||
|
for seed in dataset.seeds {
|
||||||
|
let mut stage = "seed";
|
||||||
|
let mut value = seed;
|
||||||
|
while let Some(map) = dataset.maps.get(stage) {
|
||||||
|
debug!("Stage {} -> {}", stage, map.target_domain);
|
||||||
|
value = map.map(value);
|
||||||
|
stage = &map.target_domain;
|
||||||
|
}
|
||||||
|
min_location = min_location.min(value);
|
||||||
|
info!("Final stage seed {} -> location {}", seed, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
min_location
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -131,22 +164,20 @@ mod tests {
|
||||||
map.ranges.push(Range {
|
map.ranges.push(Range {
|
||||||
range_start: 50,
|
range_start: 50,
|
||||||
src_range_start: 98,
|
src_range_start: 98,
|
||||||
length: 2
|
length: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
map.ranges.push(Range {
|
map.ranges.push(Range {
|
||||||
range_start: 52,
|
range_start: 52,
|
||||||
src_range_start: 50,
|
src_range_start: 50,
|
||||||
length: 48
|
length: 48,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(map.map(1), 1);
|
assert_eq!(map.map(1), 1);
|
||||||
assert_eq!(map.map(99), 51);
|
assert_eq!(map.map(99), 51);
|
||||||
assert_eq!(map.map(51), 53);
|
assert_eq!(map.map(51), 53);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part2(){
|
fn test_part2() {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ mod day1;
|
||||||
mod day2;
|
mod day2;
|
||||||
mod day3;
|
mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
|
mod day5;
|
||||||
mod utils;
|
mod utils;
|
||||||
use log::info;
|
use log::info;
|
||||||
use utils::Part;
|
use utils::Part;
|
||||||
|
|
@ -17,6 +18,13 @@ fn main() {
|
||||||
.format_timestamp(None)
|
.format_timestamp(None)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
let data = utils::lines_from_file("./datasets/adventofcode.com_2023_day_5_input.txt").expect("Can't load the data");
|
||||||
|
//let data = utils::lines_from_file("./datasets/test.txt").expect("Can't load the data");
|
||||||
|
let result = day5::solve(data.clone(), Part::One);
|
||||||
|
let result2 = day5::solve(data, Part::Two);
|
||||||
|
|
||||||
|
info!("Result part 1: {}", result);
|
||||||
|
info!("Result part 2: {}", result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue