Skip to content

Commit 5e4354e

Browse files
Rishav159redblobgames
authored andcommitted
Add visualization for ch 3 - depth limited search and iterative deepening search
1 parent 27002ec commit 5e4354e

11 files changed

+417
-158
lines changed

3-Solving-Problems-By-Searching/c_costDetails.js

+29-23
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,36 @@ $(document).ready(function() {
66
ucsPathCanvas = null;
77
var bfsTwo = null,
88
ucsTwo = null;
9+
//function to color the given path in the graph in the front end
910
var colorPathInGraph = function(graphDrawAgent, path) {
10-
let nodeGroups = graphDrawAgent.nodeGroups;
11-
for (var i = 0; i < path.path.length; i++) {
12-
nodeKey = path.path[i].node;;
13-
for (var j = 0; j < nodeGroups.length; j++) {
14-
if ($(nodeGroups[j]._renderer.elem).attr('nodeKey') == nodeKey) {
15-
nodeGroups[j]._collection[0].fill = 'hsl(108, 96%, 80%)';
16-
break;
11+
let nodeGroups = graphDrawAgent.nodeGroups;
12+
for (var i = 0; i < path.path.length; i++) {
13+
nodeKey = path.path[i].node;;
14+
for (var j = 0; j < nodeGroups.length; j++) {
15+
if ($(nodeGroups[j]._renderer.elem).attr('nodeKey') == nodeKey) {
16+
nodeGroups[j]._collection[0].fill = 'hsl(108, 96%, 80%)';
17+
break;
18+
}
1719
}
1820
}
19-
}
20-
let edges = graphDrawAgent.edges;
21-
for (var i = 0; i < path.path.length - 1; i++) {
22-
nodeKey1 = path.path[i].node;
23-
nodeKey2 = path.path[i + 1].node;
24-
for (var j = 0; j < edges.length; j++) {
25-
let edge = edges[j];
26-
let fnode1 = $(edge._renderer.elem).attr("node1");
27-
let fnode2 = $(edge._renderer.elem).attr("node2");
28-
if ((fnode1 == nodeKey1 && fnode2 == nodeKey2) || (fnode2 == nodeKey1 && fnode1 == nodeKey2)) {
29-
edge.stroke = 'hsla(202, 100%, 56%, 1)';
30-
edge.linewidth = 5;
21+
let edges = graphDrawAgent.edges;
22+
for (var i = 0; i < path.path.length - 1; i++) {
23+
nodeKey1 = path.path[i].node;
24+
nodeKey2 = path.path[i + 1].node;
25+
for (var j = 0; j < edges.length; j++) {
26+
let edge = edges[j];
27+
let fnode1 = $(edge._renderer.elem).attr("node1");
28+
let fnode2 = $(edge._renderer.elem).attr("node2");
29+
if ((fnode1 == nodeKey1 && fnode2 == nodeKey2) || (fnode2 == nodeKey1 && fnode1 == nodeKey2)) {
30+
edge.stroke = 'hsla(202, 100%, 56%, 1)';
31+
edge.linewidth = 5;
32+
}
3133
}
3234
}
33-
}
34-
graphDrawAgent.two.update();
35-
36-
}
35+
graphDrawAgent.two.update();
3736

37+
}
38+
//Function to draw the cost path in the bottom of the graph
3839
var drawCostPath = function(two, path) {
3940
two.clear();
4041
path.path = path.path.reverse();
@@ -85,21 +86,26 @@ $(document).ready(function() {
8586

8687
var onMouseEnter = function() {
8788
let nodeKey = $(this).attr('nodeKey');
89+
//Find the shortest paths from the inital node to the node being hovered
8890
bfsShortestPath = findShortestPath(breadthFirstSearch, nodeKey);
8991
ucsShortestPath = findShortestPath(uniformCostSearch, nodeKey);
92+
//Color those paths in the graph
9093
colorPathInGraph(bfsGraphDrawAgent, bfsShortestPath);
9194
colorPathInGraph(ucsGraphDrawAgent, ucsShortestPath);
95+
//Draw the cost path at the bottom
9296
drawCostPath(bfsTwo, bfsShortestPath);
9397
drawCostPath(ucsTwo, ucsShortestPath);
9498
};
9599
var onMouseLeave = function() {
100+
//Clear everything when mouse leaves
96101
bfsGraphDrawAgent.iterate();
97102
ucsGraphDrawAgent.iterate();
98103
bfsTwo.clear();
99104
ucsTwo.clear();
100105
bfsTwo.update();
101106
ucsTwo.update();
102107
};
108+
//Attach the events to all kind of nodes (unexplored,explored and frontier)
103109
options.nodes.unexplored.onMouseEnter = onMouseEnter;
104110
options.nodes.explored.onMouseEnter = onMouseEnter;
105111
options.nodes.frontier.onMouseEnter = onMouseEnter;

3-Solving-Problems-By-Searching/c_depthFirstSearch.js

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ $(document).ready(function() {
1717
if (graphProblem.frontier.length > 0) {
1818
var nextNode = depthFirstSearch(graphProblem);
1919
graphAgent.expand(nextNode);
20+
//If frontier is still present, find the next node to be expanded so it
21+
//could be colored differently
2022
if (graphProblem.frontier.length > 0) {
2123
graphProblem.nextToExpand = depthFirstSearch(graphProblem);
2224
} else {
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
$(document).ready(function() {
2-
$.ajax({
3-
url: "depthLimitedSearch.js",
4-
dataType: "text",
5-
success: function(data) {
6-
$("#depthLimitedSearchCode").html(data);
7-
}
2+
3+
var agent = null;
4+
5+
function init() {
6+
agent = new dlsDrawAgent('depthLimitedSearchCanvas');
7+
//Restart the simulation when limit is changed
8+
$('#limitSelector').on('input', function() {
9+
let limit = $(this).val();
10+
agent.iterate(limit);
11+
});
12+
//Draws graph for the first time
13+
agent.iterate($('#limitSelector').val());
14+
}
15+
16+
17+
$('#dlsExpanded').css('background-color', 'hsl(0,50%,75%)');
18+
$('#dlsFrontier').css('background-color', 'hsl(200,50%,70%)');
19+
$('#dlsUnexplored').css('background-color', 'hsl(0, 2%, 76%)');
20+
init();
21+
$('#limitSelector').on('input change', function() {
22+
$('#limitSelectorText').text($(this).val());
823
});
924
});
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,40 @@
11
$(document).ready(function() {
2-
$.ajax({
3-
url: "iterativeDeepening.js",
4-
dataType: "text",
5-
success: function(data) {
6-
$("#iterativeDeepeningCode").html(data);
7-
}
2+
var DELAY = 2000;
3+
var intervalFunction = null;
4+
5+
//Restart the simulation when limit is changed
6+
function init() {
7+
agent = new dlsDrawAgent('iterativeDeepeningCanvas');
8+
//Restart the simulation when limit is changed
9+
$('#idlimitSelector').change(function() {
10+
let limit = $(this).val();
11+
agent.iterate(limit);
12+
});
13+
//Draws graph for the first time
14+
agent.iterate($('#idlimitSelector').val());
15+
16+
intervalFunction = setInterval(function() {
17+
let limit = parseInt($('#idlimitSelector').val());
18+
if (limit <= 4) {
19+
$('#idlimitSelector').val(limit + 1);
20+
$('#idlimitSelector').trigger('change');
21+
} else {
22+
clearInterval(intervalFunction, DELAY);
23+
}
24+
}, DELAY)
25+
}
26+
27+
$('#idExpanded').css('background-color', 'hsl(0,50%,75%)');
28+
$('#idFrontier').css('background-color', 'hsl(200,50%,70%)');
29+
$('#idUnexplored').css('background-color', 'hsl(0, 2%, 76%)');
30+
$('#idRestartButton').click(function() {
31+
clearInterval(intervalFunction);
32+
$('#idlimitSelector').val(0);
33+
$('#idlimitSelector').trigger('change');
34+
init();
35+
});
36+
init();
37+
$('#idlimitSelector').on('input change', function() {
38+
$('#idlimitSelectorText').text($(this).val());
839
});
940
});

3-Solving-Problems-By-Searching/c_nodeExpansion.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ $(document).ready(function() {
99
var graphAgent = new GraphAgent(graphProblem);
1010
var frontierNodesAgent = new DrawFrontierAgent('frontierCanvas', 150, 250, graphProblem);
1111
var options = new DefaultOptions();
12+
//Function to execute whenever a node is clicked
1213
var clickHandler = function() {
14+
//Find out which node has been clicked
1315
let nodeKey = $(this).attr('nodeKey');
16+
//Expand it
1417
graphAgent.expand(nodeKey);
1518
graphDrawAgent.iterate();
1619
frontierNodesAgent.iterate();
@@ -35,6 +38,7 @@ $(document).ready(function() {
3538
var graphProblem = new GraphProblem(graph.nodes, graph.edges, String.fromCharCode(65 + Math.random() * 15), null);
3639
var graphAgent = new GraphAgent(graphProblem);
3740
var options = new DefaultOptions();
41+
//For this simulation, unexplored nodes and edges needs to be invisible
3842
options.nodes.unexplored.opacity = 0;
3943
options.edges.unvisited.opacity = 0;
4044
var clickHandler = function() {
@@ -55,7 +59,7 @@ $(document).ready(function() {
5559
});
5660

5761

58-
62+
//Function to draw the frontier nodes
5963
function DrawFrontierAgent(selector, h, w, problem) {
6064
this.canvas = document.getElementById(selector);
6165
this.canvas.innerHTML = '';

3-Solving-Problems-By-Searching/c_uniformCostSearch.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ $(document).ready(function() {
1818
height: h,
1919
width: w
2020
}).appendTo(exploredQueueCanvas);
21+
//Intial value for separation is 0
2122
$('.ucsSeparation').html(0);
2223
var graph = new DefaultGraph();
24+
//Precompute costs of all nodes from the initial node
2325
var costMap = precomputedCosts();
2426
var graphProblem = new GraphProblem(graph.nodes, graph.edges, 'A', 'A');
27+
//Change the text of all the nodes to its cost
2528
for (key in graphProblem.nodes) {
2629
graphProblem.nodes[key].text = costMap[graphProblem.nodes[key].id];
2730
}
28-
var graphAgent = new GraphAgent(graphProblem);
31+
var graphAgent = new GraphAgent(graphProblem, 'ucs');
2932
var options = new DefaultOptions();
3033
options.nodes.next.fill = 'hsla(126, 100%, 69%, 1)';
3134
options.edges.showCost = true;
@@ -45,9 +48,11 @@ $(document).ready(function() {
4548
drawList(priorityTwo, graphProblem.frontier, graphProblem, options, costMap);
4649
drawList(exploredTwo, graphProblem.explored, graphProblem, options, costMap);
4750
let maxCost = 0;
51+
//Find the max cost which separates the explored from frontier nodes
4852
if (graphProblem.nextToExpand) {
4953
maxCost = graphProblem.nodes[graphProblem.nextToExpand].cost;
5054
}
55+
//Draw it in the front end
5156
$('.ucsSeparation').html(maxCost);
5257
} else {
5358
clearInterval(intervalFunction, DELAY);
@@ -61,7 +66,7 @@ $(document).ready(function() {
6166
$('#ucsExploredNode').css('background-color', 'hsl(0,50%,75%)');
6267
init();
6368
});
64-
69+
//Function to draw the list of nodes for both canvas
6570
function drawList(two, list, problem, options, costMap) {
6671
two.clear();
6772
for (var i = 0; i < list.length; i++) {

3-Solving-Problems-By-Searching/costDetails.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ var findShortestPath = function(nextNodeFunction, final) {
55
}
66
let graph = new DefaultGraph();
77
problem = new GraphProblem(graph.nodes, graph.edges, 'A', null);
8-
let agent = new GraphAgent(problem);
8+
//Make a new problem fromt the graph and solve it using the given nextNodeFunction
9+
let agent = new GraphAgent(problem, 'ucs');
910
while (problem.frontier.length > 0) {
1011
let next = nextNodeFunction(problem);
1112
agent.expand(next);
13+
//Exit if final node reached
1214
if (next == final) {
1315
break;
1416
}
1517
}
1618
shortestPath.cost = problem.nodes[final].cost;
1719
var current = final;
18-
20+
//Iterate from the final to initial node using parent property to find the path
1921
while (current != problem.initialKey) {
2022
let prev = problem.nodes[current].parent;
2123
currentCost = problem.nodes[current].cost - problem.nodes[prev].cost;
@@ -25,6 +27,7 @@ var findShortestPath = function(nextNodeFunction, final) {
2527
});
2628
current = prev;
2729
}
30+
//Push the initial node to the path array
2831
shortestPath.path.push({
2932
node: problem.initialKey,
3033
cost: 0
Original file line numberDiff line numberDiff line change
@@ -1 +1,49 @@
1-
// Code for Depth Limited Search
1+
// Same as depht first search but with limit
2+
var depthLimitedSearch = function(problem, limit) {
3+
// Traverse the frontier queue from behind and choose the deepest node
4+
// whose depth is lower than the limit
5+
for (var i = problem.frontier.length - 1; i >= 0; i--) {
6+
let nextNodeKey = problem.frontier[i];
7+
if (problem.nodes[nextNodeKey].depth <= limit) {
8+
return nextNodeKey;
9+
}
10+
}
11+
//If no such node found, return null to denote traversal should stop
12+
return null;
13+
}
14+
//New Graph for DLS to behave as a tree
15+
var DLSGraph = function() {
16+
this.nodes = {
17+
'A': new GraphNode(20, 170, 'A', 'A'),
18+
'B': new GraphNode(100, 120, 'B', 'B'),
19+
'C': new GraphNode(100, 220, 'C', 'C'),
20+
'D': new GraphNode(180, 80, 'D', 'D'),
21+
'E': new GraphNode(180, 150, 'E', 'E'),
22+
'F': new GraphNode(180, 190, 'F', 'F'),
23+
'G': new GraphNode(180, 270, 'G', 'G'),
24+
'H': new GraphNode(260, 40, 'H', 'H'),
25+
'I': new GraphNode(260, 120, 'I', 'I'),
26+
'J': new GraphNode(260, 165, 'J', 'J'),
27+
'K': new GraphNode(260, 210, 'K', 'K'),
28+
'L': new GraphNode(260, 260, 'L', 'L'),
29+
'M': new GraphNode(340, 170, 'M', 'M'),
30+
'N': new GraphNode(340, 250, 'N', 'N'),
31+
'O': new GraphNode(420, 300, 'O', 'O')
32+
};
33+
this.edges = [
34+
['A', 'B', 3],
35+
['A', 'C', 6],
36+
['B', 'D', 2],
37+
['B', 'E', 2],
38+
['C', 'F', 2],
39+
['C', 'G', 2],
40+
['D', 'H', 2],
41+
['D', 'I', 2],
42+
['E', 'J', 2],
43+
['F', 'K', 2],
44+
['F', 'L', 2],
45+
['K', 'M', 2],
46+
['K', 'N', 2],
47+
['N', 'O', 2]
48+
];
49+
};

0 commit comments

Comments
 (0)