From 780171280f9581d5a59e8fd9f54fb2dabacfbe99 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Mon, 4 Dec 2023 13:25:47 +0530 Subject: [PATCH] day4: optimized --- Cargo.lock | 16 --------- Cargo.toml | 1 - src/day4/1.rs | 43 +++++++++++++++-------- src/day4/2.rs | 94 ++++++++++++++++++++++++++++++++++----------------- 4 files changed, 91 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6af94af..5ad0563 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,6 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" name = "aoc2023" version = "0.1.0" dependencies = [ - "fxhash", "ureq", ] @@ -22,12 +21,6 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cc" version = "1.0.83" @@ -71,15 +64,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "getrandom" version = "0.2.11" diff --git a/Cargo.toml b/Cargo.toml index 7780621..912dde1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ codegen-units = 16 rpath = false [dependencies] -fxhash = "0.2.1" ureq = { version = "2.9.1" } diff --git a/src/day4/1.rs b/src/day4/1.rs index 1cf2753..06ba1b7 100644 --- a/src/day4/1.rs +++ b/src/day4/1.rs @@ -1,8 +1,5 @@ #![feature(slice_split_once)] #![feature(test)] - -use fxhash::FxHashSet; - extern crate test; const INPUTS: [&[u8]; 2] = [ @@ -11,9 +8,8 @@ const INPUTS: [&[u8]; 2] = [ ]; fn process(data: &[u8]) -> u64 { - let mut win_num = FxHashSet::default(); - let mut total = 0; + for data in data.split(|&x| x == b'\n') { if data.is_empty() { continue; @@ -22,25 +18,26 @@ fn process(data: &[u8]) -> u64 { let (_, nums) = data.split_once(|&x| x == b':').unwrap(); let (nums, wins) = nums.split_once(|&x| x == b'|').unwrap(); - let nums = nums.split(|&x| x == b' '); - let wins = wins.split(|&x| x == b' '); - for win in wins { + let mut bit_map = BitMap::new(); + + for win in wins.split(|&x| x == b' ') { if win.is_empty() { continue; } let win = parse(win); - win_num.insert(win); + bit_map.set(win); } let mut val = 0; - for num in nums { + for num in nums.split(|&x| x == b' ') { if num.is_empty() { continue; } let num = parse(num); - if win_num.contains(&num) { + + if bit_map.get(num) { if val == 0 { val = 1; } else { @@ -50,20 +47,36 @@ fn process(data: &[u8]) -> u64 { } total += val; - - win_num.clear(); } total } +struct BitMap(u128); +impl BitMap { + #[inline] + pub const fn new() -> Self { + Self(0) + } + #[inline] + pub fn set(&mut self, idx: usize) { + debug_assert!(idx < 128); + self.0 |= 1 << idx; + } + #[inline] + pub const fn get(&self, idx: usize) -> bool { + debug_assert!(idx < 128); + (self.0 >> idx) & 1 == 1 + } +} + #[inline] -fn parse(b: &[u8]) -> u64 { +fn parse(b: &[u8]) -> usize { let mut out = 0; let mut pow = 1; for c in b.iter().rev() { - out += (c - b'0') as u64 * pow; + out += (c - b'0') as usize * pow; pow *= 10; } diff --git a/src/day4/2.rs b/src/day4/2.rs index 77ad08c..5b10e20 100644 --- a/src/day4/2.rs +++ b/src/day4/2.rs @@ -1,73 +1,105 @@ #![feature(test)] +#![feature(slice_split_once)] -use std::collections::HashSet; extern crate test; -const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")]; +const INPUTS: [&[u8]; 2] = [ + include_bytes!("./sample.txt"), + include_bytes!("./input.txt"), +]; -fn process(data: &str) -> u64 { +fn process(data: &[u8]) -> usize { let mut cards = vec![]; - let mut total = 0; - for data in data.lines() { - let (x, nums) = data.split_once(':').unwrap(); + for data in data.split(|&x| x == b'\n') { + if data.is_empty() { + continue; + } + let (x, nums) = data.split_once(|&x| x == b':').unwrap(); - let v = x.split_at(4).1.trim(); - let id = v.parse::().unwrap(); + let id = parse(&x[5..]); - let (nums, wins) = nums.split_once('|').unwrap(); - let nums: Vec<&str> = nums.split(' ').collect(); - let wins: Vec<&str> = wins.split(' ').collect(); + let (nums, wins) = nums.split_once(|&x| x == b'|').unwrap(); + let nums = nums.split(|&x| x == b' '); + let wins = wins.split(|&x| x == b' '); - let mut card = vec![]; - let mut win = HashSet::new(); + let mut card = BitMap::new(); + let mut win = BitMap::new(); for num in nums { if num.is_empty() { continue; } - let num = num.parse::().unwrap(); + let num = parse(num); - card.push(num); + card.set(num); } for w in wins { if w.is_empty() { continue; } - let num = w.parse::().unwrap(); - win.insert(num); + let num = parse(w); + win.set(num); } cards.push((id, card, win)); } - let mut stack: Vec<(usize, Vec, HashSet)> = cards.iter().rev().cloned().collect(); + let mut counter = vec![1; cards.len() + 1]; + counter[0] = 0; - let mut count = vec![0; cards.len() + 1]; - - while let Some((id, card, wins)) = stack.pop() { + for (id, card, wins) in cards.into_iter() { let mut sum = 0; - for c in card { - if wins.contains(&c) { + for c in 0..100 { + if card.get(c) && wins.get(c) { sum += 1; } } - count[id] += 1; - - for i in id..id + sum { - stack.push(cards[i].clone()) + let cid = counter[id]; + for c in counter.iter_mut().skip(id + 1).take(sum) { + *c += cid; } } - for c in count.iter().skip(1) { - total += c; + counter.into_iter().sum::() +} + +#[derive(Clone)] +struct BitMap(u128); +impl BitMap { + #[inline] + pub const fn new() -> Self { + Self(0) + } + #[inline] + pub fn set(&mut self, idx: usize) { + debug_assert!(idx < 128); + self.0 |= 1 << idx; + } + #[inline] + pub const fn get(&self, idx: usize) -> bool { + debug_assert!(idx < 128); + (self.0 >> idx) & 1 == 1 + } +} + +#[inline] +fn parse(b: &[u8]) -> usize { + let mut out = 0; + + let mut pow = 1; + for c in b.iter().rev() { + if !c.is_ascii_digit() { + continue; + } + out += (c - b'0') as usize * pow; + pow *= 10; } - println!("{:?}", count); - total + out } fn main() {