summaryrefslogtreecommitdiff
path: root/maize-maze/js
diff options
context:
space:
mode:
authorLizzy Hunt <lizzy.hunt@usu.edu>2024-01-12 19:13:13 -0700
committerLizzy Hunt <lizzy.hunt@usu.edu>2024-01-12 19:13:13 -0700
commit07670ef8afb5a273267ea7149d5f7eef02fdf66b (patch)
tree2d0c8e64936c7fa2588786f4af199abf1bb48a60 /maize-maze/js
parent3ac982dfa653f0eb7fbceeb1678a3cae93b512f4 (diff)
downloadsimponic.xyz-07670ef8afb5a273267ea7149d5f7eef02fdf66b.tar.gz
simponic.xyz-07670ef8afb5a273267ea7149d5f7eef02fdf66b.zip
add subprojects
Diffstat (limited to 'maize-maze/js')
-rw-r--r--maize-maze/js/assets.js8
-rw-r--r--maize-maze/js/game.js249
-rw-r--r--maize-maze/js/helpers.js18
-rw-r--r--maize-maze/js/json-ds.js30
-rw-r--r--maize-maze/js/keyboard.js22
-rw-r--r--maize-maze/js/maze.js104
6 files changed, 431 insertions, 0 deletions
diff --git a/maize-maze/js/assets.js b/maize-maze/js/assets.js
new file mode 100644
index 0000000..54ea6bb
--- /dev/null
+++ b/maize-maze/js/assets.js
@@ -0,0 +1,8 @@
+const GOAL = new Image();
+GOAL.src = "./images/fire.png";
+
+const PLAYER = new Image();
+PLAYER.src = "./images/corn.png";
+
+const BACKGROUND = new Image();
+BACKGROUND.src = "./images/popcorn.jpg";
diff --git a/maize-maze/js/game.js b/maize-maze/js/game.js
new file mode 100644
index 0000000..1249a20
--- /dev/null
+++ b/maize-maze/js/game.js
@@ -0,0 +1,249 @@
+let canvas,context;
+
+const HEIGHT = 1000;
+const WIDTH = 1000;
+
+// Next assignment: don't use so much effing global data
+let n = 10;
+let maze;
+
+let total_time;
+
+let player_pos = [];
+let goal_pos = [];
+
+let myInput = input.Keyboard();
+
+let show_player_path = false;
+let player_path = [];
+let show_next_move = false;
+let show_shortest_path = false;
+let shortest_path = [];
+
+let do_score_update = false;
+let scores = [];
+let initial_shortest_path_length = 0;
+let current_score;
+
+let do_time_update = false;
+let dom_time;
+let elapsed_time;
+let last_time;
+
+function render_maze(maze, n, dx, dy) {
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n; j++) {
+ context.beginPath();
+ if (maze[i][j].left) {
+ context.moveTo(j * dx, i * dy);
+ context.lineTo(j * dx, (i + 1) * dy);
+ }
+ if (maze[i][j].right) {
+ context.moveTo((j + 1) * dx, i * dy);
+ context.lineTo((j + 1) * dx, (i + 1) * dy);
+ }
+ if (maze[i][j].top) {
+ context.moveTo(j * dx, i * dy);
+ context.lineTo((j + 1) * dx, i * dy);
+ }
+ if (maze[i][j].bottom) {
+ context.moveTo(j * dx, (i + 1) * dy);
+ context.lineTo((j + 1) * dx, (i + 1) * dy);
+ }
+ context.stroke();
+ }
+ }
+}
+
+function render_player(x, y, dx, dy) {
+ context.drawImage(PLAYER, x*dx, y*dy, dx, dy);
+}
+
+function render_scores(scores) {
+ let html = scores.sort((a,b) => a-b).map((x,i) => `${i+1}: ${x}`).join('<br>');
+ document.getElementById('scores').innerHTML = html;
+}
+
+function render_time(total_time) {
+ document.getElementById('elapsed-time').innerHTML = total_time;
+}
+
+function render_goal(x, y, dx, dy) {
+ context.drawImage(GOAL, x*dx, y*dy, dx, dy);
+}
+
+function render_background(n, dx, dy) {
+ for (let x = 0; x < WIDTH; x += WIDTH/n) {
+ for (let y = 0; y < HEIGHT; y += HEIGHT/n) {
+ context.drawImage(BACKGROUND, x, y, dx, dy);
+ }
+ }
+}
+
+function render_circle(x,y,r,color) {
+ context.beginPath();
+ context.fillStyle = color;
+ context.arc(x, y, r, 0, 2*Math.PI);
+ context.fill();
+ context.stroke();
+}
+
+function render_path(path, dx, dy, color) {
+ path.map((coord) => {
+ render_circle(coord[0]*dx + dx/2, coord[1]*dy + dy/2, Math.min(dx/4, dy/4), color);
+ });
+}
+
+function render(elapsed) {
+ const dx = WIDTH / n;
+ const dy = HEIGHT / n;
+
+ context.fillStyle = 'rgba(255,255,255,255)';
+ context.fillRect(0, 0, canvas.width, canvas.height);
+ context.rect(0, 0, canvas.width, canvas.height);
+ context.stroke();
+
+ render_background(n, dx, dy);
+ render_maze(maze, n, dx, dy);
+
+ if (show_player_path) {
+ render_path(player_path, dx, dy, 'rgba(255, 0, 0, 255)');
+ }
+
+ if (show_shortest_path) {
+ render_path(shortest_path, dx, dy, 'rgba(255, 255, 0, 255)');
+ }
+
+ if (show_next_move && shortest_path.length>1) {
+ render_path([shortest_path[1]], dx, dy, 'rgba(255, 255, 0, 255)');
+ }
+
+ if (do_score_update) {
+ render_scores(scores);
+ }
+ if (do_time_update) {
+ render_time(dom_time);
+ }
+
+ render_player(Math.floor(player_pos[0]), Math.floor(player_pos[1]), dx, dy);
+ render_goal(goal_pos[0], goal_pos[1], dx, dy);
+}
+
+let key_actions_down = {};
+let key_actions = {
+ "move_up": ['ArrowUp', 'i', 'w'],
+ "move_right": ['ArrowRight', 'l', 'd'],
+ "move_down": ['ArrowDown', 'k', 's'],
+ "move_left": ['ArrowLeft', 'j', 'a'],
+ "breadcrumbs": ['b'],
+ "shortest_path": ['p'],
+ "hint": ['h']
+};
+function handle_input(input) {
+ if (input) {
+ if (any(key_actions['move_up'].map((x) => input.keys[x])) && !key_actions_down['move_up'] && player_pos[1] > 0) {
+ key_actions_down['move_up'] = true;
+ if (!maze[player_pos[1]][player_pos[0]].top) {
+ player_pos[1] -= 1;
+ }
+ }
+ if (any(key_actions['move_right'].map((x) => input.keys[x])) && !key_actions_down['move_right'] && player_pos[0] < n-1) {
+ key_actions_down['move_right'] = true;
+ if (!maze[player_pos[1]][player_pos[0]].right) {
+ player_pos[0] += 1;
+ }
+ }
+ if (any(key_actions['move_down'].map((x) => input.keys[x])) && !key_actions_down['move_down'] && player_pos[1] < n-1) {
+ key_actions_down['move_down'] = true;
+ if (!maze[player_pos[1]][player_pos[0]].bottom) {
+ player_pos[1] += 1;
+ }
+ }
+ if (any(key_actions['move_left'].map((x) => input.keys[x])) && !key_actions_down['move_left'] && player_pos[0] > 0) {
+ key_actions_down['move_left'] = true;
+ if (!maze[player_pos[1]][player_pos[0]].left) {
+ player_pos[0] -= 1;
+ }
+ }
+ if (input.keys['b'] && !key_actions_down['breadcrumbs']) {
+ key_actions_down['breadcrumbs'] = true;
+ show_player_path = !show_player_path;
+ }
+ if (input.keys['p'] && !key_actions_down['shortest_path']) {
+ key_actions_down['shortest_path'] = true;
+ show_shortest_path = !show_shortest_path;
+ }
+ if (input.keys['h'] && !key_actions_down['hint']) {
+ key_actions_down['hint'] = true;
+ show_next_move = !show_next_move;
+ }
+ Object.keys(key_actions).map((x) => {
+ if (key_actions_down[x] && !any(key_actions[x].map((y) => input.keys[y]))) {
+ key_actions_down[x] = false;
+ }
+ });
+ }
+}
+
+function update(elapsed) {
+ total_time += elapsed;
+
+ if (do_score_update) {
+ do_score_update = false;
+ }
+ if (do_time_update) {
+ do_time_update = false;
+ }
+
+ if (JSON.stringify(player_pos) !== JSON.stringify(player_path[player_path.length-1])) {
+ player_path.push([player_pos[0], player_pos[1]]);
+ shortest_path = solve_maze(maze, player_pos[0], player_pos[1], goal_pos[0], goal_pos[1]);
+ }
+
+ if (total_time / 1000 > dom_time) {
+ dom_time = Math.floor(total_time/1000);
+ }
+ do_time_update = true;
+
+ if (player_pos[0] == goal_pos[0] && player_pos[1] == goal_pos[1]) {
+ current_score = player_path.length - initial_shortest_path_length;
+ scores.push(current_score);
+ initialize();
+ do_score_update = true;
+ }
+}
+
+function initialize(new_n) {
+ if (new_n) {
+ n = new_n;
+ }
+ maze = generate_maze(n);
+ player_pos = [random_in_range(0, 2), random_in_range(0, 2)];
+ goal_pos = [random_in_range(n-2, n), random_in_range(n-2, n)];
+ player_path = [];
+ shortest_path = solve_maze(maze, player_pos[0], player_pos[1], goal_pos[0], goal_pos[1]);
+ initial_shortest_path_length = shortest_path.length;
+ total_time = 0;
+ current_score = 0;
+ dom_time = 0;
+ last_time = performance.now();
+}
+
+function game_loop(time_stamp) {
+ elapsed_time = time_stamp - last_time;
+ last_time = time_stamp;
+ handle_input(myInput);
+ update(elapsed_time);
+ render(elapsed_time);
+
+ // Wow! Tail call recursion! /sarcasm
+ requestAnimationFrame(game_loop);
+}
+
+window.onload = function() {
+ initialize();
+ canvas = document.getElementById('canvas');
+ context = canvas.getContext('2d');
+
+ game_loop(performance.now());
+}
diff --git a/maize-maze/js/helpers.js b/maize-maze/js/helpers.js
new file mode 100644
index 0000000..1bc6579
--- /dev/null
+++ b/maize-maze/js/helpers.js
@@ -0,0 +1,18 @@
+function random_in_range(a,z) {
+ return Math.floor(Math.random() * (z - a) + a);
+}
+
+function shuffle_array(a) {
+ for (let i = 0; i < a.length; i++) {
+ let j = random_in_range(0, i+1);
+ temp = a[i]; a[i] = a[j]; a[j] = temp;
+ }
+}
+
+function sub(p1, p2) {
+ return [p1[0] - p2[0], p1[1] - p2[1]];
+}
+
+function any(l) {
+ return l.filter((x) => x).length > 0;
+} \ No newline at end of file
diff --git a/maize-maze/js/json-ds.js b/maize-maze/js/json-ds.js
new file mode 100644
index 0000000..feb0622
--- /dev/null
+++ b/maize-maze/js/json-ds.js
@@ -0,0 +1,30 @@
+// If I were to rewrite this, I would use IEFE's - Dean was right about OO in JS
+class JSONSet {
+ items = new Set();
+ constructor(initial){
+ if (initial) {
+ this.apply_set_function('add', initial);
+ }
+ }
+ apply_set_function(f_name, x) {
+ return this.items[f_name](JSON.stringify(x));
+ }
+}
+
+class JSONHash {
+ items = {};
+ constructor(initial_key, initial_value){
+ if (initial_key && initial_value) {
+ this.items[JSON.stringify(initial)] = initial_value;
+ }
+ }
+ set_value(key, value) {
+ this.items[JSON.stringify(key)] = value;
+ }
+ get_value(key) {
+ return this.items[JSON.stringify(key)];
+ }
+ delete_value(key) {
+ delete this.items[JSON.stringify(key)];
+ }
+} \ No newline at end of file
diff --git a/maize-maze/js/keyboard.js b/maize-maze/js/keyboard.js
new file mode 100644
index 0000000..2196834
--- /dev/null
+++ b/maize-maze/js/keyboard.js
@@ -0,0 +1,22 @@
+// Shameless stolen code from "Process the Input" presentation
+let input = (function() {
+ function Keyboard() {
+ let that = {
+ keys : {}
+ };
+ function keyPress(e) {
+ that.keys[e.key] = e.timeStamp;
+ }
+ function keyRelease(e) {
+ delete that.keys[e.key];
+ }
+ window.addEventListener('keydown', keyPress);
+ window.addEventListener('keyup', keyRelease);
+
+ return that;
+ }
+
+ return {
+ Keyboard : Keyboard
+ };
+}()); \ No newline at end of file
diff --git a/maize-maze/js/maze.js b/maize-maze/js/maze.js
new file mode 100644
index 0000000..8bede6b
--- /dev/null
+++ b/maize-maze/js/maze.js
@@ -0,0 +1,104 @@
+function get_neighbors(maze, x, y) {
+ let neighbor_indices = [];
+ if (!maze[y][x].left && x > 0) {
+ neighbor_indices.push([x-1,y]);
+ }
+ if (!maze[y][x].right && x < maze[0].length-1) {
+ neighbor_indices.push([x+1,y]);
+ }
+ if (!maze[y][x].top && y > 0) {
+ neighbor_indices.push([x,y-1]);
+ }
+ if (!maze[y][x].bottom && y < maze.length-1) {
+ neighbor_indices.push([x,y+1]);
+ }
+ return neighbor_indices;
+}
+
+function new_cell() {
+ return {
+ left: false,
+ right: false,
+ top: false,
+ bottom: false
+ }
+}
+
+function generate_maze(n) {
+ let grid = new Array(n).fill().map((x) => (new Array(n).fill().map(new_cell)));
+
+ let point_sets = [];
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n; j++) {
+ point_sets.push(new JSONSet([j,i]))
+ }
+ }
+
+ let edges = [];
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n; j++) {
+ if (i !== n-1) {
+ edges.push([[i,j],[i+1,j]])
+ }
+ if (j !== n-1) {
+ edges.push([[i,j],[i,j+1]])
+ }
+ }
+ }
+ shuffle_array(edges);
+
+ let maze_edges = edges.map((x) => x);
+
+ while (edges.length) {
+ let edge = edges.pop();
+
+ let set_inds = edge.map((i) => point_sets.findIndex((x) => x.apply_set_function('has', i)));
+ if (set_inds[0] == -1 || set_inds[1] == -1) {
+ throw new Error("Could not find correct index");
+ }
+ if (set_inds[0] == set_inds[1]) {
+ continue;
+ }
+
+ // Perform the union of the sets
+ for (let i of point_sets[set_inds[1]].items) {
+ point_sets[set_inds[0]].items.add(i);
+ }
+
+ point_sets.splice(set_inds[1], 1);
+ maze_edges = maze_edges.filter((x) => x !== edge);
+ }
+ maze_edges.forEach((edge) => {
+ let direction = sub(edge[0], edge[1]);
+ if (direction[0] == -1) {
+ grid[edge[0][1]][edge[0][0]].right = grid[edge[1][1]][edge[1][0]].left = true;
+ }
+ else if (direction[1] == -1) {
+ grid[edge[0][1]][edge[0][0]].bottom = grid[edge[1][1]][edge[1][0]].top = true;
+ }
+ })
+ return grid;
+}
+
+function solve_maze(maze, x, y, end_x, end_y) {
+ let path = new JSONHash();
+ let visited = new JSONSet();
+ let queue = [[x,y]];
+ while (queue.length) {
+ let cell = queue.shift();
+ visited.apply_set_function('add', cell);
+ if (cell[0] == end_x && cell[1] == end_y) {
+ let sol_path = [[end_x, end_y]];
+ while (sol_path[0][0] != x || sol_path[0][1] != y) {
+ sol_path.unshift(path.get_value(sol_path[0]));
+ }
+ return sol_path;
+ }
+ for (let i of get_neighbors(maze, cell[0], cell[1])) {
+ if (!visited.apply_set_function('has', i)) {
+ queue.push(i);
+ path.set_value(i, cell);
+ }
+ }
+ }
+}