day 10 part 2 progress!
almost there, just 2 stubborn instances that we can't solve and i think i know why.
This commit is contained in:
parent
5fd80e56d8
commit
17ce57943c
237
day10/sol2.go
237
day10/sol2.go
@ -2,8 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/bits"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -39,6 +41,7 @@ func solve(filename string) {
|
||||
scanner := bufio.NewScanner(input)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
total := 0
|
||||
errors := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.Fields(line)
|
||||
@ -57,11 +60,19 @@ func solve(filename string) {
|
||||
fmt.Printf("%v %b %v\n", target, buts, parts)
|
||||
n := solveJolts(target, buts)
|
||||
fmt.Printf("%s = %v\n", line, n)
|
||||
total += n
|
||||
fmt.Println()
|
||||
if n >= 0 {
|
||||
total += n
|
||||
} else {
|
||||
errors += 1
|
||||
}
|
||||
//fmt.Println(n)
|
||||
}
|
||||
check(scanner.Err())
|
||||
fmt.Println(total)
|
||||
if errors > 0 {
|
||||
fmt.Printf("error! failed to solve %d instances\n", errors)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -111,15 +122,19 @@ func (j *Jolts) uint32() (u uint32) {
|
||||
return u
|
||||
}
|
||||
|
||||
func (j Jolts) Sub(m uint32, value int) Jolts {
|
||||
func (j Jolts) Add(m uint32, value int) Jolts {
|
||||
for i := range j {
|
||||
if m>>i&1 != 0 {
|
||||
j[i] -= int16(value)
|
||||
j[i] += int16(value)
|
||||
}
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func (j Jolts) Sub(m uint32, value int) Jolts {
|
||||
return j.Add(m, -value)
|
||||
}
|
||||
|
||||
func (j Jolts) Valid() bool {
|
||||
for i := range j {
|
||||
if j[i] < 0 {
|
||||
@ -129,6 +144,31 @@ func (j Jolts) Valid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (j Jolts) Less(k Jolts) bool {
|
||||
for i := range j {
|
||||
if j[i] != k[i] {
|
||||
return j[i] < k[i]
|
||||
}
|
||||
}
|
||||
return false // equal
|
||||
}
|
||||
|
||||
func (j Jolts) BitLength() int {
|
||||
var total uint32
|
||||
for _, x := range j {
|
||||
total |= uint32(x)
|
||||
}
|
||||
return bits.Len32(total)
|
||||
}
|
||||
|
||||
func (j Jolts) BitSlice(bit int) uint32 {
|
||||
var mask uint32
|
||||
for i, x := range j {
|
||||
mask |= (uint32(x) >> uint(bit)) & 1 << uint(i)
|
||||
}
|
||||
return mask
|
||||
}
|
||||
|
||||
// TODO: this isn't quite enough. we need to know not only how many button presses
|
||||
// a mask can be solved in, but also *the specific buttons* -- because even though
|
||||
// each button is pressed at most once, two buttons can be connected to the same
|
||||
@ -140,24 +180,68 @@ func (j Jolts) Valid() bool {
|
||||
// since it depends only on the button wiring. all that's left after that is a
|
||||
// graph search through the state space, using masks to prune each level.
|
||||
|
||||
// suppose we have four buttons whose bitmasks are 110, 101, 011, and 100.
|
||||
// suppose our target jolts are [2 1 1], corresponding to bitmasks 100x2 and 011x1.
|
||||
// the shortest solution for the low bits (011) is to press button 3 once. but then we need
|
||||
// to press button 4 twice to get the 2nd bits. that's 3 total button presses.
|
||||
// a more efficient solution is to press button 1 once and button 2 once (110+101 = 211),
|
||||
// for 2 total button presses.
|
||||
// this is a potential issue whenever we have a set of buttons which aren't linearly independent
|
||||
// (e.g. button 1 ^ 2 ^ 3 = button 4). we know this to be the case in some of the inputs.
|
||||
|
||||
func solveJolts(target Jolts, pool []uint32) int {
|
||||
var bits uint32
|
||||
for _, x := range target {
|
||||
bits |= uint32(x)
|
||||
var bitcost = new(state)
|
||||
bitcost.init(pool)
|
||||
for mask, vals := range bitcost.nodes {
|
||||
fmt.Printf("%b: %v\n", mask, vals)
|
||||
}
|
||||
var answer int
|
||||
for bit := uint(0); bits>>bit > 0; bit++ {
|
||||
var mask uint32
|
||||
for i := range target {
|
||||
mask |= uint32(target[i]) >> bit << i
|
||||
|
||||
bits := target.BitLength()
|
||||
|
||||
qu := newHeap(target)
|
||||
var zero Jolts
|
||||
addstates := func(t, n Node, bit int) Node {
|
||||
t.cost += n.cost << bit
|
||||
t.mask += 1
|
||||
for i := range t.jolts {
|
||||
t.jolts[i] -= n.jolts[i] << bit
|
||||
}
|
||||
return t
|
||||
}
|
||||
ntargets := len(target)
|
||||
for ntargets > 1 && target[ntargets-1] == 0 {
|
||||
ntargets--
|
||||
}
|
||||
seen := make(map[Jolts]bool)
|
||||
for qu.Len() > 0 {
|
||||
this := heap.Pop(qu).(Node)
|
||||
log.Printf("sj: %v, len(q) = %v", this, qu.Len()+1)
|
||||
if this.jolts == zero {
|
||||
return int(this.cost)
|
||||
}
|
||||
seen[this.jolts] = true
|
||||
|
||||
bit := int(this.mask)
|
||||
if bit >= int(bits) {
|
||||
continue
|
||||
}
|
||||
//mask := masks[this.mask]
|
||||
mask := this.jolts.BitSlice(bit)
|
||||
log.Printf("jolts = %v, bit = %d, mask = %0*b", this.jolts, bit, ntargets, mask)
|
||||
|
||||
if mask == 0 {
|
||||
seen[this.jolts] = false
|
||||
this.mask += 1
|
||||
qu.AddNode(this)
|
||||
continue
|
||||
}
|
||||
|
||||
n := best(mask, pool)
|
||||
answer += n << bit
|
||||
for _, n := range bitcost.best(mask) {
|
||||
t := addstates(this, n, int(bit))
|
||||
if t.jolts.Valid() && !seen[t.jolts] {
|
||||
qu.AddNode(t)
|
||||
}
|
||||
}
|
||||
|
||||
//for i, p := range pool {
|
||||
// if mask>>i&1 != 0 {
|
||||
@ -165,29 +249,120 @@ func solveJolts(target Jolts, pool []uint32) int {
|
||||
// }
|
||||
//}
|
||||
}
|
||||
return answer
|
||||
log.Printf("%v: no solution found\n", target)
|
||||
return -1
|
||||
}
|
||||
|
||||
func best(target uint32, pool []uint32) int {
|
||||
var cost = make(map[uint32]int)
|
||||
var states = []uint32{0}
|
||||
cost[0] = 0
|
||||
for _, p := range pool {
|
||||
// enumerate all the states that can be reached by toggling button p
|
||||
for _, s := range states {
|
||||
t := s ^ p
|
||||
c := cost[t] + 1
|
||||
type Node struct {
|
||||
mask uint32
|
||||
buttons uint32
|
||||
cost int32
|
||||
jolts Jolts
|
||||
}
|
||||
|
||||
if cost_t, ok := cost[t]; ok {
|
||||
if c < cost_t {
|
||||
cost[t] = c
|
||||
func (n Node) Add(mask uint32) Node {
|
||||
n.mask ^= mask
|
||||
n.cost += 1
|
||||
n.jolts = n.jolts.Add(mask, 1)
|
||||
return n
|
||||
}
|
||||
|
||||
//func (n *Node) cost() int { return bits.OnesCount(n.buttons) }
|
||||
|
||||
type Heap struct {
|
||||
heap []Node
|
||||
idx map[Jolts]int
|
||||
}
|
||||
|
||||
// these functions are for the heap.Interface interface
|
||||
// start
|
||||
|
||||
func (h *Heap) Len() int { return len(h.heap) }
|
||||
|
||||
func (h *Heap) Less(i, j int) bool {
|
||||
if h.heap[i].cost != h.heap[j].cost {
|
||||
return h.heap[i].cost < h.heap[j].cost
|
||||
}
|
||||
return h.heap[i].jolts.Less(h.heap[j].jolts)
|
||||
}
|
||||
|
||||
func (h *Heap) Swap(i, j int) {
|
||||
h.heap[i], h.heap[j] = h.heap[j], h.heap[i]
|
||||
h.idx[h.heap[i].jolts] = i
|
||||
h.idx[h.heap[j].jolts] = j
|
||||
}
|
||||
|
||||
func (h *Heap) Push(x any) {
|
||||
n := x.(Node)
|
||||
h.heap = append(h.heap, n)
|
||||
h.idx[n.jolts] = len(h.heap) - 1
|
||||
}
|
||||
|
||||
func (h *Heap) Pop() any {
|
||||
old := h.heap
|
||||
n := len(old)
|
||||
x := old[n-1]
|
||||
h.heap = old[0 : n-1]
|
||||
delete(h.idx, x.jolts)
|
||||
return x
|
||||
}
|
||||
|
||||
// end
|
||||
|
||||
func (h *Heap) AddNode(t Node) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
log.Println(h.heap)
|
||||
log.Println(h.idx)
|
||||
panic(e)
|
||||
}
|
||||
}()
|
||||
if i, ok := h.idx[t.jolts]; ok {
|
||||
old_cost := h.heap[i].cost
|
||||
if t.cost < old_cost {
|
||||
h.heap[i].cost = t.cost
|
||||
heap.Fix(h, i)
|
||||
} else {
|
||||
// nothing; don't add node with higher cost to the queue
|
||||
}
|
||||
} else {
|
||||
heap.Push(h, t)
|
||||
}
|
||||
}
|
||||
|
||||
func newHeap(start Jolts) *Heap {
|
||||
var idx = make(map[Jolts]int)
|
||||
idx[start] = 0
|
||||
return &Heap{[]Node{{jolts: start}}, idx}
|
||||
}
|
||||
|
||||
type state struct {
|
||||
nodes map[uint32][]Node
|
||||
}
|
||||
|
||||
func (s *state) init(pool []uint32) {
|
||||
qu := newHeap(Jolts{})
|
||||
best := make(map[uint32][]Node)
|
||||
seen := make(map[uint32]bool)
|
||||
for qu.Len() > 0 {
|
||||
s := heap.Pop(qu).(Node)
|
||||
best[s.mask] = append(best[s.mask], s)
|
||||
// enumerate all the states that can be reached by toggling button p
|
||||
for b, p := range pool {
|
||||
if s.buttons>>b&1 == 0 {
|
||||
t := s.Add(p)
|
||||
t.buttons |= uint32(1) << b
|
||||
if !seen[t.buttons] {
|
||||
heap.Push(qu, t)
|
||||
seen[t.buttons] = true
|
||||
}
|
||||
} else {
|
||||
cost[t] = c
|
||||
states = append(states, t)
|
||||
//qu.AddNode(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cost[target]
|
||||
s.nodes = best
|
||||
}
|
||||
|
||||
func (s *state) best(target uint32) []Node {
|
||||
return s.nodes[target]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user