986 行
29 KiB
JavaScript

// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of the University of San Francisco
function DPChange(am, w, h)
{
this.init(am, w, h);
}
DPChange.prototype = new Algorithm();
DPChange.prototype.constructor = DPChange;
DPChange.superclass = Algorithm.prototype;
DPChange.TABLE_ELEM_WIDTH = 30;
DPChange.TABLE_ELEM_HEIGHT = 30;
DPChange.TABLE_START_X = 500;
DPChange.TABLE_START_Y = 50;
DPChange.TABLE_DIFF_X = 70;
DPChange.CODE_START_X = 10;
DPChange.CODE_START_Y = 10;
DPChange.CODE_LINE_HEIGHT = 14;
DPChange.GREEDY_START_X = 100;
DPChange.GREEDY_START_Y = 150;
DPChange.RECURSIVE_START_X = 220;
DPChange.RECURSIVE_START_Y = 10;
DPChange.RECURSIVE_DELTA_Y = 14;
DPChange.RECURSIVE_DELTA_X = 8;
DPChange.CODE_HIGHLIGHT_COLOR = "#FF0000";
DPChange.CODE_STANDARD_COLOR = "#000000";
DPChange.TABLE_INDEX_COLOR = "#0000FF"
DPChange.CODE_RECURSIVE_1_COLOR = "#339933";
DPChange.CODE_RECURSIVE_2_COLOR = "#0099FF";
DPChange.DPCode = [["def ","change(n, coinArray)",":"],
[" if ","(n == 0) "],
[" return 0"],
[" best = -1"],
[" for coin in coinArray:"],
[" if ","(coin <= n)",":"],
[" nextTry = ","change(n - coin, coinArray)"],
[" if (", "best < 0", " or ", "best > nextTry + 1", ")"],
[" best = nextTry + 1"],
[" return best"]];
DPChange.GREEDYCode = [["def ","changeGreedy(n, coinArray)",":"],
[" coinsRequired = 0"],
[" for coin in reversed(coinArray): "],
[" while ", "(n <= coin)"],
[" n = n - coin"],
[" coinsRequired = coinsRequired + 1"],
[" return coinsRequired"]];
DPChange.COINS = [[1, 5, 10, 25],
[1, 4, 6, 10]];
DPChange.MAX_VALUE = 30;
DPChange.MESSAGE_ID = 0;
DPChange.prototype.setCode = function(codeArray)
{
this.code = codeArray;
this.codeID = Array(this.code.length);
var i, j;
for (i = 0; i < this.code.length; i++)
{
this.codeID[i] = new Array(this.code[i].length);
for (j = 0; j < this.code[i].length; j++)
{
this.codeID[i][j] = this.nextIndex++;
this.cmd("CreateLabel", this.codeID[i][j], this.code[i][j], DPChange.CODE_START_X, DPChange.CODE_START_Y + i * DPChange.CODE_LINE_HEIGHT, 0);
this.cmd("SetForegroundColor", this.codeID[i][j], DPChange.CODE_STANDARD_COLOR);
if (j > 0)
{
this.cmd("AlignRight", this.codeID[i][j], this.codeID[i][j-1]);
}
}
}
}
DPChange.prototype.deleteCode = function()
{
var i,j
for (i = 0; i < this.codeID.length; i++)
{
for (j = 0; j < this.codeID[i].length; j++)
{
this.cmd("Delete", this.codeID[i][j]);
}
}
this.codeID = [];
}
DPChange.prototype.setCodeAlpha = function(codeArray, alpha)
{
var i, j
for (i = 0; i < codeArray.length; i++)
{
var foo = 3;
foo = codeArray[i];
for (j = 0; j < codeArray[i].length; j++)
{
this.cmd("SetAlpha", codeArray[i][j], alpha);
}
}
}
DPChange.prototype.init = function(am, w, h)
{
DPChange.superclass.init.call(this, am, w, h);
this.nextIndex = 0;
this.addControls();
// HACK!!
this.setCode(DPChange.GREEDYCode);
this.greedyCodeID = this.codeID;
this.setCodeAlpha(this.greedyCodeID, 0);
///
this.setCode(DPChange.DPCode);
this.usingDPCode = true;
this.animationManager.StartNewAnimation(this.commands);
this.animationManager.skipForward();
this.animationManager.clearHistory();
this.initialIndex = this.nextIndex;
this.oldIDs = [];
this.commands = [];
}
DPChange.prototype.addControls = function()
{
this.controls = [];
this.fibField = addControlToAlgorithmBar("Text", "");
this.fibField.onkeydown = this.returnSubmit(this.fibField, this.emptyCallback.bind(this), 2, true);
this.controls.push(this.fibField);
this.recursiveButton = addControlToAlgorithmBar("Button", "Change Recursive");
this.recursiveButton.onclick = this.recursiveCallback.bind(this);
this.controls.push(this.recursiveButton);
this.tableButton = addControlToAlgorithmBar("Button", "Change Table");
this.tableButton.onclick = this.tableCallback.bind(this);
this.controls.push(this.tableButton);
this.memoizedButton = addControlToAlgorithmBar("Button", "Change Memoized");
this.memoizedButton.onclick = this.memoizedCallback.bind(this);
this.controls.push(this.memoizedButton);
this.greedyButton = addControlToAlgorithmBar("Button", "Change Greedy");
this.greedyButton.onclick = this.greedyCallback.bind(this);
this.controls.push(this.greedyButton);
var coinLabels = [];
var i, j;
for (i = 0; i < DPChange.COINS.length; i++)
{
var nextLabel = "Coins: [" + DPChange.COINS[i][0];
for (j = 1; j < DPChange.COINS[i].length; j++)
{
nextLabel = nextLabel + ", " + DPChange.COINS[i][j];
}
nextLabel = nextLabel + "]";
coinLabels.push(nextLabel);
}
this.coinTypeButtons = addRadioButtonGroupToAlgorithmBar(coinLabels, "CoinType");
for (i = 0; i < this.coinTypeButtons.length; i++)
{
this.coinTypeButtons[i].onclick = this.coinTypeChangedCallback.bind(this, i);
this.controls.push(this.coinTypeButtons[i]);
}
this.coinTypeButtons[0].checked = true;
this.coinIndex = 0;
}
DPChange.prototype.coinTypeChangedCallback = function(coinIndex)
{
this.implementAction(this.coinTypeChanged.bind(this), coinIndex);
}
DPChange.prototype.coinTypeChanged = function(coinIndex)
{
this.commands = [];
this.coinIndex = coinIndex;
this.coinTypeButtons[coinIndex].checked = true;
this.clearOldIDs();
return this.commands;
}
DPChange.prototype.greedyCallback = function(value)
{
if (this.fibField.value != "")
{
this.implementAction(this.implementGreedy.bind(this),parseInt(this.fibField.value));
}
else
{
this.implementAction(this.helpMessage.bind(this), "");
}
}
DPChange.prototype.implementGreedy = function(value)
{
this.commands = [];
this.clearOldIDs();
var initialValue = value;
if (this.usingDPCode)
{
this.setCodeAlpha(this.greedyCodeID, 1);
this.setCodeAlpha(this.codeID, 0);
this.usingDPCode = false;
}
var currX = DPChange.GREEDY_START_X;
var currY = DPChange.GREEDY_START_Y + 2.5 * DPChange.TABLE_ELEM_HEIGHT;
var messageID = this.nextIndex++;
this.oldIDs.push(messageID);
var valueRemainingID = this.nextIndex++;
this.oldIDs.push(valueRemainingID);
this.cmd("CreateRectangle", valueRemainingID, value, DPChange.TABLE_ELEM_WIDTH,
DPChange.TABLE_ELEM_HEIGHT,
DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y);
var tempLabel = this.nextIndex++;
this.oldIDs.push(tempLabel);
this.cmd("CreateLabel", tempLabel, "Amount remaining:",0, 0);
this.cmd("AlignLeft", tempLabel, valueRemainingID);
var requiredCoinsID = this.nextIndex++;
this.oldIDs.push(requiredCoinsID);
this.cmd("CreateRectangle", requiredCoinsID, value, DPChange.TABLE_ELEM_WIDTH,
DPChange.TABLE_ELEM_HEIGHT,
DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y + DPChange.TABLE_ELEM_HEIGHT);
tempLabel = this.nextIndex++;
this.oldIDs.push(tempLabel);
this.cmd("CreateLabel", tempLabel, "Required Coins:",0, 0);
this.cmd("AlignLeft", tempLabel, requiredCoinsID);
var requiredCoins = 0;
var i;
for (i = DPChange.COINS[this.coinIndex].length - 1; i >=0; i--)
{
while (value >= DPChange.COINS[this.coinIndex][i])
{
requiredCoins = requiredCoins + 1;
value = value - DPChange.COINS[this.coinIndex][i];
this.cmd("SetText", valueRemainingID, value);
this.cmd("SetText", requiredCoinsID, requiredCoins);
var moveIndex = this.nextIndex++;
this.oldIDs.push(moveIndex);
this.cmd("CreateLabel", moveIndex, DPChange.COINS[this.coinIndex][i], DPChange.GREEDY_START_X, DPChange.GREEDY_START_Y);
this.cmd("Move", moveIndex, currX, currY);
currX += DPChange.TABLE_ELEM_WIDTH;
this.cmd("Step");
}
}
this.cmd("CreateLabel", messageID,
"changeGreedy(" + String(initialValue)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(requiredCoins),
DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y, 0);
return this.commands;
}
DPChange.prototype.buildTable = function(maxVal)
{
this.tableID = new Array(2);
this.tableVals = new Array(2);
this.tableXPos = new Array(2);
this.tableYPos = new Array(2);
var i;
for (i = 0; i < 2; i++)
{
this.tableID[i] = new Array(maxVal + 1);
this.tableVals[i] = new Array(maxVal + 1);
this.tableXPos[i] = new Array(maxVal + 1);
this.tableYPos[i] = new Array(maxVal + 1);
}
var j;
var indexID;
var xPos;
var yPos;
var table_rows = Math.floor((this.canvasHeight - DPChange.TABLE_ELEM_HEIGHT - DPChange.TABLE_START_Y) / DPChange.TABLE_ELEM_HEIGHT);
var table_cols = Math.ceil((maxVal + 1) / table_rows);
var header1ID = this.nextIndex++;
this.oldIDs.push(header1ID);
this.cmd("CreateLabel", header1ID, "# of Coins Required", DPChange.TABLE_START_X, DPChange.TABLE_START_Y - 30);
var header2ID = this.nextIndex++;
this.oldIDs.push(header2ID);
this.cmd("CreateLabel", header2ID, "Coins to Use", DPChange.TABLE_START_X + table_cols*DPChange.TABLE_DIFF_X + 1.5*DPChange.TABLE_DIFF_X, DPChange.TABLE_START_Y - 30);
for (i = 0; i <= maxVal; i++)
{
yPos = i % table_rows * DPChange.TABLE_ELEM_HEIGHT + DPChange.TABLE_START_Y;
xPos = Math.floor(i / table_rows) * DPChange.TABLE_DIFF_X + DPChange.TABLE_START_X;
for (j = 0; j < 2; j++)
{
this.tableID[j][i] = this.nextIndex++;
this.tableVals[j][i] = -1;
this.oldIDs.push(this.tableID[j][i]);
this.tableXPos[j][i] = xPos;
this.tableYPos[j][i] = yPos;
this.cmd("CreateRectangle", this.tableID[j][i],
"",
DPChange.TABLE_ELEM_WIDTH,
DPChange.TABLE_ELEM_HEIGHT,
xPos,
yPos);
indexID = this.nextIndex++;
this.oldIDs.push(indexID);
this.cmd("CreateLabel", indexID, i, xPos - DPChange.TABLE_ELEM_WIDTH, yPos);
this.cmd("SetForegroundColor", indexID, DPChange.TABLE_INDEX_COLOR);
xPos = xPos + table_cols * DPChange.TABLE_DIFF_X + 1.5*DPChange.TABLE_DIFF_X;
}
}
}
DPChange.prototype.clearOldIDs = function()
{
for (var i = 0; i < this.oldIDs.length; i++)
{
this.cmd("Delete", this.oldIDs[i]);
}
this.oldIDs =[];
this.nextIndex = this.initialIndex;
}
DPChange.prototype.reset = function()
{
this.oldIDs =[];
this.coinIndex = 0;
this.usingDPCode = true;
this.coinTypeButtons[0].checked = true;
this.nextIndex = this.initialIndex;
}
DPChange.prototype.emptyCallback = function(event)
{
this.implementAction(this.helpMessage.bind(this), "");
// TODO: Put up a message to push the appropriate button?
}
DPChange.prototype.displayCoinsUsed = function()
{
var currValue = this.tableVals[1].length - 1;
var currX = 30;
var currY = 200;
var moveID;
moveID = this.nextIndex++;
while (currValue > 0)
{
moveID = this.nextIndex++;
this.oldIDs.push(moveID);
this.cmd("CreateLabel", moveID, this.tableVals[1][currValue], this.tableXPos[1][currValue], this.tableYPos[1][currValue]);
this.cmd("Move", moveID, currX, currY);
this.cmd("Step");
currX += 20;
currValue = currValue - this.tableVals[1][currValue];
}
}
DPChange.prototype.recursiveCallback = function(event)
{
var fibValue;
if (this.fibField.value != "")
{
var fibValue = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE - 5);
this.fibField.value = String(fibValue);
this.implementAction(this.recursiveChange.bind(this),fibValue);
}
else
{
this.implementAction(this.helpMessage.bind(this), "");
}
}
DPChange.prototype.tableCallback = function(event)
{
var fibValue;
if (this.fibField.value != "")
{
var fibValue = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE);
this.fibField.value = String(fibValue);
this.implementAction(this.tableChange.bind(this),fibValue);
}
else
{
this.implementAction(this.helpMessage.bind(this), "");
}
}
DPChange.prototype.memoizedCallback = function(event)
{
var fibValue;
if (this.fibField.value != "")
{
var changeVal = Math.min(parseInt(this.fibField.value), DPChange.MAX_VALUE);
this.fibField.value = String(changeVal);
this.implementAction(this.memoizedChange.bind(this),changeVal);
}
else
{
this.implementAction(this.helpMessage.bind(this), "");
}
}
DPChange.prototype.helpMessage = function(value)
{
this.commands = [];
this.clearOldIDs();
var messageID = this.nextIndex++;
this.oldIDs.push(messageID);
this.cmd("CreateLabel", messageID,
"Enter a value between 0 and " + String(DPChange.MAX_VALUE) + " in the text field.\n" +
"Then press the Change Recursive, Change Table, Change Memoized, or Change Greedy button",
DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y, 0);
return this.commands;
}
DPChange.prototype.recursiveChange = function(value)
{
this.commands = [];
this.clearOldIDs();
if (!this.usingDPCode)
{
this.setCodeAlpha(this.greedyCodeID, 0);
this.setCodeAlpha(this.codeID, 1);
this.usingDPCode = true;
}
this.currentY = DPChange.RECURSIVE_START_Y;
var functionCallID = this.nextIndex++;
this.oldIDs.push(functionCallID);
var final = this.change(value, DPChange.RECURSIVE_START_X, functionCallID);
this.cmd("SetText", functionCallID, "change(" + String(value)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(final[0]));
return this.commands;
}
DPChange.prototype.change = function(value, xPos, ID)
{
var coins = DPChange.COINS[this.coinIndex];
this.cmd("CreateLabel", ID, "change(" + String(value)+ ", [" +String(coins) +"])", xPos, this.currentY, 0);
this.currentY += DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
// return 1;
if (value > 0)
{
this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_STANDARD_COLOR);
var i;
var best = -1;
var nextID = this.nextIndex++;
var nextID2 = this.nextIndex++;
var recID = nextID;
var bestList;
for (i = 0; i < coins.length; i++)
{
this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_STANDARD_COLOR);
if (value >= coins[i])
{
this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_STANDARD_COLOR);
var nextTry = this.change(value - coins[i], xPos + DPChange.RECURSIVE_DELTA_X, recID);
// TODO: SOMEHTING ELSE HERE
if (best == -1)
{
this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_STANDARD_COLOR);
best = nextTry[0] + 1;
bestList = nextTry[1];
bestList.push(coins[i]);
this.currentY += DPChange.RECURSIVE_DELTA_Y;
recID = nextID2;
}
else if (best > nextTry[0] + 1)
{
this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_STANDARD_COLOR);
best = nextTry[0] + 1;
bestList = nextTry[1];
bestList.push(coins[i]);;
this.cmd("Delete", recID);
this.cmd("SetText", nextID, String(best) + " ([" + String(bestList) + "])");
this.cmd("SetPosition", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
this.cmd("Move", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY - DPChange.RECURSIVE_DELTA_Y);
this.cmd("Step");
}
else
{
this.cmd("Delete", recID);
}
}
else
{
break;
}
}
this.cmd("Delete", nextID);
this.cmd("SetText", ID, String(best) + " ([" + String(bestList) + "])");
this.cmd("SetPosition", ID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
this.cmd("Move", ID, xPos, this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y);
this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("Step");
return [best, bestList];
}
else
{
this.cmd("SetText", ID, "0");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
this.currentY -= DPChange.RECURSIVE_DELTA_Y;
return [0, []];
}
}
DPChange.prototype.tableChange = function(value)
{
this.commands = [];
this.clearOldIDs();
if (!this.usingDPCode)
{
this.setCodeAlpha(this.greedyCodeID, 0);
this.setCodeAlpha(this.codeID, 1);
this.usingDPCode = true;
}
this.buildTable(value);
coins = DPChange.COINS[this.coinIndex];
var i;
for (i = 0; i <= value && i <= 0; i++)
{
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("SetHighlight", this.tableID[0][i], 1);
this.cmd("SetText", this.tableID[0][i], 0);
this.tableVals[0][i] = 0;
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetHighlight", this.tableID[0][i], 0);
}
for (i = 1; i <= value; i++)
{
this.tableVals[0][i] = -1;
var j;
for (j = 0; j < coins.length; j++)
{
if (coins[j] <= i)
{
this.cmd("SetHighlight", this.tableID[0][i-coins[j]], 1);
this.cmd("SetHighlight", this.tableID[0][i], 1);
this.cmd("Step");
if (this.tableVals[0][i] == -1 || this.tableVals[0][i] > this.tableVals[0][i - coins[j]] + 1)
{
this.tableVals[0][i] = this.tableVals[0][i- coins[j]] + 1;
this.cmd("SetText", this.tableID[0][i], this.tableVals[0][i]);
this.cmd("SetHighlight", this.tableID[1][i], 1);
this.cmd("SetText", this.tableID[1][i], coins[j]);
this.tableVals[1][i] = coins[j];
this.cmd("Step")
this.cmd("SetHighlight", this.tableID[1][i], 0);
}
this.cmd("SetHighlight", this.tableID[0][i-coins[j]], 0);
this.cmd("SetHighlight", this.tableID[0][i], 0);
}
}
}
var finalID = this.nextIndex++;
this.oldIDs.push(finalID);
this.cmd("CreateLabel", finalID, this.tableVals[0][value], this.tableXPos[0][value] - 5, this.tableYPos[0][value] - 5, 0);
this.cmd("Move", finalID, DPChange.RECURSIVE_START_X, DPChange.RECURSIVE_START_Y);
this.cmd("Step");
this.cmd("SetText", finalID, "change(" + String(value) + ") = " + String(this.tableVals[0][value]));
this.displayCoinsUsed();
return this.commands;
}
DPChange.prototype.fibMem = function(value, xPos, ID)
{
this.cmd("CreateLabel", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
this.cmd("SetHighlight", this.tableID[value], 1);
// TODO: Add an extra pause here?
this.cmd("Step");
if (this.tableVals[value] >= 0)
{
this.cmd("Delete", ID, "fib(" + String(value)+")", xPos, this.currentY, 0);
this.cmd("CreateLabel", ID, this.tableVals[value], this.tableXPos[value] - 5, this.tableYPos[value] - 5, 0);
this.cmd("Move", ID, xPos, this.currentY);
this.cmd("Step")
this.cmd("SetHighlight", this.tableID[value], 0);
return this.tableVals[value];
}
this.cmd("SetHighlight", this.tableID[value], 0);
this.currentY += DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
if (value > 1)
{
var firstID = this.nextIndex++;
var secondID = this.nextIndex++;
this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_STANDARD_COLOR);
var firstValue = this.fibMem(value-1, xPos + DPChange.RECURSIVE_DELTA_X, firstID);
this.currentY += DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_STANDARD_COLOR);
var secondValue = this.fibMem(value-2, xPos + DPChange.RECURSIVE_DELTA_X, secondID);
this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_RECURSIVE_1_COLOR);
this.cmd("SetForegroundColor", firstID, DPChange.CODE_RECURSIVE_1_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][2], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_RECURSIVE_2_COLOR);
this.cmd("SetForegroundColor", secondID, DPChange.CODE_RECURSIVE_2_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[4][1], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][2], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][3], DPChange.CODE_STANDARD_COLOR);
this.cmd("Delete", firstID);
this.cmd("Delete", secondID);
this.cmd("SetText", ID, firstValue + secondValue);
this.cmd("Step");
this.tableVals[value] = firstValue + secondValue;
this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos+5, this.currentY + 5);
this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
this.cmd("Step");
this.cmd("Delete", this.nextIndex);
this.cmd("SetText", this.tableID[value], this.tableVals[value]);
return firstValue + secondValue;
}
else
{
this.cmd("SetText", ID, "1");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
this.tableVals[value] = 1;
this.cmd("CreateLabel", this.nextIndex, this.tableVals[value], xPos + 5, this.currentY + 5);
this.cmd("Move", this.nextIndex, this.tableXPos[value], this.tableYPos[value], this.currentY);
this.cmd("Step");
this.cmd("Delete", this.nextIndex);
this.cmd("SetText", this.tableID[value], this.tableVals[value]);
this.currentY -= DPChange.RECURSIVE_DELTA_Y;
return 1;
}
}
DPChange.prototype.memoizedChange = function(value)
{
this.commands = [];
if (!this.usingDPCode)
{
this.setCodeAlpha(this.greedyCodeID, 0);
this.setCodeAlpha(this.codeID, 1);
this.usingDPCode = true;
}
this.clearOldIDs();
this.buildTable(value);
this.currentY = DPChange.RECURSIVE_START_Y;
var functionCallID = this.nextIndex++;
this.oldIDs.push(functionCallID);
var final = this.changeMem(value, DPChange.RECURSIVE_START_X, functionCallID);
this.cmd("SetText", functionCallID, "change(" + String(value)+ ", [" +String(DPChange.COINS[this.coinIndex]) +"]) = " + String(final[0]));
return this.commands;
this.currentY = DPChange.RECURSIVE_START_Y;
return this.commands;
}
DPChange.prototype.changeMem = function(value, xPos, ID)
{
var coins = DPChange.COINS[this.coinIndex];
this.cmd("CreateLabel", ID, "change(" + String(value)+ ", [" +String(coins) +"])", xPos, this.currentY, 0);
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("SetHighlight", this.tableID[0][value], 1);
this.cmd("Step");
if (this.tableVals[0][value] >= 0)
{
this.cmd("Delete", ID);
this.cmd("CreateLabel", ID, this.tableVals[0][value], this.tableXPos[0][value] - 5, this.tableYPos[0][value] - 5, 0);
this.cmd("Move", ID, xPos, this.currentY);
this.cmd("Step")
this.cmd("SetHighlight", this.tableID[0][value], 0);
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
return [this.tableVals[0][value], []];
}
this.cmd("SetHighlight", this.tableID[0][value], 0);
this.currentY += DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[0][1], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[1][1], DPChange.CODE_STANDARD_COLOR);
// return 1;
if (value > 0)
{
this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[3][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[4][0], DPChange.CODE_STANDARD_COLOR);
var i;
var best = -1;
var nextID = this.nextIndex++;
var nextID2 = this.nextIndex++;
var recID = nextID;
var bestList;
for (i = 0; i < coins.length; i++)
{
this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[5][1], DPChange.CODE_STANDARD_COLOR);
if (value >= coins[i])
{
this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[6][1], DPChange.CODE_STANDARD_COLOR);
var nextTry = this.changeMem(value - coins[i], xPos + DPChange.RECURSIVE_DELTA_X, recID);
// TODO: SOMEHTING ELSE HERE
if (best == -1)
{
this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[7][1], DPChange.CODE_STANDARD_COLOR);
best = nextTry[0] + 1;
bestList = nextTry[1];
bestList.push(coins[i]);;
this.currentY += DPChange.RECURSIVE_DELTA_Y;
recID = nextID2;
}
else if (best > nextTry[0] + 1)
{
this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[7][2], DPChange.CODE_STANDARD_COLOR);
best = nextTry[0] + 1;
bestList = nextTry[1];
bestList.push(coins[i]);;
this.cmd("Delete", recID);
this.cmd("SetText", nextID, String(best));
this.cmd("SetPosition", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
this.cmd("Move", nextID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY - DPChange.RECURSIVE_DELTA_Y);
this.cmd("Step");
}
else
{
this.cmd("Step");
this.cmd("Delete", recID);
}
}
else
{
break;
}
}
this.cmd("Delete", nextID);
this.cmd("SetText", ID, String(best));
this.cmd("SetText", this.tableID[0][value], best);
this.cmd("SetText", this.tableID[1][value], bestList[0]);
this.tableVals[0][value] = best;
this.tableVals[1][value] = bestList[0];
this.cmd("SetPosition", ID, xPos + DPChange.RECURSIVE_DELTA_X, this.currentY);
this.cmd("Move", ID, xPos, this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y);
this.currentY = this.currentY - 2 * DPChange.RECURSIVE_DELTA_Y;
this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[9][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("Step");
return [best, bestList];
}
else
{
this.cmd("SetText", ID, "0");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_HIGHLIGHT_COLOR);
this.cmd("Step");
this.cmd("SetForegroundColor", this.codeID[2][0], DPChange.CODE_STANDARD_COLOR);
this.cmd("SetText", this.tableID[0][value], 0);
this.currentY -= DPChange.RECURSIVE_DELTA_Y;
return [0, []];
}
}
DPChange.prototype.enableUI = function(event)
{
for (var i = 0; i < this.controls.length; i++)
{
this.controls[i].disabled = false;
}
}
DPChange.prototype.disableUI = function(event)
{
for (var i = 0; i < this.controls.length; i++)
{
this.controls[i].disabled = true;
}
}
var currentAlg;
function init()
{
var animManag = initCanvas();
currentAlg = new DPChange(animManag, canvas.width, canvas.height);
}