diff --git a/Cargo.toml b/Cargo.toml
index bb5bf12..04fca26 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,3 +9,8 @@ edition = "2021"
anyhow = "1.0"
cached = "0.26.2"
itertools = "0.10.1"
+
+[profile.release]
+lto = true
+codegen-units = 1
+panic = "abort"
diff --git a/flamegraph.svg b/flamegraph.svg
new file mode 100644
index 0000000..676837a
--- /dev/null
+++ b/flamegraph.svg
@@ -0,0 +1,414 @@
+
\ No newline at end of file
diff --git a/src/day02.rs b/src/day02.rs
index 72a39dc..1c1b66c 100644
--- a/src/day02.rs
+++ b/src/day02.rs
@@ -1,18 +1,23 @@
use anyhow::Result;
-fn parse_line(s: &str) -> (&str, i32) {
- let parsed: Vec<&str> = s.splitn(2, ' ').collect();
- let instruction = parsed[0];
- let quantity = parsed[1].parse::().unwrap();
+fn parse_line(s: &str) -> (char, i32) {
+ let mut parsed = s.split_ascii_whitespace();
+ let instruction = match parsed.next().unwrap() {
+ "forward" => 'f',
+ "down" => 'd',
+ "up" => 'u',
+ _ => unreachable!(),
+ };
+ let quantity = parsed.next().unwrap().parse::().unwrap();
(instruction, quantity)
}
fn follow_course(s: &str) -> i32 {
let (mut pos, mut depth) = (0, 0);
s.lines().for_each(|line| match parse_line(line) {
- ("forward", d) => pos += d,
- ("down", d) => depth += d,
- ("up", d) => depth -= d,
+ ('f', d) => pos += d,
+ ('d', d) => depth += d,
+ ('u', d) => depth -= d,
_ => unreachable!(),
});
pos * depth
@@ -21,12 +26,12 @@ fn follow_course(s: &str) -> i32 {
fn follow_course_better(s: &str) -> i32 {
let (mut pos, mut depth, mut aim) = (0, 0, 0);
s.lines().for_each(|line| match parse_line(line) {
- ("forward", d) => {
+ ('f', d) => {
pos += d;
depth += aim * d;
}
- ("down", d) => aim += d,
- ("up", d) => aim -= d,
+ ('d', d) => aim += d,
+ ('u', d) => aim -= d,
_ => unreachable!(),
});
pos * depth
diff --git a/src/day03.rs b/src/day03.rs
index 27964e0..f4b1c0f 100644
--- a/src/day03.rs
+++ b/src/day03.rs
@@ -39,8 +39,8 @@ fn find_oxygen_or_co2(s: &str, oxygen: bool) -> usize {
.rev()
.map(|bit| {
// split current set into ones/zeroes for current bit
- let mut ones = vec![];
- let mut zeroes = vec![];
+ let mut ones = Vec::with_capacity(kept.len());
+ let mut zeroes = Vec::with_capacity(kept.len());
kept.iter().for_each(|x| {
if x & (1 << bit) != 0 {
ones.push(*x);
diff --git a/src/day05.rs b/src/day05.rs
index b178f89..9a501c3 100644
--- a/src/day05.rs
+++ b/src/day05.rs
@@ -12,17 +12,40 @@ impl LineSegment {
self.start.0 == self.end.0 || self.start.1 == self.end.1
}
- fn rasterize(&self) -> Vec<(isize, isize)> {
- let xstep = (self.end.0 - self.start.0).signum();
- let ystep = (self.end.1 - self.start.1).signum();
- let mut ret = vec![self.start];
- let (mut x, mut y) = self.start;
- while (x, y) != self.end {
- x += xstep;
- y += ystep;
- ret.push((x, y));
+ fn rasterize(&self) -> LineSegmentPixelIter {
+ let dx = self.end.0 - self.start.0;
+ let dy = self.end.1 - self.start.1;
+ LineSegmentPixelIter {
+ x: self.start.0,
+ y: self.start.1,
+ xstep: dx.signum(),
+ ystep: dy.signum(),
+ length: dx.abs().max(dy.abs()) + 1,
+ i: 0,
+ }
+ }
+}
+
+struct LineSegmentPixelIter {
+ x: isize,
+ y: isize,
+ xstep: isize,
+ ystep: isize,
+ length: isize,
+ i: isize,
+}
+
+impl Iterator for LineSegmentPixelIter {
+ type Item = (isize, isize);
+
+ fn next(&mut self) -> Option {
+ if self.i < self.length {
+ let ret = (self.x + self.i * self.xstep, self.y + self.i * self.ystep);
+ self.i += 1;
+ Some(ret)
+ } else {
+ None
}
- ret
}
}
@@ -50,21 +73,23 @@ fn parse_lines(input: &str) -> Vec {
}
fn count_overlapped_cells(segments: &[LineSegment], includ_diag: bool) -> usize {
- let mut marks: Vec<(isize, isize)> = segments
+ let mut cells: Vec> = vec![vec![0; 1000]; 1000];
+ segments
.iter()
.filter(|s| s.is_horizontal_or_vertical() || includ_diag)
- .map(|s| s.rasterize())
- .flatten()
- .collect();
- // sort so we can find duplicates
- // **NOTE** IterTools has `.duplicates()` but it's significantly slower (more than 2x) than this
- marks.sort_unstable();
- marks[..]
- .iter()
- .zip(&marks[1..])
- .filter(|(a, b)| a == b)
- .unique()
- .count()
+ .map(|s| {
+ s.rasterize()
+ .map(|(x, y)| -> usize {
+ cells[x as usize][y as usize] += 1;
+ if cells[x as usize][y as usize] == 2 {
+ 1
+ } else {
+ 0
+ }
+ })
+ .sum::()
+ })
+ .sum::()
}
pub(crate) fn run() -> Result<(usize, usize)> {
diff --git a/src/day07.rs b/src/day07.rs
index 4fab6d4..651c9bc 100644
--- a/src/day07.rs
+++ b/src/day07.rs
@@ -24,7 +24,8 @@ fn compute_fuel(positions: &[isize], target: isize, cheap_fuel: bool) -> usize {
fn find_cheapest_location(positions: &[isize], cheap_fuel: bool) -> usize {
// find start point
- let mut position = get_median(positions);
+ let start = get_median(positions);
+ let mut position = start;
let mut fuel = compute_fuel(positions, position, cheap_fuel);
// search up
@@ -36,6 +37,9 @@ fn find_cheapest_location(positions: &[isize], cheap_fuel: bool) -> usize {
position += 1;
fuel = new_fuel;
}
+ if position != start {
+ return fuel;
+ }
// search down
loop {
diff --git a/src/main.rs b/src/main.rs
index 4e99ff9..a380ad8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+use std::env;
+
use anyhow::Result;
mod day01;
@@ -9,19 +11,32 @@ mod day06;
mod day07;
mod utils;
-fn main() -> Result<()> {
- let dayfns = [
- day01::run,
- day02::run,
- day03::run,
- day04::run,
- day05::run,
- day06::run,
- day07::run,
- ];
+// used to generate more runs when profiling
+const RUNS: usize = 1;
- for (i, f) in dayfns.iter().enumerate() {
- println!("Day {:02} -> {:?}", i, f()?);
+fn main() -> Result<()> {
+ let args: Vec = env::args().collect();
+
+ for _ in 0..RUNS {
+ for (i, f) in [
+ day01::run,
+ day02::run,
+ day03::run,
+ day04::run,
+ day05::run,
+ day06::run,
+ day07::run,
+ ]
+ .iter()
+ .enumerate()
+ {
+ if args.len() == 1 || args.contains(&(i + 1).to_string()) {
+ let result = f()?;
+ if RUNS == 1 {
+ println!("Day {:02} -> {:?}", i + 1, result);
+ }
+ }
+ }
}
Ok(())