remove Go code
							parent
							
								
									ad900e8767
								
							
						
					
					
						commit
						06d4ed30c3
					
				@ -1,25 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"flag"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"git.buddy.wtf/challenges/buckets-of-fun/lib/application"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	if err := run(); err != nil {
 | 
					 | 
				
			||||||
		fmt.Fprintln(os.Stderr, err)
 | 
					 | 
				
			||||||
		os.Exit(1)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func run() error {
 | 
					 | 
				
			||||||
	flag.Parse()
 | 
					 | 
				
			||||||
	app, err := application.New(flag.Args()...)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return app.Run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,3 +0,0 @@
 | 
				
			|||||||
module git.buddy.wtf/challenges/buckets-of-fun
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
go 1.13
 | 
					 | 
				
			||||||
@ -1,52 +0,0 @@
 | 
				
			|||||||
package application
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"git.buddy.wtf/challenges/buckets-of-fun/lib/bucket"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// App holds context for the application
 | 
					 | 
				
			||||||
type App struct {
 | 
					 | 
				
			||||||
	Target  uint64
 | 
					 | 
				
			||||||
	Buckets bucket.Buckets
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// New returns an instance of the app
 | 
					 | 
				
			||||||
func New(args ...string) (*App, error) {
 | 
					 | 
				
			||||||
	if len(args) < 2 {
 | 
					 | 
				
			||||||
		msg := fmt.Sprintf("usage error: requires at least 2 arguments, received %d", len(args))
 | 
					 | 
				
			||||||
		return nil, errors.New(msg)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	target, err := strconv.ParseUint(args[0], 10, 64)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, errors.New("target must be a positive integer: " + err.Error())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	app := App{
 | 
					 | 
				
			||||||
		Target:  target,
 | 
					 | 
				
			||||||
		Buckets: bucket.Buckets{},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, arg := range args[1:] {
 | 
					 | 
				
			||||||
		capacity, err := strconv.ParseUint(arg, 10, 64)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, errors.New("bucket capacity must be a positive integer: " + err.Error())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		app.Buckets = append(app.Buckets, bucket.Bucket{Capacity: capacity})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &app, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Run runs the application
 | 
					 | 
				
			||||||
func (a *App) Run() error {
 | 
					 | 
				
			||||||
	fmt.Printf("target: %d\n", a.Target)
 | 
					 | 
				
			||||||
	fmt.Printf("buckets: %s\n", a.Buckets.String())
 | 
					 | 
				
			||||||
	for _, solution := range a.Buckets.FindTarget((a.Target)) {
 | 
					 | 
				
			||||||
		fmt.Println(solution)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,85 +0,0 @@
 | 
				
			|||||||
package bucket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "fmt"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Bucket to store volume
 | 
					 | 
				
			||||||
type Bucket struct {
 | 
					 | 
				
			||||||
	// Capacity amount the bucket can store
 | 
					 | 
				
			||||||
	Capacity uint64
 | 
					 | 
				
			||||||
	// Volume is the current volume of the bucket
 | 
					 | 
				
			||||||
	Volume uint64
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Fill returns a copy Bucket filled
 | 
					 | 
				
			||||||
func Fill(b Bucket) Bucket {
 | 
					 | 
				
			||||||
	return Bucket{
 | 
					 | 
				
			||||||
		Volume:   b.Capacity,
 | 
					 | 
				
			||||||
		Capacity: b.Capacity,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Empty returns a copy Bucket set to empty
 | 
					 | 
				
			||||||
func Empty(b Bucket) Bucket {
 | 
					 | 
				
			||||||
	return Bucket{
 | 
					 | 
				
			||||||
		Volume:   0,
 | 
					 | 
				
			||||||
		Capacity: b.Capacity,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Pour fills the target bucket to the top
 | 
					 | 
				
			||||||
func Pour(src, target Bucket) (Bucket, Bucket) {
 | 
					 | 
				
			||||||
	s := Bucket{
 | 
					 | 
				
			||||||
		Capacity: src.Capacity,
 | 
					 | 
				
			||||||
		Volume:   src.Volume,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	t := Bucket{
 | 
					 | 
				
			||||||
		Capacity: target.Capacity,
 | 
					 | 
				
			||||||
		Volume:   target.Volume,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	availableVolume := t.Capacity - t.Volume
 | 
					 | 
				
			||||||
	if availableVolume > s.Volume {
 | 
					 | 
				
			||||||
		t.Volume += s.Volume
 | 
					 | 
				
			||||||
		s.Volume = 0
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		s.Volume -= availableVolume
 | 
					 | 
				
			||||||
		t.Volume += availableVolume
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s, t
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Fill sets the volume to the capacity to fill bucket
 | 
					 | 
				
			||||||
func (b *Bucket) Fill() {
 | 
					 | 
				
			||||||
	b.Volume = b.Capacity
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Empty sets the volume to 0
 | 
					 | 
				
			||||||
func (b *Bucket) Empty() {
 | 
					 | 
				
			||||||
	b.Volume = 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsEmpty is true no volume
 | 
					 | 
				
			||||||
func (b *Bucket) IsEmpty() bool {
 | 
					 | 
				
			||||||
	return b.Volume == 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsFull is true if bucket is at capacity
 | 
					 | 
				
			||||||
func (b *Bucket) IsFull() bool {
 | 
					 | 
				
			||||||
	return b.Volume == b.Capacity
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Pour fills the target bucket to the top
 | 
					 | 
				
			||||||
func (b *Bucket) Pour(target *Bucket) {
 | 
					 | 
				
			||||||
	availableVolume := target.Capacity - target.Volume
 | 
					 | 
				
			||||||
	if availableVolume > b.Volume {
 | 
					 | 
				
			||||||
		target.Volume += b.Volume
 | 
					 | 
				
			||||||
		b.Volume = 0
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		b.Volume -= availableVolume
 | 
					 | 
				
			||||||
		target.Volume += availableVolume
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// String gets string representation
 | 
					 | 
				
			||||||
func (b *Bucket) String() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("%dvol/%dcap", b.Volume, b.Capacity)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,28 +0,0 @@
 | 
				
			|||||||
package bucket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestPour(t *testing.T) {
 | 
					 | 
				
			||||||
	var testcases = []struct {
 | 
					 | 
				
			||||||
		source            *Bucket
 | 
					 | 
				
			||||||
		target            *Bucket
 | 
					 | 
				
			||||||
		expectedSrcVol    uint64
 | 
					 | 
				
			||||||
		expectedTargetVol uint64
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{&Bucket{Capacity: 5, Volume: 2}, &Bucket{Capacity: 3, Volume: 2}, 1, 3},
 | 
					 | 
				
			||||||
		{&Bucket{Capacity: 5, Volume: 1}, &Bucket{Capacity: 3, Volume: 1}, 0, 2},
 | 
					 | 
				
			||||||
		{&Bucket{Capacity: 5, Volume: 0}, &Bucket{Capacity: 3, Volume: 0}, 0, 0},
 | 
					 | 
				
			||||||
		{&Bucket{Capacity: 5, Volume: 5}, &Bucket{Capacity: 3, Volume: 3}, 5, 3},
 | 
					 | 
				
			||||||
		{&Bucket{Capacity: 5, Volume: 4}, &Bucket{Capacity: 3, Volume: 2}, 3, 3},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, tc := range testcases {
 | 
					 | 
				
			||||||
		tc.source.Pour(tc.target)
 | 
					 | 
				
			||||||
		if tc.source.Volume != tc.expectedSrcVol {
 | 
					 | 
				
			||||||
			t.Errorf("expected source volume %d, got = %d", tc.expectedSrcVol, tc.source.Volume)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if tc.target.Volume != tc.expectedTargetVol {
 | 
					 | 
				
			||||||
			t.Errorf("expected target volume %d, got = %d", tc.expectedTargetVol, tc.target.Volume)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,267 +0,0 @@
 | 
				
			|||||||
package bucket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"sort"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Buckets manages bucket objects
 | 
					 | 
				
			||||||
type Buckets []Bucket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// // action name
 | 
					 | 
				
			||||||
type actionType int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	actionTypeUnknown actionType = iota
 | 
					 | 
				
			||||||
	actionTypeEmpty
 | 
					 | 
				
			||||||
	actionTypeFill
 | 
					 | 
				
			||||||
	actionTypePour
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type action struct {
 | 
					 | 
				
			||||||
	kind   actionType
 | 
					 | 
				
			||||||
	src    int
 | 
					 | 
				
			||||||
	target int
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type actions []action
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (a actions) String() string {
 | 
					 | 
				
			||||||
	acts := []string{}
 | 
					 | 
				
			||||||
	for _, act := range a {
 | 
					 | 
				
			||||||
		acts = append(acts, act.String())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fmt.Sprintf("[%s]", strings.Join(acts, ","))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (a action) String() string {
 | 
					 | 
				
			||||||
	switch a.kind {
 | 
					 | 
				
			||||||
	case actionTypeEmpty:
 | 
					 | 
				
			||||||
		return fmt.Sprintf("empty %d   ", a.target)
 | 
					 | 
				
			||||||
	case actionTypeFill:
 | 
					 | 
				
			||||||
		return fmt.Sprintf("fill %d    ", a.target)
 | 
					 | 
				
			||||||
	case actionTypePour:
 | 
					 | 
				
			||||||
		return fmt.Sprintf("pour %d → %d", a.src, a.target)
 | 
					 | 
				
			||||||
	case actionTypeUnknown:
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fmt.Sprintf("unknown (src: %d, target: %d)", a.src, a.target)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type result struct {
 | 
					 | 
				
			||||||
	mapping map[string][]actions
 | 
					 | 
				
			||||||
	matched map[string]interface{}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) get(key string) ([]actions, bool) {
 | 
					 | 
				
			||||||
	acts, ok := r.mapping[key]
 | 
					 | 
				
			||||||
	return acts, ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) keys() []string {
 | 
					 | 
				
			||||||
	keys := []string{}
 | 
					 | 
				
			||||||
	for key := range r.mapping {
 | 
					 | 
				
			||||||
		keys = append(keys, key)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sort.Strings(keys)
 | 
					 | 
				
			||||||
	return keys
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) matchedKeys() []string {
 | 
					 | 
				
			||||||
	keys := []string{}
 | 
					 | 
				
			||||||
	for key := range r.matched {
 | 
					 | 
				
			||||||
		keys = append(keys, key)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sort.Strings(keys)
 | 
					 | 
				
			||||||
	return keys
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) bestMatches() ([]string, bool) {
 | 
					 | 
				
			||||||
	var best []string
 | 
					 | 
				
			||||||
	found := false
 | 
					 | 
				
			||||||
	numActions := 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	matched := r.matchedKeys()
 | 
					 | 
				
			||||||
	for _, key := range matched {
 | 
					 | 
				
			||||||
		acts, ok := r.get(key)
 | 
					 | 
				
			||||||
		if found == false && ok && len(acts) > 0 {
 | 
					 | 
				
			||||||
			found = true
 | 
					 | 
				
			||||||
			numActions = len(acts[0])
 | 
					 | 
				
			||||||
			best = []string{key}
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if numActions > len(acts[0]) {
 | 
					 | 
				
			||||||
			numActions = len(acts[0])
 | 
					 | 
				
			||||||
			best = []string{key}
 | 
					 | 
				
			||||||
		} else if numActions == len(acts[0]) {
 | 
					 | 
				
			||||||
			best = append(best, key)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !found {
 | 
					 | 
				
			||||||
		return nil, false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return best, true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) addMatch(key string) {
 | 
					 | 
				
			||||||
	r.matched[key] = struct{}{}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *result) addActions(key string, acts actions) bool {
 | 
					 | 
				
			||||||
	currentActions, ok := r.mapping[key]
 | 
					 | 
				
			||||||
	if !ok || len(currentActions) == 0 {
 | 
					 | 
				
			||||||
		currentActions = []actions{acts}
 | 
					 | 
				
			||||||
		r.mapping[key] = currentActions
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(acts) > len(currentActions[0]) {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(acts) == len(currentActions[0]) {
 | 
					 | 
				
			||||||
		r.mapping[key] = append(currentActions, acts)
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	r.mapping[key] = []actions{acts}
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) empty(index int) {
 | 
					 | 
				
			||||||
	buk := &b[index]
 | 
					 | 
				
			||||||
	buk.Empty()
 | 
					 | 
				
			||||||
	b[index] = *buk
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) fill(index int) {
 | 
					 | 
				
			||||||
	buk := &b[index]
 | 
					 | 
				
			||||||
	buk.Fill()
 | 
					 | 
				
			||||||
	b[index] = *buk
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) pour(i, j int) {
 | 
					 | 
				
			||||||
	src := &b[i]
 | 
					 | 
				
			||||||
	dest := &b[j]
 | 
					 | 
				
			||||||
	src.Pour(dest)
 | 
					 | 
				
			||||||
	b[i] = *src
 | 
					 | 
				
			||||||
	b[j] = *dest
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// HasTarget returns true
 | 
					 | 
				
			||||||
func (b Buckets) HasTarget(target uint64) bool {
 | 
					 | 
				
			||||||
	for _, bucket := range b {
 | 
					 | 
				
			||||||
		if bucket.Volume == target {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) String() string {
 | 
					 | 
				
			||||||
	bucketStrs := []string{}
 | 
					 | 
				
			||||||
	for _, bucket := range b {
 | 
					 | 
				
			||||||
		bucketStrs = append(bucketStrs, bucket.String())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fmt.Sprintf("[%s]", strings.Join(bucketStrs, ","))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// FindTarget returns actions to find target
 | 
					 | 
				
			||||||
func (b Buckets) FindTarget(target uint64) []string {
 | 
					 | 
				
			||||||
	r := &result{
 | 
					 | 
				
			||||||
		mapping: map[string][]actions{},
 | 
					 | 
				
			||||||
		matched: map[string]interface{}{},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	b.findTarget(target, r, actions{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	keys, found := r.bestMatches()
 | 
					 | 
				
			||||||
	if !found {
 | 
					 | 
				
			||||||
		return []string{"No solution"}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fmt.Printf("%d solutions\n", len(keys))
 | 
					 | 
				
			||||||
	for i, key := range keys {
 | 
					 | 
				
			||||||
		allacts, ok := r.get(key)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		newState := make(Buckets, len(b))
 | 
					 | 
				
			||||||
		copy(newState, b)
 | 
					 | 
				
			||||||
		fmt.Printf("solution %d\n", i+1)
 | 
					 | 
				
			||||||
		for _, acts := range allacts {
 | 
					 | 
				
			||||||
			if len(acts) == 0 {
 | 
					 | 
				
			||||||
				fmt.Println("no actions required")
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			for _, act := range acts {
 | 
					 | 
				
			||||||
				newState = newState.performAction(act)
 | 
					 | 
				
			||||||
				fmt.Printf("%s\t%s\n", act.String(), newState.String())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ret := []string{}
 | 
					 | 
				
			||||||
	return ret
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) performAction(act action) Buckets {
 | 
					 | 
				
			||||||
	newState := make(Buckets, len(b))
 | 
					 | 
				
			||||||
	copy(newState, b)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch act.kind {
 | 
					 | 
				
			||||||
	case actionTypeEmpty:
 | 
					 | 
				
			||||||
		newState.empty(act.target)
 | 
					 | 
				
			||||||
	case actionTypeFill:
 | 
					 | 
				
			||||||
		newState.fill(act.target)
 | 
					 | 
				
			||||||
	case actionTypePour:
 | 
					 | 
				
			||||||
		newState.pour(act.src, act.target)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return newState
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) findTarget(
 | 
					 | 
				
			||||||
	target uint64,
 | 
					 | 
				
			||||||
	states *result,
 | 
					 | 
				
			||||||
	prevActions actions,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
	key := b.String()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	added := states.addActions(key, prevActions)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if b.HasTarget(target) {
 | 
					 | 
				
			||||||
		states.addMatch(key)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !added {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	possibleActions := b.possibleActions()
 | 
					 | 
				
			||||||
	for _, act := range possibleActions {
 | 
					 | 
				
			||||||
		newActions := append(prevActions, act)
 | 
					 | 
				
			||||||
		newState := b.performAction(act)
 | 
					 | 
				
			||||||
		newState.findTarget(target, states, newActions)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (b Buckets) possibleActions() actions {
 | 
					 | 
				
			||||||
	ret := actions{}
 | 
					 | 
				
			||||||
	for i, bucket := range b {
 | 
					 | 
				
			||||||
		if !bucket.IsFull() {
 | 
					 | 
				
			||||||
			ret = append(ret, action{kind: actionTypeFill, target: i})
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !bucket.IsEmpty() {
 | 
					 | 
				
			||||||
			// ret = append(ret, action{kind: actionTypeEmpty, fn: b.empty(i), target: i})
 | 
					 | 
				
			||||||
			ret = append(ret, action{kind: actionTypeEmpty, target: i})
 | 
					 | 
				
			||||||
			for j, target := range b {
 | 
					 | 
				
			||||||
				if !target.IsFull() && i != j {
 | 
					 | 
				
			||||||
					// ret = append(ret, action{kind: actionTypePour, fn: b.pour(i, j), src: i, target: j})
 | 
					 | 
				
			||||||
					ret = append(ret, action{kind: actionTypePour, src: i, target: j})
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue