remove Go code

master
Buddy Sandidge 5 years ago
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…
Cancel
Save