Skip to content

Commit

Permalink
refactor(2023): use hashsets for day 4
Browse files Browse the repository at this point in the history
  • Loading branch information
believer committed Dec 4, 2023
1 parent c970c63 commit 642403d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 44 deletions.
19 changes: 10 additions & 9 deletions rust/2023/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ You try to ask why they can't just use a weather machine ("not powerful enough")

With the help of [cargo-aoc](https://github.com/gobanos/cargo-aoc) I get automatic benchmarking using [Criterion](https://github.com/bheisler/criterion.rs). Computer is a MacBook Pro M1 Pro, 32 GB RAM.

| Day | #1 | #2 | Improvement\* | Generator |
| --- | --------: | -------: | ------------- | --------: |
| 1 | 43.18 ns | 1.19 ms | | 441.01 ns |
| 2 | 764.68 ns | 1.75 µs | | 47.81 µs |
| 3 | 159.61 µs | 7.72 ms | `-8.44%` | 86.83 µs |
| 3 | 24.33 µs | 24.32 µs | | 128.62 µs |
| Day | #1 | #2 | Improvement\* | Generator |
| --- | --------: | -------: | --------------------- | --------: |
| 1 | 43.18 ns | 1.19 ms | | 441.01 ns |
| 2 | 764.68 ns | 1.75 µs | | 47.81 µs |
| 3 | 159.61 µs | 7.72 ms | `-8.44%` | 86.83 µs |
| 4 | 12.85 µs | 13.09 µs | `-48.41%` / `-46.64%` | 230.06 µs |

\* compared to first solution

### Previous solutions

| Day | #1 | #2 | Improvement | Link |
| --: | --------: | --: | ----------: | ---- |
| 3 | 172.23 µs | - | | |
| Day | #1 | #2 | Improvement | Link |
| --: | --------: | -------: | ----------: | --------- |
| 3 | 172.23 µs | - | | |
| 4 | 24.33 µs | 24.32 µs | | 128.62 µs |
63 changes: 28 additions & 35 deletions rust/2023/src/day_04.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::collections::HashSet;

// Day 4: Scratchcards
//
// Part one went fast, but part two took a while. I also took a 20 minutes break
// to watch the latest episode of the Swedish TV advent calendar with the kids :D
//
// I think there are some improvements to be made in the code, which I'll look
// at later today.
// Refactored to a HashSet which also allows us to use intersections
// to find how many winning numbers we have. The input parser got a bit
// slower, but the solvers got a lot faster.

type Input = Vec<(Vec<u32>, Vec<u32>)>;
type Cards = HashSet<u32>;
type Input = Vec<(Cards, Cards)>;

#[aoc_generator(day4)]
pub fn input_generator(input: &str) -> Input {
Expand All @@ -15,20 +19,19 @@ pub fn input_generator(input: &str) -> Input {
for line in input.lines() {
let line = &line[5..];
let (_, line) = line.split_once(": ").unwrap();
let line = line.trim();
let (winning, losing) = line.split_once(" | ").unwrap();
let (winning, my_numbers) = line.split_once(" | ").unwrap();

let winning: Vec<u32> = winning
let winning = winning
.split_whitespace()
.map(|x| x.trim().parse().unwrap())
.collect();

let my_cards: Vec<u32> = losing
let my_numbers = my_numbers
.split_whitespace()
.map(|x| x.trim().parse().unwrap())
.collect();

numbers.push((winning, my_cards));
numbers.push((winning, my_numbers));
}

numbers
Expand Down Expand Up @@ -58,25 +61,19 @@ pub fn input_generator(input: &str) -> Input {
/// ```
#[aoc(day4, part1)]
pub fn solve_part_01(input: &Input) -> u32 {
let mut sum = 0;

for (winning, my_cards) in input {
let mut card_sum = 0;

for card in my_cards {
if winning.contains(card) {
if card_sum == 0 {
card_sum = 1;
} else {
card_sum *= 2;
}
}
}

sum += card_sum;
}

sum
input
.iter()
.map(
|(winning, my_numbers)| match winning.intersection(my_numbers).count() {
0 => 0,
1 => 1,
// With help from ChatGPT I got the following formula: 2^(n-1)
// This works perfectly for any number other than the special
// cases for 0 and 1.
n => 2u32.pow((n - 1) as u32),
},
)
.sum()
}

/* Part Two
Expand All @@ -98,17 +95,13 @@ pub fn solve_part_01(input: &Input) -> u32 {
/// ```
#[aoc(day4, part2)]
pub fn solve_part_02(input: &Input) -> u32 {
// Create a list of starting cards, one of each
let mut cards = vec![1; input.len()];

for (i, (winning, my_cards)) in input.iter().enumerate() {
let mut winning_cards = 0;

for card in my_cards {
if winning.contains(card) {
winning_cards += 1;
}
}
for (i, (winning, my_numbers)) in input.iter().enumerate() {
let winning_cards = winning.intersection(my_numbers).count();

// Add the number of winning cards to the next cards
for x in (i + 1)..=(winning_cards + i) {
cards[x] += cards[i];
}
Expand Down

0 comments on commit 642403d

Please sign in to comment.