Skip to content

Commit

Permalink
Ch 3 - Add sliders
Browse files Browse the repository at this point in the history
Use sliders instead of animation so that the reader has control over speed and pausing and rewinding
  • Loading branch information
Rishav159 authored and redblobgames committed Aug 2, 2017
1 parent 9fd4613 commit 09a6163
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 114 deletions.
52 changes: 31 additions & 21 deletions 3-Solving-Problems-By-Searching/c_breadthFirstSearch.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
$(document).ready(function() {
var w = 600,
h = 350;
var DELAY = 2000;
var intervalFunction = null;

function init() {
clearInterval(intervalFunction, DELAY);
var graph = new DefaultGraph();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
var graphAgent = new GraphAgent(graphProblem);
var options = new DefaultOptions();
options.nodes.next.fill = 'hsla(126, 100%, 69%, 1)';
var graphDrawAgent = new GraphDrawAgent(graphProblem, 'breadthFirstSearchCanvas', options, h, w);
var queueDrawAgent = new QueueDrawAgent('fifoQueueCanvas', h, w, graphProblem, options);
//Update handler is the function that would be executed every DELAY ms.
var updateFunction = function() {
if (graphProblem.frontier.length > 0) {
var nextNode = breadthFirstSearch(graphProblem);
graphAgent.expand(nextNode);
//If frontier is still present, find the next node to be expanded so it
//could be colored differently

var drawState = function(n) {
var graph = new DefaultGraph();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
var graphAgent = new GraphAgent(graphProblem);

var graphDrawAgent = new GraphDrawAgent(graphProblem, 'breadthFirstSearchCanvas', options, h, w);
var queueDrawAgent = new QueueDrawAgent('fifoQueueCanvas', h, w, graphProblem, options);

while (n--) {
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = breadthFirstSearch(graphProblem);
var nextNode = breadthFirstSearch(graphProblem);
graphAgent.expand(nextNode);
//If frontier is still present, find the next node to be expanded so it
//could be colored differently
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = breadthFirstSearch(graphProblem);
} else {
graphProblem.nextToExpand = null;
}
} else {
graphProblem.nextToExpand = null;
break;
}
graphDrawAgent.iterate();
queueDrawAgent.iterate();
} else {
clearInterval(intervalFunction, DELAY);
}
graphDrawAgent.iterate();
queueDrawAgent.iterate();
}
intervalFunction = setInterval(updateFunction, DELAY);

let ac = new AnimationController({
selector: '#bfsAC',
min: 0,
max: 15,
renderer: drawState
});
ac.renderFirst();
};

$('#bfsRestartButton').click(init);
$('#fifoWaiting').css('background-color', 'hsl(0,50%,75%)');
$('#fifoNextNode').css('background-color', 'hsl(126, 100%, 69%)');
Expand Down
49 changes: 30 additions & 19 deletions 3-Solving-Problems-By-Searching/c_depthFirstSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,43 @@ $(document).ready(function() {
var intervalFunction = null;

function init() {
clearInterval(intervalFunction, DELAY);
var graph = new DefaultGraph();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
var graphAgent = new GraphAgent(graphProblem);
var options = new DefaultOptions();
options.nodes.next.fill = 'hsla(126, 100%, 69%, 1)';
var graphDrawAgent = new GraphDrawAgent(graphProblem, 'depthFirstSearchCanvas', options, h, w);
var queueDrawAgent = new QueueDrawAgent('lifoQueueCanvas', h, w, graphProblem, options);
var updateFunction = function() {
if (graphProblem.frontier.length > 0) {
var nextNode = depthFirstSearch(graphProblem);
graphAgent.expand(nextNode);
//If frontier is still present, find the next node to be expanded so it
//could be colored differently

var drawState = function(n) {
var graph = new DefaultGraph();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
var graphAgent = new GraphAgent(graphProblem);

var graphDrawAgent = new GraphDrawAgent(graphProblem, 'depthFirstSearchCanvas', options, h, w);
var queueDrawAgent = new QueueDrawAgent('lifoQueueCanvas', h, w, graphProblem, options);

while (n--) {
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = depthFirstSearch(graphProblem);
var nextNode = depthFirstSearch(graphProblem);
graphAgent.expand(nextNode);
//If frontier is still present, find the next node to be expanded so it
//could be colored differently
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = depthFirstSearch(graphProblem);
} else {
graphProblem.nextToExpand = null;
}
} else {
graphProblem.nextToExpand = null;
break;
}
graphDrawAgent.iterate();
queueDrawAgent.iterate();
} else {
clearInterval(intervalFunction, DELAY);
}
graphDrawAgent.iterate();
queueDrawAgent.iterate();
}
intervalFunction = setInterval(updateFunction, DELAY);

let ac = new AnimationController({
selector: '#dfsAC',
min: 0,
max: 15,
renderer: drawState
});
ac.renderFirst();
};
$('#dfsRestartButton').click(init);
$('#lifoWaiting').css('background-color', 'hsl(0,50%,75%)');
Expand Down
67 changes: 36 additions & 31 deletions 3-Solving-Problems-By-Searching/c_uniformCostSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,51 @@ $(document).ready(function() {
}).appendTo(exploredQueueCanvas);
//Intial value for separation is 0
$('.ucsSeparation').html(0);
var graph = new DefaultGraph();
//Precompute costs of all nodes from the initial node
var costMap = precomputedCosts();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
//Change the text of all the nodes to its cost
for (key in graphProblem.nodes) {
graphProblem.nodes[key].text = costMap[graphProblem.nodes[key].id];
}
var graphAgent = new GraphAgent(graphProblem, 'ucs');

var options = new DefaultOptions();
options.nodes.next.fill = 'hsla(126, 100%, 69%, 1)';
options.edges.showCost = true;
var graphDrawAgent = new GraphDrawAgent(graphProblem, 'uniformCostSearchCanvas', options, h, w);
drawList(priorityTwo, graphProblem.frontier, graphProblem, options, costMap);
drawList(exploredTwo, graphProblem.explored, graphProblem, options, costMap);
var updateFunction = function() {
if (graphProblem.frontier.length > 0) {
var nextNode = uniformCostSearch(graphProblem);
graphAgent.expand(nextNode);

var drawState = function(n) {
var graph = new DefaultGraph();
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
var graphAgent = new GraphAgent(graphProblem);
for (key in graphProblem.nodes) {
graphProblem.nodes[key].text = costMap[graphProblem.nodes[key].id];
}

var graphDrawAgent = new GraphDrawAgent(graphProblem, 'uniformCostSearchCanvas', options, h, w);
var maxCost;
while (n--) {
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = uniformCostSearch(graphProblem);
var nextNode = uniformCostSearch(graphProblem);
graphAgent.expand(nextNode);
//If frontier is still present, find the next node to be expanded so it
//could be colored differently
if (graphProblem.frontier.length > 0) {
graphProblem.nextToExpand = uniformCostSearch(graphProblem);
maxCost = graphProblem.nodes[graphProblem.nextToExpand].cost;
} else {
graphProblem.nextToExpand = null;
}
} else {
graphProblem.nextToExpand = null;
}
graphDrawAgent.iterate();
drawList(priorityTwo, graphProblem.frontier, graphProblem, options, costMap);
drawList(exploredTwo, graphProblem.explored, graphProblem, options, costMap);
let maxCost = 0;
//Find the max cost which separates the explored from frontier nodes
if (graphProblem.nextToExpand) {
maxCost = graphProblem.nodes[graphProblem.nextToExpand].cost;
break;
}
//Draw it in the front end
$('.ucsSeparation').html(maxCost);
} else {
clearInterval(intervalFunction, DELAY);
}
graphDrawAgent.iterate();
drawList(priorityTwo, graphProblem.frontier, graphProblem, options, costMap);
drawList(exploredTwo, graphProblem.explored, graphProblem, options, costMap);
//Draw it in the front end
$('.ucsSeparation').html(maxCost);
}
intervalFunction = setInterval(updateFunction, DELAY);
let ac = new AnimationController({
selector: '#ucsAC',
min: 0,
max: 15,
renderer: drawState
});
ac.renderFirst();
};
$('#ucsRestartButton').click(init);
$('#ucsWaiting').css('background-color', 'hsl(0,50%,75%)');
Expand All @@ -81,7 +87,6 @@ function drawList(two, list, problem, options, costMap) {
let text = two.makeText(costMap[node.id], x, y);
let fillColor = options.nodes[state].fill;
circle.fill = fillColor;

}
two.update();
}
27 changes: 16 additions & 11 deletions 3-Solving-Problems-By-Searching/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.6.0/two.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>

<script type="text/javascript" src="../globalHelpers.js"></script>
<script type="text/javascript" src="./helpers.js"></script>
<script type="text/javascript" src="./gitter-grid.js"></script>
<script type="text/javascript" src="./aStarSearch.js"></script>
Expand Down Expand Up @@ -111,10 +112,11 @@ <h2>Breadth First Search</h2>
</div>
</div>

<div class="row">
<div class="row" id='bfsDiagram'>
<div class="col-sm-6 col-md-6">
<div class='btn btn-primary' id='bfsRestartButton'>Restart</div>
<div class="canvas" id="breadthFirstSearchCanvas" height="300px">
<div class="row" id='bfsAC'></div>
<div class="row">
<div class="canvas" id="breadthFirstSearchCanvas" height="300px"></div>
</div>
</div>
<div class="col-sm-6 col-md-6">
Expand All @@ -135,6 +137,7 @@ <h4>FIFO Queue</h4>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6 col-sm-6">
<h2>Depth First Search</h2>
Expand All @@ -145,10 +148,11 @@ <h2>Depth First Search</h2>
</div>
</div>

<div class="row">
<div class="row" id='dfsDiagram'>
<div class="col-sm-6 col-md-6">
<div class='btn btn-primary' id='dfsRestartButton'>Restart</div>
<div class="canvas" id="depthFirstSearchCanvas" height="300px">
<div class="row" id='dfsAC'></div>
<div class="row">
<div class="canvas" id="depthFirstSearchCanvas" height="300px"></div>
</div>
</div>
<div class="col-sm-6 col-md-6">
Expand Down Expand Up @@ -238,10 +242,11 @@ <h2>Uniform Cost Search</h2>
</div>
</div>

<div class="row">
<div class="row" id='ucsDiagram'>
<div class="col-sm-6 col-md-6">
<div class='btn btn-primary' id='ucsRestartButton'>Restart</div>
<div class="canvas" id="uniformCostSearchCanvas" height="300px">
<div class="row" id='ucsAC'></div>
<div class="row">
<div class="canvas" id="uniformCostSearchCanvas" height="300px"></div>
</div>
</div>
<div class="col-sm-6 col-md-6">
Expand Down Expand Up @@ -378,12 +383,12 @@ <h2>Bi-directional BFS</h2>
<div class="col-md-6">
<h2 style="text-align:center;">Bi-directional BFS</h2>
<div class="canvas" id='biCanvas' height="300px"></div>
<h1 id = 'biStepCount' style="text-align:center;margin-top:0%;"></h1>
<h1 id='biStepCount' style="text-align:center;margin-top:0%;"></h1>
</div>
<div class="col-md-6">
<h2 style="text-align:center;">Standard BFS</h2>
<div class="canvas" id='bfsCanvas' height="300px"></div>
<h1 id = 'bfsStepCount' style="text-align:center;margin-top:0%;"></h1>
<h1 id='bfsStepCount' style="text-align:center;margin-top:0%;"></h1>
</div>
</div>
</div>
Expand Down
33 changes: 9 additions & 24 deletions 6-Constraint-Satisfaction-Problems/c_backtracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,30 +97,14 @@ class BacktrackingDiagram {
//Run the algorithm and record frames
this.recordFrames(heuristics);
this.addAssignmentTable(this.backtracker.variables);
//Attach listener to the sliders and buttons
let sliderElement = this.selector.select('#backtrackSlider');
this.selector.select('.prevButton').on('mousedown', () => {
let value = parseInt(sliderElement.property('value'));
if (value > 0) {
value -= 1;
}
sliderElement.property('value', value).dispatch('input');
});
this.selector.select('.nextButton').on('mousedown', () => {
let value = parseInt(sliderElement.property('value'));
if (value < this.frames.length - 1) {
value += 1;
}
sliderElement.property('value', value).dispatch('input');
//Create AnimationController
let ac = new AnimationController({
selector: '#backtrackingAC',
min: 0,
max: this.frames.length - 1,
renderer: (n) => this.loadFrame(n)
});
sliderElement.attr('max', this.frames.length - 1)
.property('value', 0)
.on('input', () => {
let frameIndex = parseInt(sliderElement.property('value'));
this.loadFrame(this.frames[frameIndex], frameIndex);
});
//Load the first frame
this.loadFrame(this.frames[0], 0);
ac.renderFirst();
}

addNewMap(assignment) {
Expand Down Expand Up @@ -268,7 +252,8 @@ class BacktrackingDiagram {
}

//Given a frame, load it into the diagram.
loadFrame(frame, frameIndex) {
loadFrame(frameIndex) {
let frame = this.frames[frameIndex];
this.selector.selectAll('.map').remove();
this.maps = [];
this.mapElements = [];
Expand Down
13 changes: 5 additions & 8 deletions 6-Constraint-Satisfaction-Problems/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<script src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.6.0/two.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
<script type="text/javascript" src="../globalHelpers.js"></script>
<script type="text/javascript" src="./AC3.js"></script>
<script type="text/javascript" src="./backtracking.js"></script>
<script type="text/javascript" src="./minConflicts.js"></script>
Expand Down Expand Up @@ -110,14 +111,10 @@ <h2>Backtracking Search</h2>
<div class='btn btn-primary restart-button'>Restart</div>
</div>
<div class="row animation-controls">
<div class="col-md-1">
<div class='btn btn-default prevButton'>Previous</div>
</div>
<div class="col-md-4">
<input class='slider' id='backtrackSlider' type="range" steps="1" min='0' value="0">
</div>
<div class="col-md-1">
<div class='btn btn-default nextButton'>Next</div>
<div class="col-md-6">
<div class="row" id='backtrackingAC'>

</div>
</div>
</div>
<div class="row">
Expand Down
Loading

0 comments on commit 09a6163

Please sign in to comment.