diff options
author | Lizzy Hunt <lizzy.hunt@usu.edu> | 2024-01-12 19:13:13 -0700 |
---|---|---|
committer | Lizzy Hunt <lizzy.hunt@usu.edu> | 2024-01-12 19:13:13 -0700 |
commit | 07670ef8afb5a273267ea7149d5f7eef02fdf66b (patch) | |
tree | 2d0c8e64936c7fa2588786f4af199abf1bb48a60 /maize-maze/js | |
parent | 3ac982dfa653f0eb7fbceeb1678a3cae93b512f4 (diff) | |
download | simponic.xyz-07670ef8afb5a273267ea7149d5f7eef02fdf66b.tar.gz simponic.xyz-07670ef8afb5a273267ea7149d5f7eef02fdf66b.zip |
add subprojects
Diffstat (limited to 'maize-maze/js')
-rw-r--r-- | maize-maze/js/assets.js | 8 | ||||
-rw-r--r-- | maize-maze/js/game.js | 249 | ||||
-rw-r--r-- | maize-maze/js/helpers.js | 18 | ||||
-rw-r--r-- | maize-maze/js/json-ds.js | 30 | ||||
-rw-r--r-- | maize-maze/js/keyboard.js | 22 | ||||
-rw-r--r-- | maize-maze/js/maze.js | 104 |
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); + } + } + } +} |