Skip to content

Commit

Permalink
2023-15
Browse files Browse the repository at this point in the history
  • Loading branch information
fornwall committed Dec 15, 2023
1 parent c82033b commit d52f038
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 7 deletions.
36 changes: 36 additions & 0 deletions crates/core/src/common/array_stack.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[derive(Clone)]
pub struct ArrayStack<const MAX_SIZE: usize, H: Eq + Copy + Clone + Default> {
pub elements: [H; MAX_SIZE],
len: usize,
Expand All @@ -11,6 +12,13 @@ impl<const MAX_SIZE: usize, H: Eq + Copy + Clone + Default> ArrayStack<MAX_SIZE,
}
}

pub const fn new_const(initial: H) -> Self {
Self {
elements: [initial; MAX_SIZE],
len: 0,
}
}

pub fn push(&mut self, element: H) -> Result<(), String> {
if self.len == MAX_SIZE {
return Err("Too many elements pushed".to_string());
Expand Down Expand Up @@ -42,4 +50,32 @@ impl<const MAX_SIZE: usize, H: Eq + Copy + Clone + Default> ArrayStack<MAX_SIZE,
self.len -= 1;
result
}

pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&H) -> bool,
{
let mut i = 0;
while i < self.len {
if f(&self.elements[i]) {
i += 1;
} else {
self.elements.copy_within(i + 1..self.len, i);
self.len -= 1;
}
}
}
}

#[allow(clippy::unwrap_used)]
#[test]
fn retain() {
let mut a = ArrayStack::<10, u32>::new();
a.push(1).unwrap();
a.push(2).unwrap();
a.push(3).unwrap();
a.push(4).unwrap();
a.retain(|&b| b % 2 == 0);
assert_eq!(2, a.len());
assert_eq!(&[2, 4], a.slice());
}
101 changes: 94 additions & 7 deletions crates/core/src/year2023/day15.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,105 @@
use crate::common::array_stack::ArrayStack;
use crate::input::Input;

pub const fn solve(_input: &Input) -> Result<u64, String> {
Ok(0)
pub fn solve(input: &Input) -> Result<u32, String> {
const LENSES: ArrayStack<8, Lens> = ArrayStack::new_const(Lens {
label: 0,
focal_length: 0,
});

if input.is_part_one() {
return Ok(input
.text
.split(',')
.map(|word| hash(word.as_bytes()))
.sum());
}

let mut boxes = [LENSES; 256];

for step in input.text.split(',') {
let (label, operation) = step.strip_suffix('-').map_or_else(
|| {
let label = &step[..step.len() - 2];
let focal_length = u32::from(step.as_bytes()[step.len() - 1] - b'0');
(label, Operation::Put(focal_length))
},
|label| (label, Operation::RemoveLabel),
);

let lenses = &mut boxes[hash(label.as_bytes()) as usize];
let label = label_value(label.as_bytes());

match operation {
Operation::RemoveLabel => {
lenses.retain(|x| x.label != label);
}
Operation::Put(focal_length) => {
if !lenses.slice_mut().iter_mut().any(|lens| {
if lens.label == label {
lens.focal_length = focal_length;
true
} else {
false
}
}) {
lenses.push(Lens {
label,
focal_length,
})?;
}
}
}
}

Ok(boxes
.iter()
.enumerate()
.map(|(box_number, lenses)| {
(box_number + 1) as u32
* lenses
.slice()
.iter()
.enumerate()
.map(|(slot_idx, lens)| (slot_idx + 1) as u32 * lens.focal_length)
.sum::<u32>()
})
.sum())
}

enum Operation {
RemoveLabel,
Put(u32),
}

#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
struct Lens {
label: u32,
focal_length: u32,
}

fn hash(word: &[u8]) -> u32 {
word.iter()
.fold(0, |acc, &x| ((acc + u32::from(x)) * 17) & 0xff)
}

fn label_value(label: &[u8]) -> u32 {
label.iter().fold(0, |acc, &x| {
acc * u32::from(b'z' - b'a') + u32::from(x - b'a')
})
}

#[test]
pub fn tests() {
use crate::input::{test_part_one_no_allocations, test_part_two_no_allocations};

let test_input = "0";
test_part_one_no_allocations!(test_input => 0);
test_part_two_no_allocations!(test_input => 0);
let test_input = "HASH";
test_part_one_no_allocations!(test_input => 52);
let test_input = "rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7";
test_part_one_no_allocations!(test_input => 1320);
test_part_two_no_allocations!(test_input => 145);

let real_input = include_str!("day15_input.txt");
test_part_one_no_allocations!(real_input => 0);
test_part_two_no_allocations!(real_input => 0);
test_part_one_no_allocations!(real_input => 513_158);
test_part_two_no_allocations!(real_input => 200_277);
}
Loading

1 comment on commit d52f038

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@                     Benchmark Difference                    @@
#     Name   Old (instructions)   New (instructions)   Change (%)
  2023_1_1            1,453,013            1,453,000            0
  2023_1_2            1,426,883            1,426,870            0
  2023_2_1              614,090              614,077            0
  2023_2_2              590,031              590,018            0
  2023_3_1              928,566              928,553            0
  2023_3_2              674,579              674,566            0
Benchmark Instructions (count) Instructions (%)
2023_1_1 1,453,000 25.5
2023_1_2 1,426,870 25.1
2023_3_1 928,553 16.3
2023_3_2 674,566 11.9
2023_2_1 614,077 10.8
2023_2_2 590,018 10.4

Please sign in to comment.