Skip to content

Commit 6fb9836

Browse files
committed
refactor: apply aoc-rust-common to 2015 days 6-10
1 parent b567cbc commit 6fb9836

7 files changed

Lines changed: 147 additions & 399 deletions

File tree

2015/src/day03.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn get_visited_multiple_times(first: Santa, second: Santa) -> usize {
5858
for (key, value) in second.visited.iter() {
5959
visited.insert(*key, *value);
6060
}
61-
visited.values().filter(|&x| *x >= &1).count()
61+
visited.values().filter(|&x| *x >= 1).count()
6262
}
6363

6464
impl Solution for Day03 {

2015/src/day06.rs

Lines changed: 41 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use crate::{Exercise, Solvable};
1+
use aoc_rust_common::Solution;
2+
use std::fmt::Display;
23
use rayon::prelude::*;
34

4-
struct SixthDay {
5-
exercise: Exercise,
6-
}
5+
pub struct Day06;
76

87
type Grid = [[bool; 1000]; 1000];
98
type GridAmbient = [[i8; 1000]; 1000];
@@ -34,32 +33,6 @@ fn apply_on_ambient_grid(instruction: Instruction, grid: &mut GridAmbient) {
3433
}
3534
}
3635

37-
fn apply_instructions(instructions: Vec<Instruction>, grid: &mut Grid) {
38-
for instruction in instructions {
39-
apply_on_grid(instruction, grid);
40-
}
41-
}
42-
43-
fn apply_increasing_instructions(instructions: Vec<Instruction>, grid: &mut GridAmbient) {
44-
for instruction in instructions {
45-
apply_on_ambient_grid(instruction, grid);
46-
}
47-
}
48-
49-
fn count_lit(grid: &Grid) -> i64 {
50-
grid.par_iter()
51-
.flat_map(|row| row.par_iter())
52-
.filter(|&&cell| cell)
53-
.count() as i64
54-
}
55-
56-
fn count_brigthness(grid: &GridAmbient) -> i64 {
57-
grid.par_iter()
58-
.flat_map(|row| row.par_iter())
59-
.map(|&cell| cell as i64)
60-
.sum()
61-
}
62-
6336
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
6437
enum Action {
6538
On,
@@ -72,13 +45,14 @@ impl TryFrom<&str> for Action {
7245

7346
fn try_from(value: &str) -> Result<Self, Self::Error> {
7447
if value.starts_with("turn on") {
75-
return Ok(Action::On);
48+
Ok(Action::On)
7649
} else if value.starts_with("turn off") {
77-
return Ok(Action::Off);
50+
Ok(Action::Off)
7851
} else if value.starts_with("toggle") {
79-
return Ok(Action::Toggle);
52+
Ok(Action::Toggle)
53+
} else {
54+
Err(String::from("Invalid action"))
8055
}
81-
Err(String::from("Invalid action"))
8256
}
8357
}
8458

@@ -93,9 +67,9 @@ impl TryFrom<&str> for Instruction {
9367

9468
fn try_from(value: &str) -> Result<Self, Self::Error> {
9569
let mut split = value.split_whitespace().collect::<Vec<&str>>();
96-
let end: Point = Point::try_from(split.pop().unwrap())?;
70+
let end: Point = Point::try_from(split.pop().ok_or("Missing end point")?)?;
9771
split.pop();
98-
let start: Point = Point::try_from(split.pop().unwrap())?;
72+
let start: Point = Point::try_from(split.pop().ok_or("Missing start point")?)?;
9973
let action: Action = Action::try_from(split.join(" ").as_str())?;
10074
Ok(Instruction { action, start, end })
10175
}
@@ -115,88 +89,59 @@ impl TryFrom<&str> for Point {
11589

11690
fn try_from(value: &str) -> Result<Self, Self::Error> {
11791
let mut split = value.split(',');
118-
let x = split.next().unwrap().parse::<i32>().unwrap();
119-
let y = split.next().unwrap().parse::<i32>().unwrap();
92+
let x = split.next().ok_or("Missing x")?.parse::<i32>().map_err(|e| e.to_string())?;
93+
let y = split.next().ok_or("Missing y")?.parse::<i32>().map_err(|e| e.to_string())?;
12094
Ok(Point::new(x, y))
12195
}
12296
}
12397

124-
impl Solvable for SixthDay {
125-
fn solve_first(&self, is_prod: bool) -> i64 {
126-
if is_prod {
127-
self.first(&self.exercise.content)
128-
} else {
129-
self.first(&self.exercise.example)
130-
}
131-
}
98+
impl Solution for Day06 {
99+
fn year(&self) -> u32 { 2015 }
100+
fn day(&self) -> u32 { 6 }
132101

133-
fn solve_second(&self, is_prod: bool) -> i64 {
134-
if is_prod {
135-
self.second(&self.exercise.content)
136-
} else {
137-
self.second(&self.exercise.example)
138-
}
139-
}
140-
141-
fn first(&self, content: &str) -> i64 {
142-
let instructions = content
102+
fn part1(&self, input: &str) -> Box<dyn Display> {
103+
let instructions = input
143104
.lines()
144105
.map(|line| Instruction::try_from(line).unwrap())
145106
.collect::<Vec<Instruction>>();
146107
let mut grid: Grid = [[false; 1000]; 1000];
147-
apply_instructions(instructions, &mut grid);
148-
count_lit(&grid)
108+
for instruction in instructions {
109+
apply_on_grid(instruction, &mut grid);
110+
}
111+
Box::new(grid.par_iter()
112+
.flat_map(|row| row.par_iter())
113+
.filter(|&&cell| cell)
114+
.count() as i64)
149115
}
150116

151-
fn second(&self, content: &str) -> i64 {
152-
let instructions = content
117+
fn part2(&self, input: &str) -> Box<dyn Display> {
118+
let instructions = input
153119
.lines()
154120
.map(|line| Instruction::try_from(line).unwrap())
155121
.collect::<Vec<Instruction>>();
156122
let mut grid: GridAmbient = [[0; 1000]; 1000];
157-
apply_increasing_instructions(instructions, &mut grid);
158-
count_brigthness(&grid)
123+
for instruction in instructions {
124+
apply_on_ambient_grid(instruction, &mut grid);
125+
}
126+
Box::new(grid.par_iter()
127+
.flat_map(|row| row.par_iter())
128+
.map(|&cell| cell as i64)
129+
.sum::<i64>())
159130
}
160131
}
161132

162133
#[cfg(test)]
163134
mod tests {
164135
use super::*;
165-
const EXAMPLE: &str = include_str!("inputs/6_test.txt");
166-
const PROD: &str = include_str!("inputs/6_prod.txt");
167136

168137
#[test]
169-
fn instruction() {
170-
let instruction = Instruction::try_from("turn on 0,0 through 999,999").unwrap();
171-
assert_eq!(instruction.action, Action::On);
172-
assert_eq!(instruction.start, Point::new(0, 0));
173-
assert_eq!(instruction.end, Point::new(999, 999));
174-
}
175-
#[test]
176-
fn first_test() {
177-
let mut first_exercise = SixthDay {
178-
exercise: Exercise {
179-
content: String::from(PROD),
180-
example: String::from(EXAMPLE),
181-
},
182-
};
183-
184-
let expected_example = 998996;
185-
let expected_prod = 569999;
186-
187-
let result_example = first_exercise.solve_first(false);
188-
let result_prod = first_exercise.solve_first(true);
189-
assert_eq!(expected_example, result_example);
190-
assert_eq!(expected_prod, result_prod);
191-
192-
first_exercise.exercise.example =
193-
String::from("turn on 0,0 through 0,0\ntoggle 0,0 through 999,999\n");
194-
195-
let expected_example = 2000001;
196-
let expected_prod = 17836115;
197-
let result_example = first_exercise.solve_second(false);
198-
let result_prod = first_exercise.solve_second(true);
199-
assert_eq!(expected_example, result_example);
200-
assert_eq!(expected_prod, result_prod);
138+
fn test_day06() {
139+
let day = Day06;
140+
assert_eq!(day.part1("turn on 0,0 through 999,999").to_string(), "1000000");
141+
assert_eq!(day.part1("toggle 0,0 through 999,0").to_string(), "1000");
142+
assert_eq!(day.part1("turn off 499,499 through 500,500").to_string(), "0");
143+
144+
assert_eq!(day.part2("turn on 0,0 through 0,0").to_string(), "1");
145+
assert_eq!(day.part2("toggle 0,0 through 999,999").to_string(), "2000000");
201146
}
202147
}

2015/src/day07.rs

Lines changed: 25 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
use std::collections::HashMap;
2+
use aoc_rust_common::Solution;
3+
use std::fmt::Display;
24

3-
use crate::{Exercise, Solvable};
4-
5-
struct SeventhDay {
6-
exercise: Exercise,
7-
}
5+
pub struct Day07;
86

97
#[derive(Debug, PartialEq, Eq, Clone)]
108
enum Operation {
@@ -75,22 +73,13 @@ impl TryFrom<&str> for Instruction {
7573
}
7674
}
7775

78-
fn parse_instructions(content: &str) -> Vec<Instruction> {
79-
content
80-
.lines()
81-
.map(|line| Instruction::try_from(line).unwrap())
82-
.collect::<Vec<Instruction>>()
83-
}
84-
85-
/// Helper to resolve a value that might be either a number or a reference
8676
fn resolve_operand(operand: &str, values: &HashMap<String, u16>) -> Option<u16> {
8777
operand
8878
.parse::<u16>()
8979
.ok()
9080
.or_else(|| values.get(operand).copied())
9181
}
9282

93-
/// Helper to apply a binary operation if both operands are available
9483
fn apply_binary_op<F>(
9584
left: &str,
9685
right: &str,
@@ -104,15 +93,13 @@ where
10493
.and_then(|l| resolve_operand(right, values).map(|r| op(l, r)))
10594
}
10695

107-
/// Calculate wire values using an iterative approach
108-
fn calculate_values(instructions: Vec<Instruction>) -> HashMap<String, u16> {
96+
fn calculate_values(instructions: &[Instruction]) -> HashMap<String, u16> {
10997
let mut values: HashMap<String, u16> = HashMap::new();
11098
let mut pending: HashMap<String, Operation> = instructions
111-
.into_iter()
112-
.map(|inst| (inst.target, inst.operation))
99+
.iter()
100+
.map(|inst| (inst.target.clone(), inst.operation.clone()))
113101
.collect();
114102

115-
// Keep processing until we can't resolve any more operations
116103
while !pending.is_empty() {
117104
let mut resolved = Vec::new();
118105

@@ -137,7 +124,8 @@ fn calculate_values(instructions: Vec<Instruction>) -> HashMap<String, u16> {
137124
}
138125
}
139126

140-
// Remove resolved operations
127+
if resolved.is_empty() { break; }
128+
141129
for target in resolved {
142130
pending.remove(&target);
143131
}
@@ -146,36 +134,26 @@ fn calculate_values(instructions: Vec<Instruction>) -> HashMap<String, u16> {
146134
values
147135
}
148136

149-
impl Solvable for SeventhDay {
150-
fn solve_first(&self, is_prod: bool) -> i64 {
151-
if is_prod {
152-
self.first(&self.exercise.content)
153-
} else {
154-
self.first(&self.exercise.example)
155-
}
156-
}
157-
158-
fn solve_second(&self, is_prod: bool) -> i64 {
159-
if is_prod {
160-
self.second(&self.exercise.content)
161-
} else {
162-
self.second(&self.exercise.example)
163-
}
164-
}
137+
impl Solution for Day07 {
138+
fn year(&self) -> u32 { 2015 }
139+
fn day(&self) -> u32 { 7 }
165140

166-
fn first(&self, content: &str) -> i64 {
167-
let instructions = parse_instructions(content);
168-
let values = calculate_values(instructions);
169-
*values.get("a").unwrap_or(&0) as i64
141+
fn part1(&self, input: &str) -> Box<dyn Display> {
142+
let instructions: Vec<Instruction> = input.lines()
143+
.map(|l| Instruction::try_from(l).unwrap())
144+
.collect();
145+
let values = calculate_values(&instructions);
146+
Box::new(*values.get("a").unwrap_or(&0) as i64)
170147
}
171148

172-
fn second(&self, content: &str) -> i64 {
173-
let instructions = parse_instructions(content);
174-
let values = calculate_values(instructions.clone());
149+
fn part2(&self, input: &str) -> Box<dyn Display> {
150+
let instructions: Vec<Instruction> = input.lines()
151+
.map(|l| Instruction::try_from(l).unwrap())
152+
.collect();
153+
let values = calculate_values(&instructions);
175154
let a_value = *values.get("a").unwrap_or(&0);
176155

177-
// Update instructions to override wire 'b' with the value from 'a'
178-
let instructions = instructions
156+
let new_instructions: Vec<Instruction> = instructions
179157
.into_iter()
180158
.map(|inst| {
181159
if inst.target == "b" {
@@ -186,57 +164,7 @@ impl Solvable for SeventhDay {
186164
})
187165
.collect();
188166

189-
let values = calculate_values(instructions);
190-
*values.get("a").unwrap_or(&0) as i64
191-
}
192-
}
193-
194-
#[cfg(test)]
195-
mod tests {
196-
use super::*;
197-
const EXAMPLE: &str = include_str!("inputs/7_test.txt");
198-
const PROD: &str = include_str!("inputs/7_prod.txt");
199-
200-
#[test]
201-
fn test_parse() {
202-
let instructions = parse_instructions(EXAMPLE);
203-
assert_eq!(instructions.len(), 8);
204-
assert_eq!(
205-
instructions[0],
206-
Instruction::new(String::from("x"), Operation::Assignment(123),)
207-
);
208-
assert_eq!(
209-
instructions[1],
210-
Instruction::new(String::from("y"), Operation::Assignment(456))
211-
);
212-
assert_eq!(
213-
instructions[4],
214-
Instruction::new(String::from("f"), Operation::LShift("x".to_owned(), 2))
215-
);
216-
}
217-
218-
#[test]
219-
fn first_test() {
220-
let first_exercise = SeventhDay {
221-
exercise: Exercise {
222-
content: String::from(PROD),
223-
example: String::from(EXAMPLE),
224-
},
225-
};
226-
227-
let expected_example = 0;
228-
let expected_prod = 46065;
229-
230-
let result_example = first_exercise.solve_first(false);
231-
let result_prod = first_exercise.solve_first(true);
232-
assert_eq!(expected_example, result_example);
233-
assert_eq!(expected_prod, result_prod);
234-
235-
let expected_example = 0;
236-
let expected_prod = 14134;
237-
let result_example = first_exercise.solve_second(false);
238-
let result_prod = first_exercise.solve_second(true);
239-
assert_eq!(expected_example, result_example);
240-
assert_eq!(expected_prod, result_prod);
167+
let values = calculate_values(&new_instructions);
168+
Box::new(*values.get("a").unwrap_or(&0) as i64)
241169
}
242170
}

0 commit comments

Comments
 (0)