Skip to content

Commit

Permalink
Merge pull request #1 from nottu/smaller-get_card_matches
Browse files Browse the repository at this point in the history
Smaller get card matches
  • Loading branch information
nottu authored Dec 8, 2023
2 parents 3e69efd + 2b00aff commit 0821efa
Show file tree
Hide file tree
Showing 15 changed files with 2,698 additions and 25 deletions.
53 changes: 28 additions & 25 deletions src/bin/day4.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::HashSet;

fn main() {
let input = include_str!("day4/input.txt");
Expand Down Expand Up @@ -34,29 +34,28 @@ fn parse_card(card: &str) -> usize {
}

fn get_card_matches(cards: &str) -> usize {
let cards = cards.split(':').nth(1).unwrap();
let cards = cards.split('|').collect::<Vec<&str>>();
let cards = cards
.split(':')
.nth(1)
.expect("card should be formatted like 'Card <id> : <data>', no ':' character found")
.split('|')
.collect::<Vec<&str>>();

// we assume card numbers can repeat themselves...
let mut right_side: HashMap<&str, usize> = HashMap::new();
for num in cards[1].trim().split(' ') {
let num = num.trim();
*right_side.entry(num).or_default() += 1;
}
let right_side: HashSet<_> = cards[1]
.trim()
.split(' ')
.map(|num| num.trim())
.filter(|num| !num.is_empty())
.collect();

cards[0]
let left_side: HashSet<_> = cards[0]
.trim()
.split(' ')
.filter(|number| {
let curr_count = right_side.entry(number.trim()).or_default();
if number.is_empty() || *curr_count == 0 {
false
} else {
*curr_count -= 1;
true
}
})
.count()
.map(|num| num.trim())
.filter(|num| !num.is_empty())
.collect();

left_side.intersection(&right_side).count()
}

#[test]
Expand All @@ -67,11 +66,15 @@ fn day4_test_part2() {

fn part2(input: &str) -> String {
let parse_cards: Vec<_> = input.lines().map(get_card_matches).collect();
let mut parsed_cards_counts = vec![1; parse_cards.len()];
let mut card_counter = vec![0; parse_cards.len() + 1];
card_counter[0] = 1;
let mut count = 0;
let mut total_card_count = 0;
for (idx, score) in parse_cards.into_iter().enumerate() {
for count_idx in 1..=score {
parsed_cards_counts[idx + count_idx] += parsed_cards_counts[idx];
}
count += card_counter[idx];
total_card_count += count;
card_counter[idx + 1] += count;
card_counter[idx + score + 1] -= count;
}
parsed_cards_counts.iter().sum::<usize>().to_string()
total_card_count.to_string()
}
193 changes: 193 additions & 0 deletions src/bin/day5.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
fn main() {
let input = include_str!("day5/input.txt");
dbg!(part1(input));

let input = include_str!("day5/input.txt");
dbg!(part2(input));
}

#[test]
fn day5_test_part1() {
let input = include_str!("day5/test_input.txt");
assert_eq!(part1(input), "35")
}

fn part1(input: &str) -> String {
let mut input_lines = input.lines();

let seeds: Vec<u32> = input_lines
.next()
.expect("at least one line")
.split(':')
.nth(1)
.unwrap()
.trim()
.split(' ')
.filter(|s| !s.is_empty())
.map(|num| num.parse().unwrap())
.collect();
let maps = {
input_lines.next();
let lines: Vec<&str> = input_lines.collect();
let mut idx = 1;
let seed_soil_map = read_map(&lines[idx..]);
idx += 2 + seed_soil_map.len();
let soil_fert_map = read_map(&lines[idx..]);
idx += 2 + soil_fert_map.len();
let fert_water_map = read_map(&lines[idx..]);
idx += 2 + fert_water_map.len();
let water_light_map = read_map(&lines[idx..]);
idx += 2 + water_light_map.len();
let light_temp_map = read_map(&lines[idx..]);
idx += 2 + light_temp_map.len();
let temp_humidity_map = read_map(&lines[idx..]);
idx += 2 + temp_humidity_map.len();
let humidity_location_map = read_map(&lines[idx..]);

[
seed_soil_map,
soil_fert_map,
fert_water_map,
water_light_map,
light_temp_map,
temp_humidity_map,
humidity_location_map,
]
};

seeds
.into_iter()
.map(|seed| {
// println!("_______________");
maps.iter().fold(seed, |item, map_rels| {
// dbg!(map_rels, item);
let pp = map_rels.partition_point(|m| m.from <= item);
if pp == 0 {
item
} else {
let pp = pp - 1;
// dbg!(map_rels, pp);
let diff = item - map_rels[pp].from;

// dbg!(item, mapped);
if diff + 1 > map_rels[pp].range {
item
} else {
diff + map_rels[pp].to
}
}
})
})
.min()
.unwrap()
.to_string()
}

#[derive(Debug)]
struct MapRel {
to: u32,
from: u32,
range: u32,
}

fn read_map(lines: &[&str]) -> Vec<MapRel> {
let mut compressed_map = vec![];
for line in lines {
if line.is_empty() {
break;
}
let nums: Vec<_> = line.split(' ').map(|num| num.parse().unwrap()).collect();
compressed_map.push(MapRel {
to: nums[0],
from: nums[1],
range: nums[2],
});
}
compressed_map.sort_by_key(|m| m.from);
compressed_map
}

#[test]
fn day5_test_part2() {
let input = include_str!("day5/test_input.txt");
assert_eq!(part2(input), "46")
}

fn part2(input: &str) -> String {
let mut input_lines = input.lines();

let seeds: Vec<u32> = input_lines
.next()
.expect("at least one line")
.split(':')
.nth(1)
.unwrap()
.trim()
.split(' ')
.filter(|s| !s.is_empty())
.map(|num| num.parse().unwrap())
.collect();
let maps = {
input_lines.next();
let lines: Vec<&str> = input_lines.collect();
let mut idx = 1;
let seed_soil_map = read_map(&lines[idx..]);
idx += 2 + seed_soil_map.len();
let soil_fert_map = read_map(&lines[idx..]);
idx += 2 + soil_fert_map.len();
let fert_water_map = read_map(&lines[idx..]);
idx += 2 + fert_water_map.len();
let water_light_map = read_map(&lines[idx..]);
idx += 2 + water_light_map.len();
let light_temp_map = read_map(&lines[idx..]);
idx += 2 + light_temp_map.len();
let temp_humidity_map = read_map(&lines[idx..]);
idx += 2 + temp_humidity_map.len();
let humidity_location_map = read_map(&lines[idx..]);

[
seed_soil_map,
soil_fert_map,
fert_water_map,
water_light_map,
light_temp_map,
temp_humidity_map,
humidity_location_map,
]
};

let mut curr_min = u32::MAX;
for idx in 0..seeds.len() / 2 {
let idx = 2 * idx;
let seed = seeds[idx];
let range = seeds[idx + 1];
curr_min = curr_min.min(
(0..range)
.map(|i| seed + i)
.map(|seed| {
// println!("_______________");
maps.iter().fold(seed, |item, map_rels| {
// dbg!(map_rels, item);
let pp = map_rels.partition_point(|m| m.from <= item);
if pp == 0 {
item
} else {
let pp = pp - 1;
// dbg!(map_rels, pp);
let diff = item - map_rels[pp].from;

// dbg!(item, mapped);
if diff + 1 > map_rels[pp].range {
item
} else {
diff + map_rels[pp].to
}
}
})
})
.min()
.unwrap(),
);
}
curr_min.to_string()
}
Loading

0 comments on commit 0821efa

Please # to comment.