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
235
day10/sol2.go
235
day10/sol2.go
@ -2,8 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"container/heap"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math/bits"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -39,6 +41,7 @@ func solve(filename string) {
|
|||||||
scanner := bufio.NewScanner(input)
|
scanner := bufio.NewScanner(input)
|
||||||
scanner.Split(bufio.ScanLines)
|
scanner.Split(bufio.ScanLines)
|
||||||
total := 0
|
total := 0
|
||||||
|
errors := 0
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
@ -57,11 +60,19 @@ func solve(filename string) {
|
|||||||
fmt.Printf("%v %b %v\n", target, buts, parts)
|
fmt.Printf("%v %b %v\n", target, buts, parts)
|
||||||
n := solveJolts(target, buts)
|
n := solveJolts(target, buts)
|
||||||
fmt.Printf("%s = %v\n", line, n)
|
fmt.Printf("%s = %v\n", line, n)
|
||||||
|
fmt.Println()
|
||||||
|
if n >= 0 {
|
||||||
total += n
|
total += n
|
||||||
|
} else {
|
||||||
|
errors += 1
|
||||||
|
}
|
||||||
//fmt.Println(n)
|
//fmt.Println(n)
|
||||||
}
|
}
|
||||||
check(scanner.Err())
|
check(scanner.Err())
|
||||||
fmt.Println(total)
|
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
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j Jolts) Sub(m uint32, value int) Jolts {
|
func (j Jolts) Add(m uint32, value int) Jolts {
|
||||||
for i := range j {
|
for i := range j {
|
||||||
if m>>i&1 != 0 {
|
if m>>i&1 != 0 {
|
||||||
j[i] -= int16(value)
|
j[i] += int16(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return j
|
return j
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j Jolts) Sub(m uint32, value int) Jolts {
|
||||||
|
return j.Add(m, -value)
|
||||||
|
}
|
||||||
|
|
||||||
func (j Jolts) Valid() bool {
|
func (j Jolts) Valid() bool {
|
||||||
for i := range j {
|
for i := range j {
|
||||||
if j[i] < 0 {
|
if j[i] < 0 {
|
||||||
@ -129,6 +144,31 @@ func (j Jolts) Valid() bool {
|
|||||||
return true
|
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
|
// 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
|
// 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
|
// 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
|
// 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.
|
// 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 {
|
func solveJolts(target Jolts, pool []uint32) int {
|
||||||
var bits uint32
|
var bitcost = new(state)
|
||||||
for _, x := range target {
|
bitcost.init(pool)
|
||||||
bits |= uint32(x)
|
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 {
|
if mask == 0 {
|
||||||
|
seen[this.jolts] = false
|
||||||
|
this.mask += 1
|
||||||
|
qu.AddNode(this)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
n := best(mask, pool)
|
for _, n := range bitcost.best(mask) {
|
||||||
answer += n << bit
|
t := addstates(this, n, int(bit))
|
||||||
|
if t.jolts.Valid() && !seen[t.jolts] {
|
||||||
|
qu.AddNode(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//for i, p := range pool {
|
//for i, p := range pool {
|
||||||
// if mask>>i&1 != 0 {
|
// 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 {
|
type Node struct {
|
||||||
var cost = make(map[uint32]int)
|
mask uint32
|
||||||
var states = []uint32{0}
|
buttons uint32
|
||||||
cost[0] = 0
|
cost int32
|
||||||
for _, p := range pool {
|
jolts Jolts
|
||||||
// enumerate all the states that can be reached by toggling button p
|
}
|
||||||
for _, s := range states {
|
|
||||||
t := s ^ p
|
|
||||||
c := cost[t] + 1
|
|
||||||
|
|
||||||
if cost_t, ok := cost[t]; ok {
|
func (n Node) Add(mask uint32) Node {
|
||||||
if c < cost_t {
|
n.mask ^= mask
|
||||||
cost[t] = c
|
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 {
|
} else {
|
||||||
cost[t] = c
|
heap.Push(h, t)
|
||||||
states = append(states, t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cost[target]
|
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
|
||||||
|
}
|
||||||
|
//qu.AddNode(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.nodes = best
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) best(target uint32) []Node {
|
||||||
|
return s.nodes[target]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user