Skip to content

Commit 197bee4

Browse files
committed
2025 10.1
1 parent 9bf7f64 commit 197bee4

File tree

3 files changed

+202
-1
lines changed

3 files changed

+202
-1
lines changed

data

Submodule data updated from 4c247cf to 3f6e689

src/aoc/y2025/day10.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Copyright (c) 2025 Lexi Robinson
2+
//
3+
// Licensed under the EUPL, Version 1.2
4+
//
5+
// You may not use this work except in compliance with the Licence.
6+
// You should have received a copy of the Licence along with this work. If not, see:
7+
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
8+
// See the Licence for the specific language governing permissions and limitations under the Licence.
9+
//
10+
11+
use std::cmp::Ordering;
12+
use std::fmt::Display;
13+
use std::str::FromStr;
14+
15+
use itertools::Itertools;
16+
use lazy_static::lazy_static;
17+
use regex::Regex;
18+
19+
use crate::AoCError;
20+
21+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22+
struct IndicatorState([bool; 10]);
23+
24+
impl FromStr for IndicatorState {
25+
type Err = AoCError;
26+
27+
fn from_str(s: &str) -> Result<Self, Self::Err> {
28+
let mut tmp: Vec<bool> = s
29+
.chars()
30+
.map(|c| match c {
31+
'.' => Ok(false),
32+
'#' => Ok(true),
33+
_ => Err(AoCError::new_from_char(c)),
34+
})
35+
.try_collect()?;
36+
match tmp.len().cmp(&10) {
37+
Ordering::Less => {
38+
tmp.extend((0..(10 - tmp.len())).map(|_| false));
39+
}
40+
Ordering::Equal => (),
41+
Ordering::Greater => {
42+
return Err(AoCError::new(format!("Input string {s} is too long!")));
43+
}
44+
}
45+
Ok(Self(tmp.into_iter().collect_array().unwrap()))
46+
}
47+
}
48+
49+
impl Display for IndicatorState {
50+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51+
write!(
52+
f,
53+
"[{}]",
54+
self.0
55+
.iter()
56+
.map(|state| if *state { '#' } else { '.' })
57+
.join("")
58+
)
59+
}
60+
}
61+
62+
impl IndicatorState {
63+
fn be_pushed(mut self, button: &Button) -> Self {
64+
for btn in button.0.iter().copied() {
65+
self.0[btn] = !self.0[btn];
66+
}
67+
self
68+
}
69+
}
70+
71+
#[derive(Debug)]
72+
struct Button(Vec<usize>);
73+
74+
impl FromStr for Button {
75+
type Err = AoCError;
76+
77+
fn from_str(s: &str) -> Result<Self, Self::Err> {
78+
Ok(Self(
79+
s.trim_start_matches('(')
80+
.trim_end_matches(')')
81+
.split(",")
82+
.map(|s| s.parse())
83+
.try_collect()?,
84+
))
85+
}
86+
}
87+
88+
impl Display for Button {
89+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90+
write!(f, "({})", self.0.iter().join(","))
91+
}
92+
}
93+
94+
#[derive(Debug)]
95+
struct Machine {
96+
target: IndicatorState,
97+
buttons: Vec<Button>,
98+
}
99+
100+
impl FromStr for Machine {
101+
type Err = AoCError;
102+
103+
fn from_str(s: &str) -> Result<Self, Self::Err> {
104+
lazy_static! {
105+
// I swear he intentionally makes these annoying to parse with regex
106+
static ref RE: Regex = Regex::new(r"^\[([#.]+)\] ((?:\([\d,]+\) ?)+) \{[\d,]+\}$").unwrap();
107+
}
108+
109+
let matches = RE
110+
.captures(s)
111+
.ok_or_else(Self::Err::new_from_regex(s, &RE))?;
112+
113+
Ok(Self {
114+
target: matches[1].parse()?,
115+
buttons: matches[2]
116+
.split_whitespace()
117+
.map(|s| s.parse())
118+
.try_collect()?,
119+
})
120+
}
121+
}
122+
123+
impl Display for Machine {
124+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125+
write!(
126+
f,
127+
"{} {} {{???}}",
128+
self.target,
129+
self.buttons.iter().join(" ")
130+
)
131+
}
132+
}
133+
134+
struct PushResult {
135+
last_button: usize,
136+
state: IndicatorState,
137+
}
138+
139+
impl Machine {
140+
fn part_1(&self) -> usize {
141+
let current_state: IndicatorState = Default::default();
142+
143+
let mut pushes: Vec<PushResult> = self
144+
.buttons
145+
.iter()
146+
.enumerate()
147+
.map(|(i, btn)| PushResult {
148+
last_button: i,
149+
state: current_state.be_pushed(btn),
150+
})
151+
.collect();
152+
153+
for i in 1.. {
154+
if pushes
155+
.iter()
156+
.any(|PushResult { state, .. }| state == &self.target)
157+
{
158+
return i;
159+
}
160+
161+
// Let's get fucking stupid with it
162+
pushes = pushes
163+
.into_iter()
164+
.flat_map(|PushResult { last_button, state }| {
165+
self.buttons
166+
.iter()
167+
.enumerate()
168+
.filter(move |(i, _)| *i != last_button)
169+
.map(move |(last_button, button)| PushResult {
170+
last_button,
171+
state: state.be_pushed(button),
172+
})
173+
})
174+
.collect();
175+
}
176+
unreachable!();
177+
}
178+
}
179+
180+
pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
181+
let machines: Vec<Machine> = data.parse().try_collect()?;
182+
let ret: usize = machines
183+
.into_iter()
184+
.map(|machine| {
185+
log::debug!("{machine}");
186+
machine.part_1()
187+
})
188+
.sum();
189+
Ok(ret.to_string())
190+
}
191+
192+
inventory::submit!(crate::AoCDay {
193+
year: "2025",
194+
day: "10",
195+
part_1: crate::AoCPart {
196+
main: part_1,
197+
example: part_1
198+
},
199+
part_2: None
200+
});

src/aoc/y2025/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ pub mod day06;
1515
pub mod day07;
1616
pub mod day08;
1717
pub mod day09;
18+
pub mod day10;
1819
pub mod day11;

0 commit comments

Comments
 (0)