diff --git a/config.json b/config.json index af9cfbfb..23eda90e 100644 --- a/config.json +++ b/config.json @@ -61,7 +61,8 @@ "saddle-points", "ocr-numbers", "meetup", - "bracket-push" + "bracket-push", + "two-bucket" ], "deprecated": [ "point-mutations" diff --git a/two-bucket/example-2.js b/two-bucket/example-2.js new file mode 100644 index 00000000..c596f540 --- /dev/null +++ b/two-bucket/example-2.js @@ -0,0 +1,98 @@ +//alternate solution written by Fullstack student, Griffin Telljohann +'use strict'; + +function TwoBucket(bucket1, bucket2, goal, startingBucket) { + this.b1max = bucket1; + this.b2max = bucket2; + this.goalAmount = goal; + this.states = {}; + var invalid = (startingBucket == "one" ? 0 : this.b1max) + "," + (startingBucket == "two" ? 0 : this.b2max) + this.beenHere = {}; + this.beenHere[invalid] = true; + var bestSolution = this.solve((startingBucket == "one" ? this.b1max : 0), (startingBucket == "two" ? this.b2max : 0)) + this.goalBucket = bestSolution.goalBucket; + this.otherBucket = bestSolution.otherBucketFill; + this.minMoves = 1 + bestSolution.numMoves; +} + +TwoBucket.prototype.moves = function() { + return this.minMoves; +}; + +TwoBucket.prototype.solve = function(bucket1fill, bucket2fill) { + // if you've already been in this state, return + if (this.beenHere[bucket1fill + "," + bucket2fill]) return {goalBucket: null}; + else this.beenHere[bucket1fill + "," + bucket2fill] = true; + + // if either bucket is filled to the goal amount, you've found a solution + if (bucket1fill == this.goalAmount) { + return {numMoves: 0, goalBucket: "one", otherBucketFill: bucket2fill}; + } + if (bucket2fill == this.goalAmount) { + return {numMoves: 0, goalBucket: "two", otherBucketFill: bucket1fill}; + } + + if (this.states[bucket1fill + "," + bucket2fill]) { + return this.states[bucket1fill + "," + bucket2fill]; + } + + + var testObj, bestSolution = {goalBucket: null}; + // fill bucket 1 to top + if (bucket1fill !== this.b1max && bucket2fill !== this.b2max) { + testObj = this.solve(this.b1max, bucket2fill); + bestSolution = betterSolution(testObj, bestSolution); + } + + // fill bucket 2 to top + if (bucket1fill !== this.b1max && bucket2fill !== this.b2max) { + testObj = this.solve(bucket1fill, this.b2max); + bestSolution = betterSolution(testObj, bestSolution); + } + + // empty bucket 1 + if (bucket1fill !== 0 && bucket2fill !== 0) { + //console.log("empty 1"); + testObj = this.solve(0, bucket2fill); + bestSolution = betterSolution(testObj, bestSolution); + } + + // empty bucket 2 + if (bucket1fill !== 0 && bucket2fill !== 0) { + //console.log("empty 2"); + testObj = this.solve(bucket1fill, 0); + bestSolution = betterSolution(testObj, bestSolution); + } + + var totalAmount = bucket1fill + bucket2fill; + // pour bucket 1 into bucket 2 + if (bucket2fill !== this.b2max) { + if (totalAmount <= this.b2max) {testObj = this.solve(0, totalAmount);} + else {testObj = this.solve(totalAmount - this.b2max, this.b2max);} + bestSolution = betterSolution(testObj, bestSolution); + } + + // pour bucket 2 into bucket 1 + if (bucket1fill !== this.b1max) { + if (totalAmount <= this.b1max) testObj = this.solve(totalAmount, 0); + else testObj = this.solve(this.b1max, totalAmount - this.b1max); + bestSolution = betterSolution(testObj, bestSolution); + } + + this.states[bucket1fill + "," + bucket2fill] = bestSolution; + if (typeof bestSolution.numMoves === "number") { + bestSolution.numMoves++; + } + return bestSolution; +} + +function betterSolution(test, currentBest) { + if (test.goalBucket) { + if (!currentBest || !currentBest.goalBucket || test.numMoves < currentBest.numMoves) { + return test; + } + } + return currentBest; +} + +module.exports = TwoBucket; diff --git a/two-bucket/example.js b/two-bucket/example.js new file mode 100644 index 00000000..aac22bf0 --- /dev/null +++ b/two-bucket/example.js @@ -0,0 +1,89 @@ +'use strict'; + +function TwoBucket(x,y,z,starter) { + this.starter = starter; + this.x = x; + this.y = y; + + this.reachedGoal = function(measurements) { + var reached = false; + if(measurements[0] == z || measurements[1] == z) { + if(measurements[0] == z) { + this.goalBucket = 'one'; + this.otherBucket = measurements[1]; + } else { + this.goalBucket = 'two'; + this.otherBucket = measurements[0]; + } + reached = true; + } + return reached; + } + + this.bigFirst = function(measurements, moveCount, prBool) { + var j = measurements[0], k = measurements[1]; + while(true) { + if(this.reachedGoal(measurements)) break; + if(k > x && j == 0 && moveCount == 0) { + j = x; + k = y - j; + } else if(j == x) { + j = 0; + } else if((k > x && j !== 0) || (k > x && prBool)) { + k = k - (x-j); + j = x; + } else if(k > x || j == 0) { + j = k; + k = k - j; + } else if(k == 0) { + k = y; + } + measurements = [j,k]; + moveCount++; + prBool ? prBool = false : prBool = true; + } + return moveCount; + } + + this.smallFirst = function(measurements, moveCount, prBool) { + var j = measurements[0], k = measurements[1]; + while(true) { + if(this.reachedGoal(measurements)) break; + if(j == x && moveCount == 0) { + j = 0; + k = x; + } else if(j == 0) { + j = x; + } else if(j == x && k < y) { + var tempK = k; + k + j > y ? k = y : k = tempK + j; + tempK + j > y ? j = j - (y- tempK) : j = 0; + } else if(k == y) { + k = 0; + } else if(k == 0 && j < x) { + k = j; + j = 0; + } + measurements = [j,k]; + moveCount++; + prBool ? prBool = false : prBool = true; + } + return moveCount; + } +} + +TwoBucket.prototype.moves = function() { + var j = 0, k = 0; //j will be running val of bucket one, k = running val of bucket two + this.starter == 'one' ? j = this.x : k = this.y; + var measurements = [j,k]; + var moveCount = 0; + var prBool = true; // pour / receive boolean - need to pour or receive every other turn + if(this.starter == 'one') { + moveCount = this.smallFirst(measurements, moveCount, prBool); + } else { + moveCount = this.bigFirst(measurements, moveCount, prBool); + } + return moveCount + 1; //accounts for first move made before loop (and moveCount starts at zero before loop) +} + +module.exports = TwoBucket; diff --git a/two-bucket/two-bucket_test.spec.js b/two-bucket/two-bucket_test.spec.js new file mode 100644 index 00000000..c3ca98e1 --- /dev/null +++ b/two-bucket/two-bucket_test.spec.js @@ -0,0 +1,47 @@ +var TwoBucket = require('./two-bucket'); + +describe('TwoBucket', function(){ + describe('works for input of 3,5,1', function(){ + var buckOne = 3; + var buckTwo = 5; + var goal = 1; + + it('starting with bucket one', function(){ + var starterBuck = 'one'; //indicates which bucket to fill first + var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + expect(twoBucket.moves()).toEqual(4); //includes the first fill + expect(twoBucket.goalBucket).toEqual('one'); //which bucket should end up with the desired # of liters + expect(twoBucket.otherBucket).toEqual(5); //leftover value in the "other" bucket once the goal has been reached + }); + + it('starting with bucket two', function(){ + var starterBuck = 'two'; + var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + expect(twoBucket.moves()).toEqual(8); + expect(twoBucket.goalBucket).toEqual('two'); + expect(twoBucket.otherBucket).toEqual(3); + }); + }); + + describe('works for input of 7,11,2', function(){ + var buckOne = 7; + var buckTwo = 11; + var goal = 2; + + it('starting with bucket one', function(){ + var starterBuck = 'one'; + var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + expect(twoBucket.moves()).toEqual(14); + expect(twoBucket.goalBucket).toEqual('one'); + expect(twoBucket.otherBucket).toEqual(11); + }); + + it('starting with bucket two', function(){ + var starterBuck = 'two'; + var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + expect(twoBucket.moves()).toEqual(18); + expect(twoBucket.goalBucket).toEqual('two'); + expect(twoBucket.otherBucket).toEqual(7); + }); + }); +});