-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.js
231 lines (194 loc) · 7.45 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
// There are a lot of side effects here, but I swear to the old gods and the new that
// if I have to spend one more minute trying to make JavaScript both readable and
// functionally sound, I'm going to fucking scream.
// Global constants
const FONT_SIZE = 10;
const SEARCH_HEAD_LENGTH = 25;
const SEARCH_HEAD_WIDTH = 10;
// Generate data
let numNumbers = 30;
var numArray = generateData(numNumbers);
var target = chooseTarget(numArray);
// Visualize everything immediately - don't wait for a button press here.
let l, b;
init();
// Bind the reset button
document.getElementById('reset').addEventListener("click", function () {
reset();
resetSearchInfo();
});
// Also with user input
document.getElementById('resetWithInput').addEventListener("click", function () {
resetWithInput();
resetSearchInfo();
});
// Bind the reset button
document.getElementById('numRandomNumbersField').addEventListener("keypress", function(e) {
if (e.keyCode == 13) {
console.log(e.keyCode);
reset();
resetSearchInfo();
}
});
// Also with user input
document.getElementById('userInput').addEventListener("keypress", function(e) {
if (e.keyCode == 13) {
console.log(e.keyCode);
resetWithInput();
resetSearchInfo();
}
});
// Builds the entire sketch object for the linear search visualization.
// Returns a sketch object used for creating new p5 objects.
function buildLinearSearchSketch () {
let linearSearch = function (p) {
// So both setup and draw can access it:
let search = null;
// Is run once when the p5.js sketch is started
p.setup = function() {
// Save height and width for later positioning
let cnv = document.getElementById('linearCanvas');
this.width = cnv.offsetWidth;
this.height = cnv.offsetHeight;
//Configure p5
p.textSize(FONT_SIZE);
p.createCanvas(this.width, this.height);
// Establish visualization for linear search
search = new VisualLinearSearch(p, numArray);
search.startSearchFor(target);
// Bind step function to button clicks
let button = document.getElementById('stepLinear');
let stepCountField = document.getElementById('stepCountLinear');
let numExcludedNodesField = document.getElementById('exclusionCounterLinear');
button.onclick = function () {
search.step();
stepCountField.innerHTML = "Number of steps: " + search.numSteps;
numExcludedNodesField.innerHTML = 'Number of excluded nodes: ' + search.numExcludedNodes;
}
}
// Is run once every frame
p.draw = function () {
p.background(250, 235, 215);
search.show();
}
}
return linearSearch;
}
// Builds the entire sketch object for the binary search visualization.
// Returns a sketch object used for creating new p5 objects.
function buildBinarySearchSketch () {
let binarySearch = function (p) {
// So both setup and draw can access it
let binary = null;
// Run once when the sketch is started
p.setup = function () {
// Save height and width for later positioning
let cnv = document.getElementById('binaryCanvas');
this.width = cnv.offsetWidth;
this.height = cnv.offsetHeight;
//Configure p5
p.textSize(FONT_SIZE);
p.createCanvas(this.width, this.height);
// Can you believe that I had to tell it what comparing function
// it should use to sort an array of numbers. Fuck javascript.
let sorted = numArray.sort(function(a,b){return a - b});
binary = new VisualBinarySearch(p, sorted, this.width * 0.5, 50);
binary.startSearchFor(target);
// Bind button to step function
let button = document.getElementById('stepBinary');
let numStepsField = document.getElementById('stepCountBinary');
let numExcludedNodesField = document.getElementById('exclusionCounterBinary');
button.onclick = function () {
binary.step();
numStepsField.innerHTML = 'Number of steps: ' + binary.numSteps;
numExcludedNodesField.innerHTML = 'Number of excluded nodes: ' + binary.numExcludedNodes;
}
}
// Run once every frame
p.draw = function () {
p.background(255, 228, 196);
binary.show();
}
}
return binarySearch;
}
//UTILITY
//Unique random numbers between 0 and 100
function generateData(numData) {
let arr = []
while(arr.length < numData){
let randomnumber = Math.floor(Math.random()*100);
if(arr.indexOf(randomnumber) > -1) continue;
arr[arr.length] = randomnumber;
}
return arr;
}
function chooseTarget(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
// Hard reset with random data
function reset() {
// Remove the sketches
l.remove();
b.remove();
// Read the number of numbers to generate:
let num = document.getElementById('numRandomNumbersField').value;
let isValid = /^[0-9]*$/.test(num);
if (!isValid) {
// TODO: Show some error message here.
}
numNumbers = parseInt(num);
// Regenerate data
numArray = generateData(numNumbers);
target = chooseTarget(numArray);
// Regenerate the sketches
l = new p5(buildLinearSearchSketch(), 'linearCanvas');
b = new p5(buildBinarySearchSketch(), 'binaryCanvas');
}
// Sets it all up when the site loads
function init() {
numArray = generateData(numNumbers);
target = chooseTarget(numArray);
l = new p5(buildLinearSearchSketch(), 'linearCanvas');
b = new p5(buildBinarySearchSketch(), 'binaryCanvas');
}
// Reset but with user input instead of random data.
function resetWithInput() {
debugger
// Remove the sketches
l.remove();
b.remove();
// Get the user input
let input = document.getElementById('userInput').value;
let errorField = document.getElementById('inputErrorMessageField');
errorField.style.visibility = 'hidden';
// Clean the input, alert user if they messed up
let isValid = /^[0-9,\s]*$/.test(input);
if (!isValid) {
errorField.innerHTML = "Please enter only integers separated by commas.</br> Example input:</br> 4, 8, 15, 16, 23, 42";
errorField.style.visibility = 'visible';
console.log('getting the fuck out');
return;
}
// Remove whitespace
input = input.replace(/\s/g, '');
let numbersAsStrings = input.split(',');
// Parse into actual integers
let numbers = [];
numbersAsStrings.forEach(number => {
numbers.push(parseInt(number));
});
// yay side-effects
numArray = numbers;
target = chooseTarget(numArray);
// Regenerate the sketches
l = new p5(buildLinearSearchSketch(), 'linearCanvas');
b = new p5(buildBinarySearchSketch(), 'binaryCanvas');
}
/* Reset number of excluded nodes and number of steps to 0 for all visualizations */
function resetSearchInfo() {
document.getElementById('stepCountBinary').innerHTML = "Number of steps: 0";
document.getElementById('exclusionCounterBinary').innerHTML = "Number of exluded nodes: 0";
document.getElementById('stepCountBinary').innerHTML = "Number of steps: 0";
document.getElementById('exclusionCounterBinary').innerHTML = "Number of excluded nodes: 0";
}