2025 Day 10 Solved!
This commit is contained in:
250
2025/day10/main.go
Normal file
250
2025/day10/main.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/draffensperger/golp"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
part1(inp)
|
||||
fmt.Println()
|
||||
part2(inp)
|
||||
}
|
||||
|
||||
func part1(inp []string) {
|
||||
machines := parseInput(inp)
|
||||
var ret int
|
||||
for _, m := range machines {
|
||||
r := m.Start()
|
||||
ret += r
|
||||
}
|
||||
|
||||
fmt.Println("# Part 1")
|
||||
fmt.Println(ret)
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
machines := parseInput(inp)
|
||||
var ret int
|
||||
var wg sync.WaitGroup
|
||||
for _, m := range machines {
|
||||
wg.Go(func() {
|
||||
sol := m.SolveJoltage()
|
||||
ret += sol
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
fmt.Println("# Part 2")
|
||||
fmt.Println(ret)
|
||||
}
|
||||
|
||||
func parseInput(inp []string) []*Machine {
|
||||
var ret []*Machine
|
||||
for i := range inp {
|
||||
ret = append(ret, NewMachine(i, inp[i]))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type Machine struct {
|
||||
id int
|
||||
numLights int
|
||||
lights int
|
||||
wLights int
|
||||
buttons [][]int
|
||||
joltages []int
|
||||
jCounters []int
|
||||
}
|
||||
|
||||
func NewMachine(id int, inp string) *Machine {
|
||||
ret := Machine{id: id}
|
||||
pts := strings.Fields(inp)
|
||||
for _, p := range pts {
|
||||
in := p[1 : len(p)-1]
|
||||
switch p[0] {
|
||||
case '[':
|
||||
var l []int
|
||||
for i := range in {
|
||||
if in[i] == '#' {
|
||||
l = append(l, i)
|
||||
}
|
||||
}
|
||||
ret.wLights = intsToBitmask(l)
|
||||
ret.numLights = len(in)
|
||||
case '(':
|
||||
wP := strings.Split(in, ",")
|
||||
var w []int
|
||||
for i := range wP {
|
||||
w = append(w, h.Atoi(wP[i]))
|
||||
}
|
||||
ret.buttons = append(ret.buttons, w)
|
||||
case '{':
|
||||
wJ := strings.Split(in, ",")
|
||||
for i := range wJ {
|
||||
ret.joltages = append(ret.joltages, h.Atoi(wJ[i]))
|
||||
ret.jCounters = append(ret.jCounters, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &ret
|
||||
}
|
||||
|
||||
// Start presses buttons until the machine is running
|
||||
func (m *Machine) Start() int {
|
||||
bMasks := []int{}
|
||||
for _, b := range m.buttons {
|
||||
bMasks = append(bMasks, intsToBitmask(b))
|
||||
}
|
||||
// Start at the end
|
||||
endMask := 0
|
||||
current := map[int]bool{m.wLights: true}
|
||||
var ret int
|
||||
for p := 1; p <= 1000; p++ {
|
||||
nextSet := make(map[int]bool)
|
||||
for c := range current {
|
||||
for _, b := range bMasks {
|
||||
nextSet[c^b] = true
|
||||
}
|
||||
}
|
||||
current = nextSet
|
||||
if _, exists := current[endMask]; exists {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *Machine) SolveJoltage() int {
|
||||
if slices.Equal(m.jCounters, m.joltages) {
|
||||
return 0
|
||||
}
|
||||
|
||||
nB := len(m.buttons)
|
||||
nJ := len(m.joltages)
|
||||
|
||||
lp := golp.NewLP(0, nB)
|
||||
lp.SetVerboseLevel(golp.NEUTRAL)
|
||||
|
||||
objCoeffs := make([]float64, nB)
|
||||
for i := range nB {
|
||||
objCoeffs[i] = 1.0
|
||||
}
|
||||
lp.SetObjFn(objCoeffs)
|
||||
|
||||
for i := range nB {
|
||||
lp.SetInt(i, true)
|
||||
lp.SetBounds(i, 0.0, float64(1000))
|
||||
}
|
||||
for i := 0; i < nJ; i++ {
|
||||
var entries []golp.Entry
|
||||
for j, btn := range m.buttons {
|
||||
if slices.Contains(btn, i) {
|
||||
entries = append(entries, golp.Entry{Col: j, Val: 1.0})
|
||||
}
|
||||
}
|
||||
targetValue := float64(m.joltages[i])
|
||||
if err := lp.AddConstraintSparse(entries, golp.EQ, targetValue); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
status := lp.Solve()
|
||||
if status != golp.OPTIMAL {
|
||||
return 0
|
||||
}
|
||||
|
||||
solution := lp.Variables()
|
||||
totalPresses := 0
|
||||
for _, val := range solution {
|
||||
totalPresses += int(val + 0.5)
|
||||
}
|
||||
return totalPresses
|
||||
}
|
||||
|
||||
func (m *Machine) Reset() { m.lights = 0 }
|
||||
|
||||
func (m Machine) String() string {
|
||||
l := bitmaskToBytes(m.lights, m.numLights)
|
||||
wl := bitmaskToBytes(m.wLights, m.numLights)
|
||||
return fmt.Sprintf("[%s] -> [%s] %d", string(l), string(wl), m.wLights)
|
||||
}
|
||||
|
||||
func intsToBitmask(i []int) int {
|
||||
mask := 0
|
||||
for _, v := range i {
|
||||
mask |= 1 << v
|
||||
}
|
||||
return mask
|
||||
}
|
||||
func bitmaskToInts(in int, length int) []int {
|
||||
var ret []int
|
||||
for i := 0; i < length; i++ {
|
||||
if in&1 == 1 {
|
||||
ret = append(ret, i)
|
||||
}
|
||||
in = in >> 1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func bitmaskToBytes(in int, length int) []byte {
|
||||
var ret []byte
|
||||
for i := 1; i <= length; i++ {
|
||||
if in&1 == 1 {
|
||||
ret = append(ret, '#')
|
||||
} else {
|
||||
ret = append(ret, '.')
|
||||
}
|
||||
in = in >> 1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func elim(mtx [][]int) ([]int, [][]int) {
|
||||
m := len(mtx)
|
||||
if m == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
n := len(mtx[0]) - 1
|
||||
pivCols := []int{}
|
||||
cRow := 0
|
||||
mat := make([][]int, m)
|
||||
for i := range mtx {
|
||||
mat[i] = make([]int, n+1)
|
||||
copy(mat[i], mtx[i])
|
||||
}
|
||||
for col := 0; col < n && cRow < m; col++ {
|
||||
pivRow := -1
|
||||
for row := cRow; row < m; row++ {
|
||||
if mat[row][col] != 0 {
|
||||
pivRow = row
|
||||
break
|
||||
}
|
||||
}
|
||||
if pivRow == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
mat[cRow], mat[pivRow] = mat[pivRow], mat[cRow]
|
||||
pivCols = append(pivCols, col)
|
||||
|
||||
for row := cRow + 1; row < m; row++ {
|
||||
if mat[row][col] != 0 {
|
||||
factor := mat[row][col]
|
||||
pivVal := mat[cRow][col]
|
||||
for j := col; j <= n; j++ {
|
||||
mat[row][j] = mat[row][j]*pivVal - mat[cRow][j]*factor
|
||||
}
|
||||
}
|
||||
}
|
||||
cRow++
|
||||
}
|
||||
return pivCols, mat
|
||||
}
|
||||
Reference in New Issue
Block a user