Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 44 additions & 34 deletions Advents/AoC2025/day10.lean
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Advents.Utils
open Std

/-!
The inputs are switches to flips, patterns for flipping and joltages.
-/

namespace AoC2025_Day10

open System in
Expand All @@ -9,6 +13,10 @@ def input : FilePath := ("Advents"/"AoC2025"/"day10" : FilePath).withExtension "

/-!
# Question 1

In part 1, we should determine the minimum number of flips in patterns that take us from all switches being off to creating the input pattern.

We need to return the total minimum number of required switches.
-/

/-- `test` is the test string for the problem. -/
Expand All @@ -19,38 +27,46 @@ def test := "[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
/-- `atest` is the test string for the problem, split into rows. -/
def atest := (test.splitOn "\n").toArray

structure machine where
/--
The state to keep track of the data of the problem.

* `ls` is the array of light switches -- they can be on or off;
* `bs` is the array of configurations that can be toggled simultaneously;
* `js` is the array of joltages;
* `con` is the number of elapsed steps.
-/
structure state where
/-- `ls` is the array of light switches -- they can be on or off -/
ls : Array Bool
/-- `bs` is the array of configurations that can be toggled simultaneously -/
bs : Array (Array Nat)
/-- `js` is the array of joltages -/
js : Array Nat
ons : Array Bool
/-- `con` is the number of elapsed steps -/
con : Nat
deriving Inhabited, BEq, Hashable

instance : ToString machine where
/-- A convenience instance to print a `state`. -/
instance : ToString state where
toString := fun
| {ls := l, bs := b, js := _j, ons := os} => s!"current: {l}\n{b}\ntarget: {os}"
| {ls := l, bs := b, js := _j, con := c} => s!"current: {l}\n{b}\n{c}"

def inputToM (dat : Array String) : Array machine :=
/-- Convert the input into an array of `state`s. -/
def inputToM (dat : Array String) : Array state :=
dat.foldl (init := #[]) fun tot s => tot.push <|
let i1 := s.takeWhile (· != '(') |>.drop 1 |>.dropRight 2
let r2 := s.dropWhile (· != '(')
let i2 := r2.takeWhile (· != '{')
let i3 := r2.dropWhile (· != '{')
let ons := i1.foldl (init := #[]) fun tot s => tot.push (s == '#')
{ ls := ons.map fun _ => false
bs := (i2.splitOn " ").foldl (init := #[]) (·.push <| ·.getNats.toArray) |>.pop
let ons := i1.foldl (·.push <| · == '#') #[]
{ ls := ons
bs := (i2.splitOn " ").foldl (·.push <| ·.getNats.toArray) #[] |>.pop
js := i3.getNats.toArray
ons := ons }

structure state extends machine where
con : Nat
deriving Inhabited, BEq, Hashable

instance : ToString state where
toString := fun | s@{con := n, ..} => s!"{s.tomachine}\n{n}"
con := 0 }

/-- Toggle the switches in `l` occupying the positions in `b`. -/
def toggleOne (l : Array Bool) (b : Array Nat) : Array Bool :=
b.foldl (init := l) fun tot n => tot.modify (n) (!·)
b.foldl (·.modify · (!·)) l

#guard
let l := #[false, true, true, false]
Expand All @@ -62,37 +78,29 @@ def toggleOne (l : Array Bool) (b : Array Nat) : Array Bool :=
let b := #[1, 3]
toggleOne l b == #[false, false, true, true]

def toggle (m : machine) (b : Array Nat) : machine :=
{m with ls := toggleOne m.ls b}

def MtoS (m : machine) (c : Nat) : state where
ls := m.ls
bs := m.bs
js := m.js
ons := m.ons
con := c
/-- Toggle the light switches of the input `state`, incrementing `con` by `1` as well. -/
def toggle (m : state) (b : Array Nat) : state :=
{m with ls := toggleOne m.ls b, con := m.con + 1}

/-- Toggle the input `state` in all possible ways, corresponding to all `bs`. -/
def stepSingle (s : state) : HashSet state :=
s.bs.foldl (init := ∅) fun tot n =>
tot.insert (MtoS (toggle s.tomachine n) (s.con + 1))
s.bs.foldl (·.insert <| toggle s ·) ∅

/-- Toggle all entries of `h` in all possible ways. -/
def step (h : HashSet state) : HashSet state :=
h.fold (init := ∅) (·.union <| stepSingle ·)
h.fold (·.union <| stepSingle ·)

/-- `part1 dat` takes as input the input of the problem and returns the solution to part 1. -/
def part1 (dat : Array String) : Nat := Id.run do
let ms := inputToM dat
let mut tot := 0
for m in ms do
let s := MtoS m 0
for s in ms do
let mut h : HashSet state := {s}
let mut con := 0
let mut found := false
while !found do
con := con + 1
h := step h
for a in h do
found := found || a.ls == a.ons
found := found || a.ls.all (!·)
if found then
tot := tot + a.con
break
Expand All @@ -104,6 +112,8 @@ set_option trace.profiler true in solve 1 396

/-!
# Question 2

In part 2, we should do something similar, but adding to joltages, instead of flipping switches.
-/

/-- `part2 dat` takes as input the input of the problem and returns the solution to part 2. -/
Expand Down