Skip to content

Commit e4c3630

Browse files
committed
optimizations
1 parent 405266a commit e4c3630

File tree

8 files changed

+245
-15
lines changed

8 files changed

+245
-15
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,9 @@ answer.txt
2222

2323
resolve_error.sh
2424
resolve_unknown.sh
25-
.run.db
25+
.run.db
26+
27+
src/year*/day*/Cargo.toml
28+
src/year*/day*/Cargo.lock
29+
src/year*/day*/target/
30+
crates/**/Cargo.lock

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Puzzle | Stars |
2727
[Day 11: Plutonian Pebbles](https://adventofcode.com/2024/day/11) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day11/day11.rs) [![Go](./scripts/assets/go.png)](src/year2024/day11/day11.go)
2828
[Day 12: Garden Groups](https://adventofcode.com/2024/day/12) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day12/day12.rs) [![Go](./scripts/assets/go.png)](src/year2024/day12/day12.go)
2929
[Day 13: Claw Contraption](https://adventofcode.com/2024/day/13) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day13/day13.rs) [![Rust](./scripts/assets/rust.png)](src/year2024/day13_z3/day13_z3.rs) [![Python](./scripts/assets/python.png)](src/year2024/day13_z3/day13.py) [![Go](./scripts/assets/go.png)](src/year2024/day13/day13.go)
30-
[Day 14: Restroom Redoubt](https://adventofcode.com/2024/day/14) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day14/day14.rs) [![Python](./scripts/assets/python.png)](src/year2024/day14/day14.py) [🎁](src/year2024/day14/README.md)
30+
[Day 14: Restroom Redoubt](https://adventofcode.com/2024/day/14) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day14/day14.rs) [![Python](./scripts/assets/python.png)](src/year2024/day14/day14.py) [![Go](./scripts/assets/go.png)](src/year2024/day14/day14.go) [🎁](src/year2024/day14/README.md)
3131
[Day 15: Warehouse Woes](https://adventofcode.com/2024/day/15) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day15/day15.rs) [![Go](./scripts/assets/go.png)](src/year2024/day15/day15.go) [🎁](src/year2024/day15/README.md)
3232
[Day 16: Reindeer Maze](https://adventofcode.com/2024/day/16) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day16/day16.rs) [🎁](src/year2024/day16/README.md)
3333
[Day 17: Chronospatial Computer](https://adventofcode.com/2024/day/17) | ⭐⭐ | [![Rust](./scripts/assets/rust.png)](src/year2024/day17/day17.rs)

src/main.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ fn run_day_single(args: &aoc::Args) {
5858
let sols = solutions(year, day, &alt);
5959

6060
if sols.len() != 1 {
61-
println!("-r requires exactly one solution ({} found with year={year:?} day={day:?} alt={alt:?})", sols.len());
61+
println!(
62+
"-r requires exactly one solution ({} found with year={year:?} day={day:?} alt={alt:?})",
63+
sols.len()
64+
);
6265
std::process::exit(1);
6366
}
6467

@@ -227,7 +230,9 @@ fn run_all(args: &aoc::Args) {
227230

228231
if puzzles > 1 {
229232
println!();
230-
println!("Elapsed: {total_elapsed:#?} for {puzzles} puzzle(s) - success: {success}, failed: {failed}");
233+
println!(
234+
"Elapsed: {total_elapsed:#?} for {puzzles} puzzle(s) - success: {success}, failed: {failed}"
235+
);
231236
}
232237
}
233238

src/year2015/day16/day16.rs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,70 @@ struct Puzzle<'a> {
88
}
99

1010
impl<'a> Puzzle<'a> {
11+
/// Parse the input data using manual string parsing (faster than regex).
12+
/// Parses lines in the format: "Sue 1: goldfish: 6, trees: 9, akitas: 0"
1113
fn new(data: &'a str) -> Self {
1214
let mut aunts: FxHashMap<u32, FxHashMap<&'a str, u32>> = FxHashMap::default();
1315

16+
for line in data.lines() {
17+
let Some(rest) = line.strip_prefix("Sue ") else {
18+
continue;
19+
};
20+
21+
let Some(colon_pos) = rest.find(':') else {
22+
continue;
23+
};
24+
25+
let sue = rest[..colon_pos].parse::<u32>().unwrap();
26+
let mut props = rest[colon_pos + 1..].trim_start();
27+
28+
let mut aunt = FxHashMap::default();
29+
30+
while !props.is_empty() {
31+
// read the pair "<key>: <value>"
32+
let Some(key_end) = props.find(':') else {
33+
break;
34+
};
35+
let key = props[..key_end].trim_end();
36+
37+
props = &props[key_end + 1..];
38+
39+
let value_end = props.find(',').unwrap_or(props.len());
40+
let value = props[..value_end].trim_start().parse::<u32>().unwrap();
41+
42+
aunt.insert(key, value);
43+
44+
// go to next pair
45+
props = props[value_end..].trim_start_matches(',').trim_start();
46+
}
47+
48+
aunts.insert(sue, aunt);
49+
}
50+
Self { aunts }
51+
}
52+
53+
/// Parse the input data using regex (slower but more readable).
54+
/// Parses lines in the format: "Sue 1: goldfish: 6, trees: 9, akitas: 0"
55+
fn new_regex(data: &'a str) -> Self {
56+
let mut aunts: FxHashMap<u32, FxHashMap<&'a str, u32>> = FxHashMap::default();
57+
1458
let re = Regex::new(r"Sue (\d+): (\w+): (\d+), (\w+): (\d+), (\w+): (\d+)").unwrap();
1559

1660
for line in data.lines() {
1761
let m = re.captures(line).unwrap();
1862
let sue = m.get(1).unwrap().as_str().parse::<u32>().unwrap();
1963

64+
let mut aunt = FxHashMap::default();
65+
2066
for i in (2..=6).step_by(2) {
2167
let key = m.get(i).unwrap().as_str();
2268
let value = m.get(i + 1).unwrap().as_str().parse::<u32>().unwrap();
23-
aunts.entry(sue).or_default().insert(key, value);
69+
aunt.insert(key, value);
2470
}
71+
72+
aunts.insert(sue, aunt);
2573
}
74+
2675
Self { aunts }
2776
}
2877

@@ -72,7 +121,17 @@ pub fn solve(data: &str) -> (u32, u32) {
72121
(puzzle.part1(), puzzle.part2())
73122
}
74123

124+
#[must_use]
125+
pub fn solve_regex(data: &str) -> (u32, u32) {
126+
let puzzle = Puzzle::new_regex(data);
127+
(puzzle.part1(), puzzle.part2())
128+
}
129+
75130
pub fn main() {
76131
let args = aoc::parse_args();
77-
args.run(solve);
132+
if args.has_option("--use-regex") {
133+
args.run(solve_regex);
134+
} else {
135+
args.run(solve);
136+
}
78137
}

src/year2022/day19/day19.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ struct Blueprint {
106106

107107
impl Blueprint {
108108
fn new(input: &str) -> Self {
109-
let re= Regex::new(r"Blueprint (\d+): Each ore robot costs (\d+) ore. Each clay robot costs (\d+) ore. Each obsidian robot costs (\d+) ore and (\d+) clay. Each geode robot costs (\d+) ore and (\d+) obsidian.").unwrap();
109+
let re = Regex::new(r"Blueprint (\d+): Each ore robot costs (\d+) ore. Each clay robot costs (\d+) ore. Each obsidian robot costs (\d+) ore and (\d+) clay. Each geode robot costs (\d+) ore and (\d+) obsidian.").unwrap();
110110

111111
let m = re.captures(input).unwrap();
112112

src/year2024/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Puzzle | Stars |
2222
[Day 11: Plutonian Pebbles](https://adventofcode.com/2024/day/11) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day11/day11.rs) [![Go](../../scripts/assets/go.png)](day11/day11.go)
2323
[Day 12: Garden Groups](https://adventofcode.com/2024/day/12) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day12/day12.rs) [![Go](../../scripts/assets/go.png)](day12/day12.go)
2424
[Day 13: Claw Contraption](https://adventofcode.com/2024/day/13) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day13/day13.rs) [![Rust](../../scripts/assets/rust.png)](day13_z3/day13_z3.rs) [![Python](../../scripts/assets/python.png)](day13_z3/day13.py) [![Go](../../scripts/assets/go.png)](day13/day13.go)
25-
[Day 14: Restroom Redoubt](https://adventofcode.com/2024/day/14) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day14/day14.rs) [![Python](../../scripts/assets/python.png)](day14/day14.py) [🎁](day14/README.md)
25+
[Day 14: Restroom Redoubt](https://adventofcode.com/2024/day/14) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day14/day14.rs) [![Python](../../scripts/assets/python.png)](day14/day14.py) [![Go](../../scripts/assets/go.png)](day14/day14.go) [🎁](day14/README.md)
2626
[Day 15: Warehouse Woes](https://adventofcode.com/2024/day/15) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day15/day15.rs) [![Go](../../scripts/assets/go.png)](day15/day15.go) [🎁](day15/README.md)
2727
[Day 16: Reindeer Maze](https://adventofcode.com/2024/day/16) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day16/day16.rs) [🎁](day16/README.md)
2828
[Day 17: Chronospatial Computer](https://adventofcode.com/2024/day/17) | ⭐⭐ | [![Rust](../../scripts/assets/rust.png)](day17/day17.rs)

src/year2024/day13/day13.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! [Day 13: Claw Contraption](https://adventofcode.com/2024/day/13)
22
3-
use regex::Regex;
43
type F = fraction::GenericFraction<i64>;
54

65
struct ClawMachine {
@@ -14,12 +13,23 @@ struct ClawMachine {
1413

1514
impl ClawMachine {
1615
fn parse(s: &str) -> Self {
17-
let re = Regex::new(r"\d+").unwrap();
18-
19-
let values = re
20-
.find_iter(s)
21-
.map(|m| m.as_str().parse::<i64>().unwrap())
22-
.collect::<Vec<_>>();
16+
let mut values = Vec::new();
17+
let mut chars = s.chars().peekable();
18+
19+
// find positive integers into chars
20+
while let Some(ch) = chars.next() {
21+
if let Some(mut num) = ch.to_digit(10).map(i64::from) {
22+
while let Some(next_ch) = chars.peek().copied() {
23+
if let Some(digit) = next_ch.to_digit(10) {
24+
num = num * 10 + i64::from(digit);
25+
chars.next();
26+
} else {
27+
break;
28+
}
29+
}
30+
values.push(num);
31+
}
32+
}
2333

2434
Self {
2535
a_x: F::from(values[0]),

src/year2024/day14/day14.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// [Day 14: Restroom Redoubt](https://adventofcode.com/2024/day/14)
2+
package main
3+
4+
import (
5+
"fmt"
6+
"log"
7+
"os"
8+
"strings"
9+
"time"
10+
)
11+
12+
type Robot struct {
13+
px, py int
14+
vx, vy int
15+
}
16+
17+
type Puzzle struct {
18+
robots []Robot
19+
width int
20+
height int
21+
}
22+
23+
func newPuzzle(data []byte) Puzzle {
24+
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
25+
26+
var robots []Robot
27+
for _, line := range lines {
28+
if line == "" {
29+
continue
30+
}
31+
32+
var robot Robot
33+
fmt.Sscanf(line, "p=%d,%d v=%d,%d", &robot.px, &robot.py, &robot.vx, &robot.vy)
34+
robots = append(robots, robot)
35+
}
36+
37+
return Puzzle{
38+
robots: robots,
39+
width: 101,
40+
height: 103,
41+
}
42+
}
43+
44+
func mod(a, b int) int {
45+
r := a % b
46+
if r < 0 {
47+
r += b
48+
}
49+
return r
50+
}
51+
52+
func (p Puzzle) part1() int {
53+
quadrants := make(map[[2]int]int)
54+
55+
for _, robot := range p.robots {
56+
px := mod(robot.px+robot.vx*100, p.width)
57+
py := mod(robot.py+robot.vy*100, p.height)
58+
59+
if px == p.width/2 || py == p.height/2 {
60+
continue
61+
}
62+
63+
q := [2]int{(px * 2) / p.width, (py * 2) / p.height}
64+
quadrants[q]++
65+
}
66+
67+
product := 1
68+
for _, count := range quadrants {
69+
product *= count
70+
}
71+
return product
72+
}
73+
74+
func (p Puzzle) part2() int {
75+
outer:
76+
for seconds := 0; seconds < 100_000; seconds++ {
77+
grid := make(map[[2]int]struct{})
78+
79+
for _, robot := range p.robots {
80+
px := mod(robot.px+robot.vx*seconds, p.width)
81+
py := mod(robot.py+robot.vy*seconds, p.height)
82+
83+
key := [2]int{px, py}
84+
if _, exists := grid[key]; exists {
85+
continue outer
86+
}
87+
grid[key] = struct{}{}
88+
}
89+
90+
horizontalLines := 0
91+
for y := 0; y < p.height; y++ {
92+
for x := 0; x < p.width-10; x++ {
93+
line := true
94+
for i := x; i < x+5; i++ {
95+
if _, ok := grid[[2]int{i, y}]; !ok {
96+
line = false
97+
break
98+
}
99+
}
100+
if line {
101+
horizontalLines++
102+
}
103+
}
104+
}
105+
106+
if horizontalLines > 5 {
107+
return seconds
108+
}
109+
}
110+
111+
return 0
112+
}
113+
114+
func solve(data []byte) (int, int) {
115+
puzzle := newPuzzle(data)
116+
return puzzle.part1(), puzzle.part2()
117+
}
118+
119+
func main() {
120+
filename := "input.txt"
121+
elapsed := false
122+
123+
for i := 1; i < len(os.Args); i++ {
124+
arg := os.Args[i]
125+
if arg == "--elapsed" {
126+
elapsed = true
127+
} else if !strings.HasPrefix(arg, "-") {
128+
filename = arg
129+
}
130+
}
131+
132+
data, err := os.ReadFile(filename)
133+
if err != nil {
134+
log.Fatal(err)
135+
}
136+
137+
if elapsed {
138+
start := time.Now()
139+
result1, result2 := solve(data)
140+
duration := time.Since(start)
141+
142+
fmt.Println(result1)
143+
fmt.Println(result2)
144+
fmt.Printf("elapsed: %f ms\n", duration.Seconds()*1000.0)
145+
} else {
146+
result1, result2 := solve(data)
147+
148+
fmt.Println(result1)
149+
fmt.Println(result2)
150+
}
151+
}

0 commit comments

Comments
 (0)