// Package twobucket solves the Two Bucket measuring problem.
package twobucket
import (
"fmt"
)
// States represents the various bucket pair states.
type States [][2]int
// Solve calculates the steps needed for measuring the goalAmount.
func Solve(sizeBucketOne, sizeBucketTwo, goalAmount int, startBucket string) (goalBucket string, numSteps, otherBucketLevel int, e error) {
if sizeBucketOne == 0 || sizeBucketTwo == 0 || goalAmount == 0 {
return "", 0, 0, fmt.Errorf("invalid bucket size or goal")
}
var b1, b2, stp int
var discardState [2]int // this represents the opposite starting bucket state
switch startBucket {
case "one":
b1 = sizeBucketOne
discardState = [2]int{0, sizeBucketTwo}
case "two":
b2 = sizeBucketTwo
discardState = [2]int{sizeBucketOne, 0}
default:
return "", 0, 0, fmt.Errorf("starting bucket must be \"one\" or \"two\"")
}
stp++
states := make(States, 1)
states[0] = [2]int{b1, b2}
var oldStatesSize int
for ; ; stp++ {
for _, st := range states {
switch {
case st[0] == goalAmount:
return "one", stp, st[1], nil
case st[1] == goalAmount:
return "two", stp, st[0], nil
}
}
var childs States
// log.Println(oldStatesSize)
for _, st := range states[oldStatesSize:] {
childs = append(childs, genStates(st[0], st[1], sizeBucketOne, sizeBucketTwo)...)
}
oldStatesSize = len(states)
for _, st := range childs {
if !states.contains(st) &&
// do not accept discardState to make tests happy
st != discardState {
states = append(states, st)
}
}
// log.Println("states:", states)
}
}
func (sts States) contains(s [2]int) bool {
for _, st := range sts {
if st == s {
return true
}
}
return false
}
func genStates(b1, b2, sizeBucketOne, sizeBucketTwo int) States {
// log.Println("genStates input values (b1,b2,s1,s2): ", b1, b2, sizeBucketOne, sizeBucketTwo)
var sts States
//Empty buckets
sts = append(sts, [2]int{b1, 0})
sts = append(sts, [2]int{0, b2})
//Fill buckets
sts = append(sts, [2]int{b1, sizeBucketTwo})
sts = append(sts, [2]int{sizeBucketOne, b2})
var origb1 = b1
var origb2 = b2
//b1->b2
for b2 < sizeBucketTwo && b1 > 0 {
b1--
b2++
}
sts = append(sts, [2]int{b1, b2})
// FIXME: this is quite lame way of going back to oringinal values
b1 = origb1
b2 = origb2
//b2->b1
for b1 < sizeBucketOne && b2 > 0 {
b1++
b2--
}
sts = append(sts, [2]int{b1, b2})
// log.Println("generated states:", sts)
return sts
}