summaryrefslogtreecommitdiff
path: root/Homework/cs5410
diff options
context:
space:
mode:
Diffstat (limited to 'Homework/cs5410')
-rw-r--r--Homework/cs5410/bbiy/README.md20
-rw-r--r--Homework/cs5410/bbiy/assets/image/background.gifbin0 -> 1468046 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/bigblue.pngbin0 -> 1489 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/flag.pngbin0 -> 985 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/floor.pngbin0 -> 1296 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/grass.pngbin0 -> 1090 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/hedge.pngbin0 -> 14592 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/lava.pngbin0 -> 409 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/rock.pngbin0 -> 1288 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wall.pngbin0 -> 1283 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/water.pngbin0 -> 436 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordBigBlue.pngbin0 -> 1083 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordFlag.pngbin0 -> 509 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordIs.pngbin0 -> 490 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordKill.pngbin0 -> 1042 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordLava.pngbin0 -> 492 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordPush.pngbin0 -> 483 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordRock.pngbin0 -> 517 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordSink.pngbin0 -> 499 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordStop.pngbin0 -> 490 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordWall.pngbin0 -> 556 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordWater.pngbin0 -> 506 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordWin.pngbin0 -> 455 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/image/wordYou.pngbin0 -> 448 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/sound/death.mp3bin0 -> 7321 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/sound/move.mp3bin0 -> 1845 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/sound/music.mp3bin0 -> 2696840 bytes
-rw-r--r--Homework/cs5410/bbiy/assets/sound/win.mp3bin0 -> 8678 bytes
-rw-r--r--Homework/cs5410/bbiy/index.html47
-rw-r--r--Homework/cs5410/bbiy/index.js55
-rw-r--r--Homework/cs5410/bbiy/levels-all.bbiy252
-rw-r--r--Homework/cs5410/bbiy/package-lock.json876
-rw-r--r--Homework/cs5410/bbiy/package.json15
-rw-r--r--Homework/cs5410/bbiy/src/bootstrap.js117
-rw-r--r--Homework/cs5410/bbiy/src/components/alive.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/appearence.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/burn.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/burnable.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/component.js8
-rw-r--r--Homework/cs5410/bbiy/src/components/controllable.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/gridPosition.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/loadPriority.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/momentum.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/name.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/noun.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/particles.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/position.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/pushable.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/sink.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/sinkable.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/sprite.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/stop.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/verb.js1
-rw-r--r--Homework/cs5410/bbiy/src/components/win.js1
-rw-r--r--Homework/cs5410/bbiy/src/entities/bigblue.js13
-rw-r--r--Homework/cs5410/bbiy/src/entities/borderParticles.js41
-rw-r--r--Homework/cs5410/bbiy/src/entities/entity.js23
-rw-r--r--Homework/cs5410/bbiy/src/entities/flag.js12
-rw-r--r--Homework/cs5410/bbiy/src/entities/floor.js8
-rw-r--r--Homework/cs5410/bbiy/src/entities/grass.js8
-rw-r--r--Homework/cs5410/bbiy/src/entities/hedge.js9
-rw-r--r--Homework/cs5410/bbiy/src/entities/lava.js9
-rw-r--r--Homework/cs5410/bbiy/src/entities/rock.js14
-rw-r--r--Homework/cs5410/bbiy/src/entities/wall.js13
-rw-r--r--Homework/cs5410/bbiy/src/entities/water.js9
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordBigBlue.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordFlag.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordIs.js11
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordKill.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordLava.js11
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordPush.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordRock.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordSink.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordStop.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordWall.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordWater.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordWin.js10
-rw-r--r--Homework/cs5410/bbiy/src/entities/wordYou.js10
-rw-r--r--Homework/cs5410/bbiy/src/game.js72
-rw-r--r--Homework/cs5410/bbiy/src/render/graphics.js47
-rw-r--r--Homework/cs5410/bbiy/src/render/sprites.js156
-rw-r--r--Homework/cs5410/bbiy/src/require.js5
-rw-r--r--Homework/cs5410/bbiy/src/systems/collision.js93
-rw-r--r--Homework/cs5410/bbiy/src/systems/grid.js71
-rw-r--r--Homework/cs5410/bbiy/src/systems/keyboardInput.js46
-rw-r--r--Homework/cs5410/bbiy/src/systems/logic.js149
-rw-r--r--Homework/cs5410/bbiy/src/systems/menu.js114
-rw-r--r--Homework/cs5410/bbiy/src/systems/particle.js57
-rw-r--r--Homework/cs5410/bbiy/src/systems/physics.js16
-rw-r--r--Homework/cs5410/bbiy/src/systems/render.js26
-rw-r--r--Homework/cs5410/bbiy/src/systems/system.js1
-rw-r--r--Homework/cs5410/bbiy/src/systems/undo.js32
-rw-r--r--Homework/cs5410/bbiy/src/utils/clamp.js6
-rw-r--r--Homework/cs5410/bbiy/src/utils/loadLevel.js87
-rw-r--r--Homework/cs5410/bbiy/src/utils/objectEquivalence.js14
-rw-r--r--Homework/cs5410/bbiy/src/utils/randInRange.js4
-rw-r--r--Homework/cs5410/bbiy/src/utils/unitizeVector.js11
-rw-r--r--Homework/cs5410/bbiy/styles/style.css73
-rw-r--r--Homework/cs5410/centipede/assets/images/centipede-assets.pngbin0 -> 11555 bytes
-rw-r--r--Homework/cs5410/centipede/assets/sounds/enemy_hit.wavbin0 -> 125286 bytes
-rw-r--r--Homework/cs5410/centipede/assets/sounds/laser.wavbin0 -> 12402 bytes
-rw-r--r--Homework/cs5410/centipede/assets/sounds/mushroom_hit.wavbin0 -> 9780 bytes
-rw-r--r--Homework/cs5410/centipede/css/style.css63
-rw-r--r--Homework/cs5410/centipede/index.html38
-rw-r--r--Homework/cs5410/centipede/js/game/game.js39
-rw-r--r--Homework/cs5410/centipede/js/game/graphics.js55
-rw-r--r--Homework/cs5410/centipede/js/game/input.js32
-rw-r--r--Homework/cs5410/centipede/js/game/menu.js143
-rw-r--r--Homework/cs5410/centipede/js/game/object.js51
-rw-r--r--Homework/cs5410/centipede/js/game/objects/bullet.js11
-rw-r--r--Homework/cs5410/centipede/js/game/objects/centipede.js105
-rw-r--r--Homework/cs5410/centipede/js/game/objects/explosion.js14
-rw-r--r--Homework/cs5410/centipede/js/game/objects/flea.js49
-rw-r--r--Homework/cs5410/centipede/js/game/objects/mushroom.js43
-rw-r--r--Homework/cs5410/centipede/js/game/objects/player.js63
-rw-r--r--Homework/cs5410/centipede/js/game/objects/scorpion.js32
-rw-r--r--Homework/cs5410/centipede/js/game/objects/spider.js45
-rw-r--r--Homework/cs5410/centipede/js/game/sounds.js5
-rw-r--r--Homework/cs5410/centipede/js/game/sprites.js120
-rw-r--r--Homework/cs5410/centipede/js/main.js75
-rw-r--r--Homework/cs5410/maize-maze/LICENSE.md21
-rw-r--r--Homework/cs5410/maize-maze/README.md9
-rw-r--r--Homework/cs5410/maize-maze/css/styles.css24
-rw-r--r--Homework/cs5410/maize-maze/images/corn.pngbin0 -> 10272 bytes
-rw-r--r--Homework/cs5410/maize-maze/images/fire.pngbin0 -> 8378 bytes
-rw-r--r--Homework/cs5410/maize-maze/images/popcorn.jpgbin0 -> 33339 bytes
-rw-r--r--Homework/cs5410/maize-maze/index.html75
-rw-r--r--Homework/cs5410/maize-maze/js/assets.js8
-rw-r--r--Homework/cs5410/maize-maze/js/game.js249
-rw-r--r--Homework/cs5410/maize-maze/js/helpers.js18
-rw-r--r--Homework/cs5410/maize-maze/js/json-ds.js30
-rw-r--r--Homework/cs5410/maize-maze/js/keyboard.js22
-rw-r--r--Homework/cs5410/maize-maze/js/maze.js104
-rw-r--r--Homework/cs5410/maize-maze/screenshot.pngbin0 -> 1295982 bytes
134 files changed, 4323 insertions, 0 deletions
diff --git a/Homework/cs5410/bbiy/README.md b/Homework/cs5410/bbiy/README.md
new file mode 100644
index 0000000..da290c7
--- /dev/null
+++ b/Homework/cs5410/bbiy/README.md
@@ -0,0 +1,20 @@
+# BBIY (Big Blue Is You)
+
+It's like Baba is You, but Aggies (and not as good :P)
+
+Most artwork is from the initial game, as found [here](https://www.spriters-resource.com/pc_computer/babaisyou/sheet/115231/), besides an ugly AF custom "Big Blue" (I am no artist and I spent way too long on it).
+
+Music is "Fluffing a Duck" by Kevin Macleod, found [on YouTube](https://www.youtube.com/watch?v=yQjAF3frudY).
+
+Background image is stolen [from here](https://i.pinimg.com/originals/b2/2a/a2/b22aa22b2f3f55b6468361158d52e2e7.gif).
+## Building and running
+
+It's as simple as:
+
+```
+npm install
+npm run start
+```
+
+## Play online
+[on my website](https://simponic.xyz/bbiy/)
diff --git a/Homework/cs5410/bbiy/assets/image/background.gif b/Homework/cs5410/bbiy/assets/image/background.gif
new file mode 100644
index 0000000..4188529
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/background.gif
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/bigblue.png b/Homework/cs5410/bbiy/assets/image/bigblue.png
new file mode 100644
index 0000000..93f22ea
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/bigblue.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/flag.png b/Homework/cs5410/bbiy/assets/image/flag.png
new file mode 100644
index 0000000..0a53d60
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/flag.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/floor.png b/Homework/cs5410/bbiy/assets/image/floor.png
new file mode 100644
index 0000000..92ec9f7
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/floor.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/grass.png b/Homework/cs5410/bbiy/assets/image/grass.png
new file mode 100644
index 0000000..1991e8c
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/grass.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/hedge.png b/Homework/cs5410/bbiy/assets/image/hedge.png
new file mode 100644
index 0000000..9295e61
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/hedge.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/lava.png b/Homework/cs5410/bbiy/assets/image/lava.png
new file mode 100644
index 0000000..bf95837
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/lava.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/rock.png b/Homework/cs5410/bbiy/assets/image/rock.png
new file mode 100644
index 0000000..ce108b0
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/rock.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wall.png b/Homework/cs5410/bbiy/assets/image/wall.png
new file mode 100644
index 0000000..6912323
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wall.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/water.png b/Homework/cs5410/bbiy/assets/image/water.png
new file mode 100644
index 0000000..47703e0
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/water.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordBigBlue.png b/Homework/cs5410/bbiy/assets/image/wordBigBlue.png
new file mode 100644
index 0000000..6fc767e
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordBigBlue.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordFlag.png b/Homework/cs5410/bbiy/assets/image/wordFlag.png
new file mode 100644
index 0000000..d848902
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordFlag.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordIs.png b/Homework/cs5410/bbiy/assets/image/wordIs.png
new file mode 100644
index 0000000..878e40c
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordIs.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordKill.png b/Homework/cs5410/bbiy/assets/image/wordKill.png
new file mode 100644
index 0000000..e781260
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordKill.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordLava.png b/Homework/cs5410/bbiy/assets/image/wordLava.png
new file mode 100644
index 0000000..be23819
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordLava.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordPush.png b/Homework/cs5410/bbiy/assets/image/wordPush.png
new file mode 100644
index 0000000..bdf847e
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordPush.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordRock.png b/Homework/cs5410/bbiy/assets/image/wordRock.png
new file mode 100644
index 0000000..6809956
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordRock.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordSink.png b/Homework/cs5410/bbiy/assets/image/wordSink.png
new file mode 100644
index 0000000..8b06deb
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordSink.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordStop.png b/Homework/cs5410/bbiy/assets/image/wordStop.png
new file mode 100644
index 0000000..e8dc434
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordStop.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordWall.png b/Homework/cs5410/bbiy/assets/image/wordWall.png
new file mode 100644
index 0000000..24564a1
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordWall.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordWater.png b/Homework/cs5410/bbiy/assets/image/wordWater.png
new file mode 100644
index 0000000..5141d08
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordWater.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordWin.png b/Homework/cs5410/bbiy/assets/image/wordWin.png
new file mode 100644
index 0000000..0c018ea
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordWin.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/image/wordYou.png b/Homework/cs5410/bbiy/assets/image/wordYou.png
new file mode 100644
index 0000000..a0613c5
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/image/wordYou.png
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/sound/death.mp3 b/Homework/cs5410/bbiy/assets/sound/death.mp3
new file mode 100644
index 0000000..b60a956
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/sound/death.mp3
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/sound/move.mp3 b/Homework/cs5410/bbiy/assets/sound/move.mp3
new file mode 100644
index 0000000..59d2de5
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/sound/move.mp3
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/sound/music.mp3 b/Homework/cs5410/bbiy/assets/sound/music.mp3
new file mode 100644
index 0000000..0d879cc
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/sound/music.mp3
Binary files differ
diff --git a/Homework/cs5410/bbiy/assets/sound/win.mp3 b/Homework/cs5410/bbiy/assets/sound/win.mp3
new file mode 100644
index 0000000..ad2887c
--- /dev/null
+++ b/Homework/cs5410/bbiy/assets/sound/win.mp3
Binary files differ
diff --git a/Homework/cs5410/bbiy/index.html b/Homework/cs5410/bbiy/index.html
new file mode 100644
index 0000000..d89a6b9
--- /dev/null
+++ b/Homework/cs5410/bbiy/index.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Big Blue Is You!</title>
+ <link rel="stylesheet" href="styles/style.css">
+ </head>
+
+ <body>
+ <div style="text-align:center">
+ <div class="canvas-holder">
+ <canvas id="game-canvas" width="1000" height="1000"></canvas>
+ <!--
+ <div class="game-hud" id="hud">
+ <p>Hello, world!</p>
+ </div>
+ -->
+ <div class="menu" style="display: none" id="menu">
+ </div>
+ </div>
+ </div>
+
+ <script>
+ const game = {
+ running: true,
+ lastTimeStamp: performance.now(),
+ controls: JSON.parse(
+ localStorage.getItem("controls") || JSON.stringify({
+ left: "a",
+ right: "d",
+ up: "w",
+ down: "s",
+ undo: "z",
+ reset: "r",
+ })
+ ),
+ level: 0,
+ canvas: {
+ width: document.getElementById('game-canvas').width,
+ height: document.getElementById('game-canvas').height,
+ context: document.getElementById('game-canvas').getContext("2d"),
+ },
+ };
+ </script>
+
+ <script data-main = "src/bootstrap" src = "src/require.js"></script>
+ </body>
+</html>
diff --git a/Homework/cs5410/bbiy/index.js b/Homework/cs5410/bbiy/index.js
new file mode 100644
index 0000000..8b046c1
--- /dev/null
+++ b/Homework/cs5410/bbiy/index.js
@@ -0,0 +1,55 @@
+const express = require('express');
+const path = require('path');
+const fs = require('fs');
+
+const MAP_LAYERS=2;
+
+const app = express();
+app.route('/').get((req, res) => {
+ res.sendFile(path.join(__dirname, 'index.html'));
+});
+
+app.route('/levels').get((req, res) => {
+ fs.readFile(path.join(__dirname, 'levels-all.bbiy'), 'utf8', (err, data) => {
+ if (err) {
+ console.log(err);
+ return;
+ }
+
+ const levels = [];
+ const lines = data.split('\r\n');
+ do {
+ const levelName = lines.shift();
+ if (!levelName) {
+ break;
+ }
+ const [xDim, yDim] = lines.shift().split(' x ').map((x) => parseInt(x));
+
+ let level = Array(yDim).fill(null).map(() => Array(xDim).fill(null).map(() => []));
+ for (let i = 0; i < MAP_LAYERS; i++) {
+ for (let y = 0; y < yDim; y++) {
+ const line = lines.shift().split('');
+ for (let x = 0; x < xDim; x++) {
+ if (line[x] !== ' ') {
+ level[y][x].push(line[x]);
+ }
+ }
+ }
+ }
+ levels.push({
+ levelName,
+ gridSize: {xDim, yDim},
+ level,
+ });
+ } while (lines.length);
+
+ // Send the array of objects
+ res.send(levels);
+ });
+});
+
+app.use(express.static('.'));
+
+app.listen(3000, () => {
+ console.log('Listening on 3000');
+});
diff --git a/Homework/cs5410/bbiy/levels-all.bbiy b/Homework/cs5410/bbiy/levels-all.bbiy
new file mode 100644
index 0000000..a098f30
--- /dev/null
+++ b/Homework/cs5410/bbiy/levels-all.bbiy
@@ -0,0 +1,252 @@
+(almost) No Rules
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h h
+h h
+h h
+h h
+h h
+h wwwwwwwwwwww h
+h r h
+h b r f h
+h r h
+h aaaaa vvvvv h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+hhhhhhhhhhhhhhhhhhhh
+
+
+ V IK A IN
+
+ W R
+ IS IP
+
+
+
+
+
+
+
+ BIY IX
+ F
+
+
+
+
+
+Level-1
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+h llllllllllll h
+h llllllllllll h
+h llllllllllll h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+hhhhhhhhhhhhhhhhhhhh
+
+
+
+
+
+ WIS RIP
+
+ wwwwwwwwwwww
+ r
+ b r f
+ r
+ wwwwwwwwwwww
+
+ BIY FIX
+
+
+
+
+
+
+Level-2
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h g h
+h h
+h g g h
+h g g h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+h h
+h g g h
+h g h
+h g gg h
+h h
+hhhhhhhhhhhhhhhhhhhh
+
+
+
+
+ wwwwwwww
+ w w
+ w I w
+ wwwww X w
+ w w
+ w F f b w
+ w w
+ wwwwwwwwwwww
+
+ B W
+ I I
+ Y S
+
+
+
+
+Level-3
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h g g h
+h g g h
+h h
+h g g gg h
+h g g h
+h g h
+h h
+h h
+h g h
+h h
+h gh
+h h
+h gg h
+h h
+h g h
+h gg h
+h h
+hhhhhhhhhhhhhhhhhhhh
+
+
+
+ FIX
+ wwwww
+ w w
+ w f w
+ w w
+ wwwwwwwwwww
+ w w
+ w WIS w
+ w w
+ w w
+ w b w
+ w w
+ w w
+ wwwwwwwwwww
+ BIY
+
+
+Level-4
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h g h
+h g gh
+h h
+h g g h
+h h
+h gg h
+h h
+h h
+h h
+h h
+h h
+h g h
+h h
+hg h
+h h
+h g ggg h
+h g g h
+hhhhhhhhhhhhhhhhhhhh
+
+ BWw
+ IIw AIN
+ YSw wwwwwwww
+ www w w
+ w RIP w
+ w w
+ w b rr w
+ w w
+ wwwwwaaaawwwww
+ w w
+ w w
+ w w
+ waaa w
+ waaa FIX w
+ wfaa w
+ wwwwwwwwwwwwww
+
+
+
+Level-5
+20 x 20
+hhhhhhhhhhhhhhhhhhhh
+h h
+h g g h
+h gg h
+h g h
+h h
+h h
+h ggg h
+h g g h
+h g ggg h
+h g h
+h h
+h h
+h gg g h
+h h
+h h
+h g g h
+h g h
+h h
+hhhhhhhhhhhhhhhhhhhh
+
+
+ r
+ r r
+ r W
+ I
+ wwwww vvvvv S
+ w w v v
+ w b r v f v
+ w w v v
+ wwwww vvvvv
+
+
+ wBIYw r
+ F
+ RIP I
+ X
+
+ VIK
+
diff --git a/Homework/cs5410/bbiy/package-lock.json b/Homework/cs5410/bbiy/package-lock.json
new file mode 100644
index 0000000..0a4e4d5
--- /dev/null
+++ b/Homework/cs5410/bbiy/package-lock.json
@@ -0,0 +1,876 @@
+{
+ "name": "bigblueisyou",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "bigblueisyou",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "express": "^4.17.3"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
+ "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.8.1",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.9.7",
+ "raw-body": "2.4.3",
+ "type-is": "~1.6.18"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.17.3",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
+ "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.2",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.2",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.9.7",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.17.2",
+ "serve-static": "1.14.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
+ "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
+ "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "1.8.1",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/send": {
+ "version": "0.17.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
+ "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "1.8.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.14.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
+ "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ }
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "body-parser": {
+ "version": "1.19.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
+ "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.8.1",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.9.7",
+ "raw-body": "2.4.3",
+ "type-is": "~1.6.18"
+ }
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "express": {
+ "version": "4.17.3",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
+ "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.2",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.2",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.9.7",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.17.2",
+ "serve-static": "1.14.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "http-errors": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
+ "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw=="
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
+ "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "1.8.1",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "send": {
+ "version": "0.17.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
+ "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "1.8.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
+ "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.2"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ }
+ }
+}
diff --git a/Homework/cs5410/bbiy/package.json b/Homework/cs5410/bbiy/package.json
new file mode 100644
index 0000000..e3dfbf8
--- /dev/null
+++ b/Homework/cs5410/bbiy/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "bigblueisyou",
+ "version": "1.0.0",
+ "description": "Big Blue Is You!",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node index.js"
+ },
+ "author": "Logan Hunt",
+ "license": "ISC",
+ "dependencies": {
+ "express": "^4.17.3"
+ }
+}
diff --git a/Homework/cs5410/bbiy/src/bootstrap.js b/Homework/cs5410/bbiy/src/bootstrap.js
new file mode 100644
index 0000000..09e7ec5
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/bootstrap.js
@@ -0,0 +1,117 @@
+game.bootstrap = (() => {
+ const image_extensions = ["png", "jpeg", "jpg"];
+ const audio_extensions = ["mp3"];
+ const scripts = [
+ {
+ src: [
+ 'src/utils/objectEquivalence.js', 'src/utils/unitizeVector.js', 'src/utils/clamp.js', 'src/utils/loadLevel.js',
+ 'src/utils/randInRange.js'
+ ],
+ id: 'utils'
+ },
+ { src: ['src/render/graphics.js'], id: 'graphics' },
+ { src: ['src/render/sprites.js'], id: 'sprites' },
+ { src: ['src/components/component.js'], id: 'component' },
+ {
+ src: [
+ 'src/components/position.js', 'src/components/momentum.js', 'src/components/gridPosition.js',
+ 'src/components/appearence.js', 'src/components/controllable.js', 'src/components/pushable.js',
+ 'src/components/loadPriority.js', 'src/components/stop.js', 'src/components/alive.js',
+ 'src/components/sprite.js', 'src/components/particles.js', 'src/components/noun.js',
+ 'src/components/name.js', 'src/components/verb.js', 'src/components/burn.js',
+ 'src/components/burnable.js', 'src/components/sink.js', 'src/components/sinkable.js',
+ 'src/components/win.js',
+ ],
+ id: 'components'
+ },
+ { src: ['src/entities/entity.js'], id: 'entity' },
+ {
+ src: [
+ 'src/entities/bigblue.js', 'src/entities/flag.js', 'src/entities/floor.js', 'src/entities/grass.js', 'src/entities/hedge.js',
+ 'src/entities/lava.js', 'src/entities/rock.js', 'src/entities/wall.js', 'src/entities/wordBigBlue.js',
+ 'src/entities/wordFlag.js', 'src/entities/wordIs.js', 'src/entities/wordKill.js', 'src/entities/wordLava.js',
+ 'src/entities/wordPush.js', 'src/entities/wordRock.js', 'src/entities/wordSink.js', 'src/entities/wordStop.js',
+ 'src/entities/wordWall.js', 'src/entities/wordWater.js', 'src/entities/wordWin.js', 'src/entities/wordYou.js',
+ 'src/entities/borderParticles.js', 'src/entities/water.js'
+ ],
+ id: 'entities'
+ },
+ { src: ['src/systems/system.js'], id: 'system' },
+ {
+ src: [
+ 'src/systems/render.js', 'src/systems/grid.js', 'src/systems/physics.js', 'src/systems/keyboardInput.js',
+ 'src/systems/collision.js', 'src/systems/undo.js', 'src/systems/particle.js', 'src/systems/menu.js', 'src/systems/logic.js',
+ ],
+ id: 'systems' },
+ { src: ['src/game.js'], id: 'game' },
+ ];
+ const assets = {};
+ [
+ "bigblue", "flag", "floor", "grass", "hedge", "lava", "rock",
+ "wall", "wordBigBlue", "wordFlag", "wordIs", "wordKill", "wordLava",
+ "wordPush", "wordRock", "wordSink", "wordStop", "wordWall", "wordWater",
+ "wordWin", "wordYou", "water"
+ ].map((x) => assets[x] = `assets/image/${x}.png`);
+ [
+ "music", "death", "move", "win"
+ ].map((x) => assets[x] = `assets/sound/${x}.mp3`);
+
+ const loadScripts = function(onDone) {
+ if (scripts.length) {
+ let script = scripts.shift();
+ require(script.src, () => {
+ loadScripts(onDone);
+ });
+ } else {
+ onDone();
+ }
+ }
+
+ const loadAsset = (source) => {
+ let fileExtension = source.substr(source.lastIndexOf('.') + 1);
+ return fetch(source)
+ .then((r) => r.blob())
+ .then((r) => {
+ let asset;
+ if (image_extensions.includes(fileExtension)) {
+ asset = new Image();
+ } else if (audio_extensions.includes(fileExtension)) {
+ asset = new Audio();
+ }
+ asset.src = URL.createObjectURL(r);
+ const ready = () => URL.revokeObjectURL(asset.src);
+ if (asset instanceof Image) {
+ asset.onload = ready;
+ } else if (asset instanceof Audio) {
+ asset.oncanplaythrough = ready;
+ }
+ return asset;
+ })
+ }
+
+ const loadAssets = function() {
+ game.assets = {};
+ const promises = [];
+ for (let key in assets) {
+ promises.push(loadAsset(assets[key], (asset) => {
+ game.assets[key] = asset;
+ }, (error) => {
+ console.log(error)
+ }));
+ }
+ return Promise.all(Object.keys(assets).map((key) => {
+ return loadAsset(assets[key]).then((asset) => game.assets[key] = asset);
+ }));
+ }
+
+ const loadLevels = function() {
+ game.levels = [];
+ fetch('/levels')
+ .then((r) => r.json())
+ .then((r) => game.levels = r);
+ }
+
+ Promise.all([loadAssets(), loadLevels()]).then(() => {
+ loadScripts(() => game.initialize());
+ })
+})();
diff --git a/Homework/cs5410/bbiy/src/components/alive.js b/Homework/cs5410/bbiy/src/components/alive.js
new file mode 100644
index 0000000..08b0890
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/alive.js
@@ -0,0 +1 @@
+game.components.Alive = () => game.Component('alive'); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/appearence.js b/Homework/cs5410/bbiy/src/components/appearence.js
new file mode 100644
index 0000000..8c2130a
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/appearence.js
@@ -0,0 +1 @@
+game.components.Appearance = ({rot, width, height}) => game.Component('appearance', {rot, width, height}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/burn.js b/Homework/cs5410/bbiy/src/components/burn.js
new file mode 100644
index 0000000..f138e9d
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/burn.js
@@ -0,0 +1 @@
+game.components.Burn = () => game.Component('burn', {}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/burnable.js b/Homework/cs5410/bbiy/src/components/burnable.js
new file mode 100644
index 0000000..d5767e7
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/burnable.js
@@ -0,0 +1 @@
+game.components.Burnable = () => game.Component('burnable', {}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/component.js b/Homework/cs5410/bbiy/src/components/component.js
new file mode 100644
index 0000000..9b55a1f
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/component.js
@@ -0,0 +1,8 @@
+game.components = {};
+
+game.Component = (name, spec) => {
+ return {
+ name,
+ ...spec
+ };
+};
diff --git a/Homework/cs5410/bbiy/src/components/controllable.js b/Homework/cs5410/bbiy/src/components/controllable.js
new file mode 100644
index 0000000..84b05ee
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/controllable.js
@@ -0,0 +1 @@
+game.components.Controllable = ({ controls }) => game.Component('controllable', { controls }); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/gridPosition.js b/Homework/cs5410/bbiy/src/components/gridPosition.js
new file mode 100644
index 0000000..ede4b23
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/gridPosition.js
@@ -0,0 +1 @@
+game.components.GridPosition = ({x, y}) => game.Component('gridPosition', {x, y}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/loadPriority.js b/Homework/cs5410/bbiy/src/components/loadPriority.js
new file mode 100644
index 0000000..35c3887
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/loadPriority.js
@@ -0,0 +1 @@
+game.components.LoadPriority = ({priority}) => game.Component('loadPriority', {priority}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/momentum.js b/Homework/cs5410/bbiy/src/components/momentum.js
new file mode 100644
index 0000000..b974aa7
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/momentum.js
@@ -0,0 +1 @@
+game.components.Momentum = ({dx, dy}) => game.Component('momentum', {dx, dy}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/name.js b/Homework/cs5410/bbiy/src/components/name.js
new file mode 100644
index 0000000..d3bf14a
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/name.js
@@ -0,0 +1 @@
+game.components.Name = ({selector}) => game.Component('name', {selector});
diff --git a/Homework/cs5410/bbiy/src/components/noun.js b/Homework/cs5410/bbiy/src/components/noun.js
new file mode 100644
index 0000000..4b01e06
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/noun.js
@@ -0,0 +1 @@
+game.components.Noun = ({select}) => game.Component('noun', {select});
diff --git a/Homework/cs5410/bbiy/src/components/particles.js b/Homework/cs5410/bbiy/src/components/particles.js
new file mode 100644
index 0000000..8120ff1
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/particles.js
@@ -0,0 +1 @@
+game.components.Particles = (spec) => game.Component('particles', {spec});
diff --git a/Homework/cs5410/bbiy/src/components/position.js b/Homework/cs5410/bbiy/src/components/position.js
new file mode 100644
index 0000000..072a1a6
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/position.js
@@ -0,0 +1 @@
+game.components.Position = ({x, y}) => game.Component('position', {x, y}) \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/pushable.js b/Homework/cs5410/bbiy/src/components/pushable.js
new file mode 100644
index 0000000..85087ea
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/pushable.js
@@ -0,0 +1 @@
+game.components.Pushable = () => game.Component('pushable');
diff --git a/Homework/cs5410/bbiy/src/components/sink.js b/Homework/cs5410/bbiy/src/components/sink.js
new file mode 100644
index 0000000..3a4d9dc
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/sink.js
@@ -0,0 +1 @@
+game.components.Sink = () => game.Component('sink', {}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/sinkable.js b/Homework/cs5410/bbiy/src/components/sinkable.js
new file mode 100644
index 0000000..1fcb132
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/sinkable.js
@@ -0,0 +1 @@
+game.components.Sinkable = () => game.Component('sinkable', {}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/sprite.js b/Homework/cs5410/bbiy/src/components/sprite.js
new file mode 100644
index 0000000..f45975d
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/sprite.js
@@ -0,0 +1 @@
+game.components.Sprite = ({spriteName}) => game.Component('sprite', {spriteName}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/components/stop.js b/Homework/cs5410/bbiy/src/components/stop.js
new file mode 100644
index 0000000..17d4c38
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/stop.js
@@ -0,0 +1 @@
+game.components.Stop = () => game.Component("stop");
diff --git a/Homework/cs5410/bbiy/src/components/verb.js b/Homework/cs5410/bbiy/src/components/verb.js
new file mode 100644
index 0000000..393e48c
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/verb.js
@@ -0,0 +1 @@
+game.components.Verb = ({action}) => game.Component('verb', {action});
diff --git a/Homework/cs5410/bbiy/src/components/win.js b/Homework/cs5410/bbiy/src/components/win.js
new file mode 100644
index 0000000..ea905fc
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/components/win.js
@@ -0,0 +1 @@
+game.components.Win = () => game.Component('win', {}); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/entities/bigblue.js b/Homework/cs5410/bbiy/src/entities/bigblue.js
new file mode 100644
index 0000000..45fbc90
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/bigblue.js
@@ -0,0 +1,13 @@
+game.createBigBlue = () => {
+ const bigBlue = game.Entity();
+ bigBlue.addComponent(game.components.LoadPriority({priority: 1}));
+ bigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ bigBlue.addComponent(game.components.Alive());
+ bigBlue.addComponent(game.components.Sprite({spriteName: "bigBlue"}));
+
+// bigBlue.addComponent(game.components.Controllable({controls: ['left', 'right', 'up', 'down']}));
+ bigBlue.addComponent(game.components.Name({selector: "bigblue"}));
+ bigBlue.addComponent(game.components.Burnable());
+ bigBlue.addComponent(game.components.Sinkable());
+ return bigBlue;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/borderParticles.js b/Homework/cs5410/bbiy/src/entities/borderParticles.js
new file mode 100644
index 0000000..e1a7e98
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/borderParticles.js
@@ -0,0 +1,41 @@
+game.createBorderParticles = (spawnerSpec) => {
+ const particleSpawner = game.Entity();
+ const spawnFunction = (particleSpec) => {
+ switch (Math.floor(Math.random() * 4)) {
+ case 0:
+ particleSpec.y = 0;
+ particleSpec.dy = -Math.abs(particleSpec.dy);
+ break;
+ case 1:
+ particleSpec.x = 1;
+ particleSpec.dx = Math.abs(particleSpec.dx);
+ break;
+ case 2:
+ particleSpec.y = 1;
+ particleSpec.dy = Math.abs(particleSpec.dy);
+ break;
+ case 3:
+ particleSpec.x = 0;
+ particleSpec.dx = -Math.abs(particleSpec.dx);
+ break;
+ }
+ return particleSpec;
+ };
+ particleSpawner.addComponent(game.components.Particles({
+ spec: {
+ spawnFunction,
+ colors: ["#666666", "#777777", "#888888", "#999999"],
+ maxSpeed: 0.20,
+ minRadius: 1,
+ maxRadius: 3,
+ minLife: 100,
+ maxLife: 300,
+ minAmount: 20,
+ maxAmount: 50,
+ ...spawnerSpec,
+ }
+ }));
+ particleSpawner.addComponent(game.components.LoadPriority({priority: 1}));
+ particleSpawner.addComponent(game.components.Alive());
+ return particleSpawner;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/entity.js b/Homework/cs5410/bbiy/src/entities/entity.js
new file mode 100644
index 0000000..3da032c
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/entity.js
@@ -0,0 +1,23 @@
+game.nextId = 0;
+
+game.Entity = (id=game.nextId++) => {
+ const components = {};
+
+ const addComponent = (component) => {
+ components[component.name] = component;
+ };
+ const hasComponent = (componentName) => components[componentName] !== undefined;
+ const removeComponent = (componentName) => {
+ if (hasComponent(componentName)) {
+ delete components[componentName];
+ }
+ };
+
+ return {
+ id,
+ components,
+ addComponent,
+ removeComponent,
+ hasComponent
+ };
+} \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/entities/flag.js b/Homework/cs5410/bbiy/src/entities/flag.js
new file mode 100644
index 0000000..e8c662a
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/flag.js
@@ -0,0 +1,12 @@
+game.createFlag = () => {
+ const flag = game.Entity();
+ flag.addComponent(game.components.LoadPriority({priority: 5}));
+ flag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ flag.addComponent(game.components.Alive());
+ flag.addComponent(game.components.Sprite({spriteName: "flag"}))
+ flag.addComponent(game.components.Name({selector: "flag"}));
+
+ flag.addComponent(game.components.Burnable());
+ flag.addComponent(game.components.Sinkable());
+ return flag;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/floor.js b/Homework/cs5410/bbiy/src/entities/floor.js
new file mode 100644
index 0000000..95cbcf2
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/floor.js
@@ -0,0 +1,8 @@
+game.createFloor = () => {
+ const floor = game.Entity();
+ floor.addComponent(game.components.LoadPriority({priority: 6}));
+ floor.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ floor.addComponent(game.components.Alive());
+ floor.addComponent(game.components.Sprite({spriteName: "floor"}))
+ return floor;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/grass.js b/Homework/cs5410/bbiy/src/entities/grass.js
new file mode 100644
index 0000000..7f26712
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/grass.js
@@ -0,0 +1,8 @@
+game.createGrass = () => {
+ const grass = game.Entity();
+ grass.addComponent(game.components.LoadPriority({priority: 6}));
+ grass.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ grass.addComponent(game.components.Alive());
+ grass.addComponent(game.components.Sprite({spriteName: "grass"}))
+ return grass;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/hedge.js b/Homework/cs5410/bbiy/src/entities/hedge.js
new file mode 100644
index 0000000..90d069b
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/hedge.js
@@ -0,0 +1,9 @@
+game.createHedge = () => {
+ const hedge = game.Entity();
+ hedge.addComponent(game.components.LoadPriority({priority: 6}));
+ hedge.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ hedge.addComponent(game.components.Stop({stop: true}));
+ hedge.addComponent(game.components.Alive());
+ hedge.addComponent(game.components.Sprite({spriteName: "hedge"}))
+ return hedge;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/lava.js b/Homework/cs5410/bbiy/src/entities/lava.js
new file mode 100644
index 0000000..e529812
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/lava.js
@@ -0,0 +1,9 @@
+game.createLava = () => {
+ const lava = game.Entity();
+ lava.addComponent(game.components.LoadPriority({priority: 6}));
+ lava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ lava.addComponent(game.components.Alive());
+ lava.addComponent(game.components.Sprite({spriteName: "lava"}))
+ lava.addComponent(game.components.Name({selector: "lava"}));
+ return lava;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/rock.js b/Homework/cs5410/bbiy/src/entities/rock.js
new file mode 100644
index 0000000..a87710a
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/rock.js
@@ -0,0 +1,14 @@
+game.createRock = () => {
+ const rock = game.Entity();
+ rock.addComponent(game.components.LoadPriority({priority: 2}));
+ rock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ rock.addComponent(game.components.Alive());
+ rock.addComponent(game.components.Sprite({spriteName: "rock"}));;
+
+
+// rock.addComponent(game.components.Pushable());
+ rock.addComponent(game.components.Name({selector: "rock"}));
+ rock.addComponent(game.components.Sinkable());
+
+ return rock;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wall.js b/Homework/cs5410/bbiy/src/entities/wall.js
new file mode 100644
index 0000000..e7549ca
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wall.js
@@ -0,0 +1,13 @@
+game.createWall = () => {
+ const wall = game.Entity();
+ wall.addComponent(game.components.LoadPriority({priority: 3}));
+ wall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+// wall.addComponent(game.components.Stop());
+ wall.addComponent(game.components.Name({selector: "wall"}));
+ wall.addComponent(game.components.Alive());
+ wall.addComponent(game.components.Sprite({spriteName: "wall"}));
+
+ wall.addComponent(game.components.Burnable());
+ wall.addComponent(game.components.Sinkable());
+ return wall;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/water.js b/Homework/cs5410/bbiy/src/entities/water.js
new file mode 100644
index 0000000..11522b1
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/water.js
@@ -0,0 +1,9 @@
+game.createWater = () => {
+ const water = game.Entity();
+ water.addComponent(game.components.LoadPriority({priority: 5}));
+ water.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ water.addComponent(game.components.Alive());
+ water.addComponent(game.components.Sprite({spriteName: "water"}))
+ water.addComponent(game.components.Name({selector: "water"}))
+ return water;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordBigBlue.js b/Homework/cs5410/bbiy/src/entities/wordBigBlue.js
new file mode 100644
index 0000000..15aaa0e
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordBigBlue.js
@@ -0,0 +1,10 @@
+game.createWordBigBlue = () => {
+ const wordBigBlue = game.Entity();
+ wordBigBlue.addComponent(game.components.LoadPriority({priority: 3}));
+ wordBigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordBigBlue.addComponent(game.components.Pushable({pushable: true}));
+ wordBigBlue.addComponent(game.components.Alive());
+ wordBigBlue.addComponent(game.components.Sprite({spriteName: "wordBigBlue"}));
+ wordBigBlue.addComponent(game.components.Noun({select: "bigblue"}));
+ return wordBigBlue;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordFlag.js b/Homework/cs5410/bbiy/src/entities/wordFlag.js
new file mode 100644
index 0000000..79617ea
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordFlag.js
@@ -0,0 +1,10 @@
+game.createWordFlag = () => {
+ const wordFlag = game.Entity();
+ wordFlag.addComponent(game.components.LoadPriority({priority: 3}));
+ wordFlag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordFlag.addComponent(game.components.Pushable({pushable: true}));
+ wordFlag.addComponent(game.components.Alive());
+ wordFlag.addComponent(game.components.Sprite({spriteName: "wordFlag"}));
+ wordFlag.addComponent(game.components.Noun({select: "flag"}));
+ return wordFlag;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordIs.js b/Homework/cs5410/bbiy/src/entities/wordIs.js
new file mode 100644
index 0000000..041f10c
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordIs.js
@@ -0,0 +1,11 @@
+game.createWordIs = () => {
+ const wordIs = game.Entity();
+ wordIs.addComponent(game.components.LoadPriority({priority: 3}));
+ wordIs.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ // wordIs.addComponent(game.components.Stop({stop: true}));
+ wordIs.addComponent(game.components.Pushable());
+ wordIs.addComponent(game.components.Alive());
+ wordIs.addComponent(game.components.Sprite({spriteName: "wordIs"}));
+ wordIs.addComponent(game.components.Verb({action: "Is"}));
+ return wordIs;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordKill.js b/Homework/cs5410/bbiy/src/entities/wordKill.js
new file mode 100644
index 0000000..6906e9c
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordKill.js
@@ -0,0 +1,10 @@
+game.createWordKill = () => {
+ const wordKill = game.Entity();
+ wordKill.addComponent(game.components.LoadPriority({priority: 3}));
+ wordKill.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordKill.addComponent(game.components.Pushable({pushable: true}));
+ wordKill.addComponent(game.components.Alive());
+ wordKill.addComponent(game.components.Sprite({spriteName: "wordKill"}))
+ wordKill.addComponent(game.components.Verb({action: "burn"}));
+ return wordKill;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordLava.js b/Homework/cs5410/bbiy/src/entities/wordLava.js
new file mode 100644
index 0000000..cf31286
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordLava.js
@@ -0,0 +1,11 @@
+game.createWordLava = () => {
+ const wordLava = game.Entity();
+ wordLava.addComponent(game.components.LoadPriority({priority: 3}));
+ wordLava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordLava.addComponent(game.components.Pushable({pushable: true}));
+ wordLava.addComponent(game.components.Alive());
+
+ wordLava.addComponent(game.components.Sprite({spriteName: "wordLava"}))
+ wordLava.addComponent(game.components.Noun({select: "lava"}));
+ return wordLava;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordPush.js b/Homework/cs5410/bbiy/src/entities/wordPush.js
new file mode 100644
index 0000000..5594e46
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordPush.js
@@ -0,0 +1,10 @@
+game.createWordPush = () => {
+ const wordPush = game.Entity();
+ wordPush.addComponent(game.components.LoadPriority({priority: 3}));
+ wordPush.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordPush.addComponent(game.components.Pushable({pushable: true}));
+ wordPush.addComponent(game.components.Alive());
+ wordPush.addComponent(game.components.Sprite({spriteName: "wordPush"}));
+ wordPush.addComponent(game.components.Verb({action: "push"}));
+ return wordPush;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordRock.js b/Homework/cs5410/bbiy/src/entities/wordRock.js
new file mode 100644
index 0000000..648f6ba
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordRock.js
@@ -0,0 +1,10 @@
+game.createWordRock = () => {
+ const wordRock = game.Entity();
+ wordRock.addComponent(game.components.LoadPriority({priority: 3}));
+ wordRock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordRock.addComponent(game.components.Pushable({pushable: true}));
+ wordRock.addComponent(game.components.Alive());
+ wordRock.addComponent(game.components.Sprite({spriteName: "wordRock"}));
+ wordRock.addComponent(game.components.Noun({select: "rock"}));
+ return wordRock;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordSink.js b/Homework/cs5410/bbiy/src/entities/wordSink.js
new file mode 100644
index 0000000..369f922
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordSink.js
@@ -0,0 +1,10 @@
+game.createWordSink = () => {
+ const wordSink = game.Entity();
+ wordSink.addComponent(game.components.LoadPriority({priority: 3}));
+ wordSink.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordSink.addComponent(game.components.Pushable({pushable: true}));
+ wordSink.addComponent(game.components.Alive());
+ wordSink.addComponent(game.components.Sprite({spriteName: "wordSink"}));
+ wordSink.addComponent(game.components.Verb({action: "sink"}));
+ return wordSink;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordStop.js b/Homework/cs5410/bbiy/src/entities/wordStop.js
new file mode 100644
index 0000000..e2ad45c
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordStop.js
@@ -0,0 +1,10 @@
+game.createWordStop = () => {
+ const wordStop = game.Entity();
+ wordStop.addComponent(game.components.LoadPriority({priority: 3}));
+ wordStop.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordStop.addComponent(game.components.Pushable({pushable: true}));
+ wordStop.addComponent(game.components.Alive());
+ wordStop.addComponent(game.components.Sprite({spriteName: "wordStop"}));
+ wordStop.addComponent(game.components.Verb({action: "stop"}));
+ return wordStop;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordWall.js b/Homework/cs5410/bbiy/src/entities/wordWall.js
new file mode 100644
index 0000000..277ab69
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordWall.js
@@ -0,0 +1,10 @@
+game.createWordWall = () => {
+ const wordWall = game.Entity();
+ wordWall.addComponent(game.components.LoadPriority({priority: 3}));
+ wordWall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordWall.addComponent(game.components.Pushable({pushable: true}));
+ wordWall.addComponent(game.components.Alive());
+ wordWall.addComponent(game.components.Noun({select: "wall"}));
+ wordWall.addComponent(game.components.Sprite({spriteName: "wordWall"}));
+ return wordWall;
+};
diff --git a/Homework/cs5410/bbiy/src/entities/wordWater.js b/Homework/cs5410/bbiy/src/entities/wordWater.js
new file mode 100644
index 0000000..eb0c1be
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordWater.js
@@ -0,0 +1,10 @@
+game.createWordWater = () => {
+ const wordWater = game.Entity();
+ wordWater.addComponent(game.components.LoadPriority({priority: 3}));
+ wordWater.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordWater.addComponent(game.components.Pushable({pushable: true}));
+ wordWater.addComponent(game.components.Alive());
+ wordWater.addComponent(game.components.Sprite({spriteName: "wordWater"}));
+ wordWater.addComponent(game.components.Noun({select: "water"}));
+ return wordWater;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordWin.js b/Homework/cs5410/bbiy/src/entities/wordWin.js
new file mode 100644
index 0000000..e8948ee
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordWin.js
@@ -0,0 +1,10 @@
+game.createWordWin = () => {
+ const wordWin = game.Entity();
+ wordWin.addComponent(game.components.LoadPriority({priority: 3}));
+ wordWin.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordWin.addComponent(game.components.Pushable({pushable: true}));
+ wordWin.addComponent(game.components.Alive());
+ wordWin.addComponent(game.components.Sprite({spriteName: "wordWin"}));
+ wordWin.addComponent(game.components.Verb({action: "win"}));
+ return wordWin;
+}
diff --git a/Homework/cs5410/bbiy/src/entities/wordYou.js b/Homework/cs5410/bbiy/src/entities/wordYou.js
new file mode 100644
index 0000000..1bf698f
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/entities/wordYou.js
@@ -0,0 +1,10 @@
+game.createWordYou = () => {
+ const wordYou = game.Entity();
+ wordYou.addComponent(game.components.LoadPriority({priority: 3}));
+ wordYou.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
+ wordYou.addComponent(game.components.Pushable({pushable: true}));
+ wordYou.addComponent(game.components.Alive());
+ wordYou.addComponent(game.components.Sprite({spriteName: "wordYou"}));
+ wordYou.addComponent(game.components.Verb({action: "you"}));
+ return wordYou;
+};
diff --git a/Homework/cs5410/bbiy/src/game.js b/Homework/cs5410/bbiy/src/game.js
new file mode 100644
index 0000000..5a7e391
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/game.js
@@ -0,0 +1,72 @@
+game.loop = (timeStamp) => {
+ if (!game.running) {
+ return;
+ }
+
+ let elapsedTime = timeStamp - game.lastTimeStamp;
+ game.lastTimeStamp = timeStamp;
+
+ const changedIds = new Set();
+ game.systemOrder.map((i) => {
+ game.systems[i]
+ .update(elapsedTime, game.entities, changedIds)
+ .forEach((id) => changedIds.add(id));
+ });
+
+ for (let id in game.entities) {
+ if (game.entities[id].hasComponent("particles") && !game.entities[id].hasComponent("alive")) {
+ delete game.entities[id];
+ }
+ }
+
+ requestAnimationFrame(game.loop);
+};
+
+game.toggleRunning = () => {
+ game.running = !game.running;
+};
+
+game.startLoop = () => {
+ game.running = true;
+ game.lastTimeStamp = performance.now();
+ game.assets.music.play();
+ if (game.assets.music.paused) {
+ alert("Failed to start background music; please allow autoplay in your browser settings.");
+ }
+ requestAnimationFrame(game.loop);
+};
+
+game.loadSystems = () => {
+ game.systemOrder = ["grid", "collision", "physics", "keyboardInput", "particle", "logic", "undo", "render"];
+ game.systems = { };
+ game.systems.physics = game.system.Physics(),
+ game.systems.grid = game.system.Grid(game.entitiesGrid);
+ game.systems.collision = game.system.Collision(game.entitiesGrid);
+ game.systems.render = game.system.Render(game.graphics);
+ game.systems.particle = game.system.Particle(game.canvas.context);
+ game.systems.keyboardInput = game.system.KeyboardInput();
+ game.systems.logic = game.system.Logic(game.entitiesGrid);
+ game.systems.undo = game.system.Undo(game.entitiesGrid, game.systems.logic, game.systems.grid);
+ game.systems.menu = game.system.Menu();
+};
+
+game.loadLevelIndex = (level) => {
+ game.win = false;
+
+ game.level = level;
+ [game.entities, game.config] = game.loadLevel(game.levels[game.level]);
+
+ // Maintained by grid system as a side-effect
+ game.entitiesGrid = Array(game.config.yDim).fill(null).map(() => Array(game.config.xDim).fill(null).map(() => new Map()));
+ game.loadSystems();
+};
+
+game.initialize = () => {
+ game.assets.music.addEventListener('ended', function() {
+ this.currentTime = 0;
+ this.play();
+ }, false);
+
+ game.loadLevelIndex(0);
+ game.startLoop();
+};
diff --git a/Homework/cs5410/bbiy/src/render/graphics.js b/Homework/cs5410/bbiy/src/render/graphics.js
new file mode 100644
index 0000000..aa4195e
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/render/graphics.js
@@ -0,0 +1,47 @@
+// Pretty much a copy of my centipede code
+game.graphics = (
+ (context) => {
+ context.imageSmoothingEnabled = false;
+ const clear = () => {
+ context.clearRect(0, 0, game.canvas.width, game.canvas.height);
+ };
+
+ const Sprite = ({image, spriteX, spriteY, spriteWidth, spriteHeight, timePerFrame, cols, rows, numFrames, color, drawFunction}) => {
+ timePerFrame = timePerFrame ?? 100;
+ numFrames = numFrames ?? 1;
+ cols = cols ?? numFrames;
+ rows = rows ?? 1;
+ spriteX = spriteX ?? 0;
+ spriteY = spriteY ?? 0;
+
+ let currentFrame = 0;
+ let lastTime = performance.now();
+
+ let draw;
+ if (!drawFunction) {
+ draw = (_elapsedTime, {x, y, rot, width, height}) => {
+ if (numFrames > 1) {
+ if (performance.now()-lastTime > timePerFrame) {
+ lastTime = performance.now();
+ currentFrame = (currentFrame + 1) % numFrames;
+ }
+ }
+ context.save();
+ context.translate(x+width/2, y+height/2);
+ context.rotate(rot * Math.PI / 180);
+ context.translate(-x-width/2, -y-height/2);
+ const row = currentFrame % rows;
+ const col = Math.floor(currentFrame / rows);
+ context.drawImage(image, spriteX+col*spriteWidth, spriteY+row*spriteHeight, spriteWidth, spriteHeight, x, y, width, height);
+
+ context.restore();
+ };
+ } else {
+ draw = (elapsedTime, drawSpec) => drawFunction(elapsedTime, drawSpec, context);
+ }
+ return { draw };
+ }
+
+ return { clear, Sprite };
+ }
+)(game.canvas.context);
diff --git a/Homework/cs5410/bbiy/src/render/sprites.js b/Homework/cs5410/bbiy/src/render/sprites.js
new file mode 100644
index 0000000..d8ae126
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/render/sprites.js
@@ -0,0 +1,156 @@
+game.sprites = {
+ bigBlue: game.graphics.Sprite({
+ image: game.assets.bigblue,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ flag: game.graphics.Sprite({
+ image: game.assets.flag,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ floor: game.graphics.Sprite({
+ image: game.assets.floor,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ hedge: game.graphics.Sprite({
+ image: game.assets.hedge,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 250,
+ }),
+ grass: game.graphics.Sprite({
+ image: game.assets.grass,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ lava: game.graphics.Sprite({
+ image: game.assets.lava,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ rock: game.graphics.Sprite({
+ image: game.assets.rock,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wall: game.graphics.Sprite({
+ image: game.assets.wall,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ water: game.graphics.Sprite({
+ image: game.assets.water,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordBigBlue: game.graphics.Sprite({
+ image: game.assets.wordBigBlue,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordFlag: game.graphics.Sprite({
+ image: game.assets.wordFlag,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordIs: game.graphics.Sprite({
+ image: game.assets.wordIs,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordKill: game.graphics.Sprite({
+ image: game.assets.wordKill,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordLava: game.graphics.Sprite({
+ image: game.assets.wordLava,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordPush: game.graphics.Sprite({
+ image: game.assets.wordPush,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordRock: game.graphics.Sprite({
+ image: game.assets.wordRock,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordSink: game.graphics.Sprite({
+ image: game.assets.wordSink,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordStop: game.graphics.Sprite({
+ image: game.assets.wordStop,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordWall: game.graphics.Sprite({
+ image: game.assets.wordWall,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordWater: game.graphics.Sprite({
+ image: game.assets.wordWater,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordWin: game.graphics.Sprite({
+ image: game.assets.wordWin,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+ wordYou: game.graphics.Sprite({
+ image: game.assets.wordYou,
+ spriteHeight: 24,
+ spriteWidth: 24,
+ numFrames: 3,
+ timePerFrame: 100,
+ }),
+};
diff --git a/Homework/cs5410/bbiy/src/require.js b/Homework/cs5410/bbiy/src/require.js
new file mode 100644
index 0000000..a4203f0
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/require.js
@@ -0,0 +1,5 @@
+/** vim: et:ts=4:sw=4:sts=4
+ * @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors.
+ * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
+ */
+var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;i<e.length&&(!e[i]||!t(e[i],i,e));i+=1);}function eachReverse(e,t){var i;if(e)for(i=e.length-1;-1<i&&(!e[i]||!t(e[i],i,e));i-=1);}function hasProp(e,t){return hasOwn.call(e,t)}function getOwn(e,t){return hasProp(e,t)&&e[t]}function eachProp(e,t){var i;for(i in e)if(hasProp(e,i)&&t(e[i],i))break}function mixin(i,e,r,n){return e&&eachProp(e,function(e,t){!r&&hasProp(i,t)||(!n||"object"!=typeof e||!e||isArray(e)||isFunction(e)||e instanceof RegExp?i[t]=e:(i[t]||(i[t]={}),mixin(i[t],e,r,n)))}),i}function bind(e,t){return function(){return t.apply(e,arguments)}}function scripts(){return document.getElementsByTagName("script")}function defaultOnError(e){throw e}function getGlobal(e){if(!e)return e;var t=global;return each(e.split("."),function(e){t=t[e]}),t}function makeError(e,t,i,r){var n=new Error(t+"\nhttps://requirejs.org/docs/errors.html#"+e);return n.requireType=e,n.requireModules=r,i&&(n.originalError=i),n}if(void 0===define){if(void 0!==requirejs){if(isFunction(requirejs))return;cfg=requirejs,requirejs=void 0}void 0===require||isFunction(require)||(cfg=require,require=void 0),req=requirejs=function(e,t,i,r){var n,o,a=defContextName;return isArray(e)||"string"==typeof e||(o=e,isArray(t)?(e=t,t=i,i=r):e=[]),o&&o.context&&(a=o.context),(n=getOwn(contexts,a))||(n=contexts[a]=req.s.newContext(a)),o&&n.configure(o),n.require(e,t,i)},req.config=function(e){return req(e)},req.nextTick=void 0!==setTimeout?function(e){setTimeout(e,4)}:function(e){e()},require||(require=req),req.version=version,req.jsExtRegExp=/^\/|:|\?|\.js$/,req.isBrowser=isBrowser,s=req.s={contexts:contexts,newContext:newContext},req({}),each(["toUrl","undef","defined","specified"],function(t){req[t]=function(){var e=contexts[defContextName];return e.require[t].apply(e,arguments)}}),isBrowser&&(head=s.head=document.getElementsByTagName("head")[0],baseElement=document.getElementsByTagName("base")[0],baseElement&&(head=s.head=baseElement.parentNode)),req.onError=defaultOnError,req.createNode=function(e,t,i){var r=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");return r.type=e.scriptType||"text/javascript",r.charset="utf-8",r.async=!0,r},req.load=function(t,i,r){var e,n=t&&t.config||{};if(isBrowser)return(e=req.createNode(n,i,r)).setAttribute("data-requirecontext",t.contextName),e.setAttribute("data-requiremodule",i),!e.attachEvent||e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0||isOpera?(e.addEventListener("load",t.onScriptLoad,!1),e.addEventListener("error",t.onScriptError,!1)):(useInteractive=!0,e.attachEvent("onreadystatechange",t.onScriptLoad)),e.src=r,n.onNodeCreated&&n.onNodeCreated(e,n,i,r),currentlyAddingScript=e,baseElement?head.insertBefore(e,baseElement):head.appendChild(e),currentlyAddingScript=null,e;if(isWebWorker)try{setTimeout(function(){},0),importScripts(r),t.completeLoad(i)}catch(e){t.onError(makeError("importscripts","importScripts failed for "+i+" at "+r,e,[i]))}},isBrowser&&!cfg.skipDataMain&&eachReverse(scripts(),function(e){if(head||(head=e.parentNode),dataMain=e.getAttribute("data-main"))return mainScript=dataMain,cfg.baseUrl||-1!==mainScript.indexOf("!")||(mainScript=(src=mainScript.split("/")).pop(),subPath=src.length?src.join("/")+"/":"./",cfg.baseUrl=subPath),mainScript=mainScript.replace(jsSuffixRegExp,""),req.jsExtRegExp.test(mainScript)&&(mainScript=dataMain),cfg.deps=cfg.deps?cfg.deps.concat(mainScript):[mainScript],!0}),define=function(e,i,t){var r,n;"string"!=typeof e&&(t=i,i=e,e=null),isArray(i)||(t=i,i=null),!i&&isFunction(t)&&(i=[],t.length&&(t.toString().replace(commentRegExp,commentReplace).replace(cjsRequireRegExp,function(e,t){i.push(t)}),i=(1===t.length?["require"]:["require","exports","module"]).concat(i))),useInteractive&&(r=currentlyAddingScript||getInteractiveScript())&&(e||(e=r.getAttribute("data-requiremodule")),n=contexts[r.getAttribute("data-requirecontext")]),n?(n.defQueue.push([e,i,t]),n.defQueueMap[e]=!0):globalDefQueue.push([e,i,t])},define.amd={jQuery:!0},req.exec=function(text){return eval(text)},req(cfg)}function newContext(u){var i,e,l,c,d,g={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},p={},f={},r={},h=[],m={},n={},v={},x=1,b=1;function q(e,t,i){var r,n,o,a,s,u,c,d,p,f,l=t&&t.split("/"),h=g.map,m=h&&h["*"];if(e&&(u=(e=e.split("/")).length-1,g.nodeIdCompat&&jsSuffixRegExp.test(e[u])&&(e[u]=e[u].replace(jsSuffixRegExp,"")),"."===e[0].charAt(0)&&l&&(e=l.slice(0,l.length-1).concat(e)),function(e){var t,i;for(t=0;t<e.length;t++)if("."===(i=e[t]))e.splice(t,1),t-=1;else if(".."===i){if(0===t||1===t&&".."===e[2]||".."===e[t-1])continue;0<t&&(e.splice(t-1,2),t-=2)}}(e),e=e.join("/")),i&&h&&(l||m)){e:for(o=(n=e.split("/")).length;0<o;o-=1){if(s=n.slice(0,o).join("/"),l)for(a=l.length;0<a;a-=1)if((r=getOwn(h,l.slice(0,a).join("/")))&&(r=getOwn(r,s))){c=r,d=o;break e}!p&&m&&getOwn(m,s)&&(p=getOwn(m,s),f=o)}!c&&p&&(c=p,d=f),c&&(n.splice(0,d,c),e=n.join("/"))}return getOwn(g.pkgs,e)||e}function E(t){isBrowser&&each(scripts(),function(e){if(e.getAttribute("data-requiremodule")===t&&e.getAttribute("data-requirecontext")===l.contextName)return e.parentNode.removeChild(e),!0})}function w(e){var t=getOwn(g.paths,e);if(t&&isArray(t)&&1<t.length)return t.shift(),l.require.undef(e),l.makeRequire(null,{skipMap:!0})([e]),!0}function y(e){var t,i=e?e.indexOf("!"):-1;return-1<i&&(t=e.substring(0,i),e=e.substring(i+1,e.length)),[t,e]}function S(e,t,i,r){var n,o,a,s,u=null,c=t?t.name:null,d=e,p=!0,f="";return e||(p=!1,e="_@r"+(x+=1)),u=(s=y(e))[0],e=s[1],u&&(u=q(u,c,r),o=getOwn(m,u)),e&&(u?f=i?e:o&&o.normalize?o.normalize(e,function(e){return q(e,c,r)}):-1===e.indexOf("!")?q(e,c,r):e:(u=(s=y(f=q(e,c,r)))[0],f=s[1],i=!0,n=l.nameToUrl(f))),{prefix:u,name:f,parentMap:t,unnormalized:!!(a=!u||o||i?"":"_unnormalized"+(b+=1)),url:n,originalName:d,isDefine:p,id:(u?u+"!"+f:f)+a}}function k(e){var t=e.id,i=getOwn(p,t);return i||(i=p[t]=new l.Module(e)),i}function M(e,t,i){var r=e.id,n=getOwn(p,r);!hasProp(m,r)||n&&!n.defineEmitComplete?(n=k(e)).error&&"error"===t?i(n.error):n.on(t,i):"defined"===t&&i(m[r])}function O(i,e){var t=i.requireModules,r=!1;e?e(i):(each(t,function(e){var t=getOwn(p,e);t&&(t.error=i,t.events.error&&(r=!0,t.emit("error",i)))}),r||req.onError(i))}function j(){globalDefQueue.length&&(each(globalDefQueue,function(e){var t=e[0];"string"==typeof t&&(l.defQueueMap[t]=!0),h.push(e)}),globalDefQueue=[])}function P(e){delete p[e],delete f[e]}function R(){var e,r,t=1e3*g.waitSeconds,n=t&&l.startTime+t<(new Date).getTime(),o=[],a=[],s=!1,u=!0;if(!i){if(i=!0,eachProp(f,function(e){var t=e.map,i=t.id;if(e.enabled&&(t.isDefine||a.push(e),!e.error))if(!e.inited&&n)w(i)?s=r=!0:(o.push(i),E(i));else if(!e.inited&&e.fetched&&t.isDefine&&(s=!0,!t.prefix))return u=!1}),n&&o.length)return(e=makeError("timeout","Load timeout for modules: "+o,null,o)).contextName=l.contextName,O(e);u&&each(a,function(e){!function n(o,a,s){var e=o.map.id;o.error?o.emit("error",o.error):(a[e]=!0,each(o.depMaps,function(e,t){var i=e.id,r=getOwn(p,i);!r||o.depMatched[t]||s[i]||(getOwn(a,i)?(o.defineDep(t,m[i]),o.check()):n(r,a,s))}),s[e]=!0)}(e,{},{})}),n&&!r||!s||!isBrowser&&!isWebWorker||d||(d=setTimeout(function(){d=0,R()},50)),i=!1}}function a(e){hasProp(m,e[0])||k(S(e[0],null,!0)).init(e[1],e[2])}function o(e,t,i,r){e.detachEvent&&!isOpera?r&&e.detachEvent(r,t):e.removeEventListener(i,t,!1)}function s(e){var t=e.currentTarget||e.srcElement;return o(t,l.onScriptLoad,"load","onreadystatechange"),o(t,l.onScriptError,"error"),{node:t,id:t&&t.getAttribute("data-requiremodule")}}function T(){var e;for(j();h.length;){if(null===(e=h.shift())[0])return O(makeError("mismatch","Mismatched anonymous define() module: "+e[e.length-1]));a(e)}l.defQueueMap={}}return c={require:function(e){return e.require?e.require:e.require=l.makeRequire(e.map)},exports:function(e){if(e.usingExports=!0,e.map.isDefine)return e.exports?m[e.map.id]=e.exports:e.exports=m[e.map.id]={}},module:function(e){return e.module?e.module:e.module={id:e.map.id,uri:e.map.url,config:function(){return getOwn(g.config,e.map.id)||{}},exports:e.exports||(e.exports={})}}},(e=function(e){this.events=getOwn(r,e.id)||{},this.map=e,this.shim=getOwn(g.shim,e.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0}).prototype={init:function(e,t,i,r){r=r||{},this.inited||(this.factory=t,i?this.on("error",i):this.events.error&&(i=bind(this,function(e){this.emit("error",e)})),this.depMaps=e&&e.slice(0),this.errback=i,this.inited=!0,this.ignore=r.ignore,r.enabled||this.enabled?this.enable():this.check())},defineDep:function(e,t){this.depMatched[e]||(this.depMatched[e]=!0,this.depCount-=1,this.depExports[e]=t)},fetch:function(){if(!this.fetched){this.fetched=!0,l.startTime=(new Date).getTime();var e=this.map;if(!this.shim)return e.prefix?this.callPlugin():this.load();l.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],bind(this,function(){return e.prefix?this.callPlugin():this.load()}))}},load:function(){var e=this.map.url;n[e]||(n[e]=!0,l.load(this.map.id,e))},check:function(){if(this.enabled&&!this.enabling){var t,e,i=this.map.id,r=this.depExports,n=this.exports,o=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,this.depCount<1&&!this.defined){if(isFunction(o)){if(this.events.error&&this.map.isDefine||req.onError!==defaultOnError)try{n=l.execCb(i,o,r,n)}catch(e){t=e}else n=l.execCb(i,o,r,n);if(this.map.isDefine&&void 0===n&&((e=this.module)?n=e.exports:this.usingExports&&(n=this.exports)),t)return t.requireMap=this.map,t.requireModules=this.map.isDefine?[this.map.id]:null,t.requireType=this.map.isDefine?"define":"require",O(this.error=t)}else n=o;if(this.exports=n,this.map.isDefine&&!this.ignore&&(m[i]=n,req.onResourceLoad)){var a=[];each(this.depMaps,function(e){a.push(e.normalizedMap||e)}),req.onResourceLoad(l,this.map,a)}P(i),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else hasProp(l.defQueueMap,i)||this.fetch()}},callPlugin:function(){var u=this.map,c=u.id,e=S(u.prefix);this.depMaps.push(e),M(e,"defined",bind(this,function(e){var o,t,i,r=getOwn(v,this.map.id),n=this.map.name,a=this.map.parentMap?this.map.parentMap.name:null,s=l.makeRequire(u.parentMap,{enableBuildCallback:!0});return this.map.unnormalized?(e.normalize&&(n=e.normalize(n,function(e){return q(e,a,!0)})||""),M(t=S(u.prefix+"!"+n,this.map.parentMap,!0),"defined",bind(this,function(e){this.map.normalizedMap=t,this.init([],function(){return e},null,{enabled:!0,ignore:!0})})),void((i=getOwn(p,t.id))&&(this.depMaps.push(t),this.events.error&&i.on("error",bind(this,function(e){this.emit("error",e)})),i.enable()))):r?(this.map.url=l.nameToUrl(r),void this.load()):((o=bind(this,function(e){this.init([],function(){return e},null,{enabled:!0})})).error=bind(this,function(e){this.inited=!0,(this.error=e).requireModules=[c],eachProp(p,function(e){0===e.map.id.indexOf(c+"_unnormalized")&&P(e.map.id)}),O(e)}),o.fromText=bind(this,function(e,t){var i=u.name,r=S(i),n=useInteractive;t&&(e=t),n&&(useInteractive=!1),k(r),hasProp(g.config,c)&&(g.config[i]=g.config[c]);try{req.exec(e)}catch(e){return O(makeError("fromtexteval","fromText eval for "+c+" failed: "+e,e,[c]))}n&&(useInteractive=!0),this.depMaps.push(r),l.completeLoad(i),s([i],o)}),void e.load(u.name,s,o,g))})),l.enable(e,this),this.pluginMaps[e.id]=e},enable:function(){(f[this.map.id]=this).enabled=!0,this.enabling=!0,each(this.depMaps,bind(this,function(e,t){var i,r,n;if("string"==typeof e){if(e=S(e,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[t]=e,n=getOwn(c,e.id))return void(this.depExports[t]=n(this));this.depCount+=1,M(e,"defined",bind(this,function(e){this.undefed||(this.defineDep(t,e),this.check())})),this.errback?M(e,"error",bind(this,this.errback)):this.events.error&&M(e,"error",bind(this,function(e){this.emit("error",e)}))}i=e.id,r=p[i],hasProp(c,i)||!r||r.enabled||l.enable(e,this)})),eachProp(this.pluginMaps,bind(this,function(e){var t=getOwn(p,e.id);t&&!t.enabled&&l.enable(e,this)})),this.enabling=!1,this.check()},on:function(e,t){var i=this.events[e];i||(i=this.events[e]=[]),i.push(t)},emit:function(e,t){each(this.events[e],function(e){e(t)}),"error"===e&&delete this.events[e]}},(l={config:g,contextName:u,registry:p,defined:m,urlFetched:n,defQueue:h,defQueueMap:{},Module:e,makeModuleMap:S,nextTick:req.nextTick,onError:O,configure:function(e){if(e.baseUrl&&"/"!==e.baseUrl.charAt(e.baseUrl.length-1)&&(e.baseUrl+="/"),"string"==typeof e.urlArgs){var i=e.urlArgs;e.urlArgs=function(e,t){return(-1===t.indexOf("?")?"?":"&")+i}}var r=g.shim,n={paths:!0,bundles:!0,config:!0,map:!0};eachProp(e,function(e,t){n[t]?(g[t]||(g[t]={}),mixin(g[t],e,!0,!0)):g[t]=e}),e.bundles&&eachProp(e.bundles,function(e,t){each(e,function(e){e!==t&&(v[e]=t)})}),e.shim&&(eachProp(e.shim,function(e,t){isArray(e)&&(e={deps:e}),!e.exports&&!e.init||e.exportsFn||(e.exportsFn=l.makeShimExports(e)),r[t]=e}),g.shim=r),e.packages&&each(e.packages,function(e){var t;t=(e="string"==typeof e?{name:e}:e).name,e.location&&(g.paths[t]=e.location),g.pkgs[t]=e.name+"/"+(e.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}),eachProp(p,function(e,t){e.inited||e.map.unnormalized||(e.map=S(t,null,!0))}),(e.deps||e.callback)&&l.require(e.deps||[],e.callback)},makeShimExports:function(t){return function(){var e;return t.init&&(e=t.init.apply(global,arguments)),e||t.exports&&getGlobal(t.exports)}},makeRequire:function(o,a){function s(e,t,i){var r,n;return a.enableBuildCallback&&t&&isFunction(t)&&(t.__requireJsBuild=!0),"string"==typeof e?isFunction(t)?O(makeError("requireargs","Invalid require call"),i):o&&hasProp(c,e)?c[e](p[o.id]):req.get?req.get(l,e,o,s):(r=S(e,o,!1,!0).id,hasProp(m,r)?m[r]:O(makeError("notloaded",'Module name "'+r+'" has not been loaded yet for context: '+u+(o?"":". Use require([])")))):(T(),l.nextTick(function(){T(),(n=k(S(null,o))).skipMap=a.skipMap,n.init(e,t,i,{enabled:!0}),R()}),s)}return a=a||{},mixin(s,{isBrowser:isBrowser,toUrl:function(e){var t,i=e.lastIndexOf("."),r=e.split("/")[0];return-1!==i&&(!("."===r||".."===r)||1<i)&&(t=e.substring(i,e.length),e=e.substring(0,i)),l.nameToUrl(q(e,o&&o.id,!0),t,!0)},defined:function(e){return hasProp(m,S(e,o,!1,!0).id)},specified:function(e){return e=S(e,o,!1,!0).id,hasProp(m,e)||hasProp(p,e)}}),o||(s.undef=function(i){j();var e=S(i,o,!0),t=getOwn(p,i);t.undefed=!0,E(i),delete m[i],delete n[e.url],delete r[i],eachReverse(h,function(e,t){e[0]===i&&h.splice(t,1)}),delete l.defQueueMap[i],t&&(t.events.defined&&(r[i]=t.events),P(i))}),s},enable:function(e){getOwn(p,e.id)&&k(e).enable()},completeLoad:function(e){var t,i,r,n=getOwn(g.shim,e)||{},o=n.exports;for(j();h.length;){if(null===(i=h.shift())[0]){if(i[0]=e,t)break;t=!0}else i[0]===e&&(t=!0);a(i)}if(l.defQueueMap={},r=getOwn(p,e),!t&&!hasProp(m,e)&&r&&!r.inited){if(!(!g.enforceDefine||o&&getGlobal(o)))return w(e)?void 0:O(makeError("nodefine","No define call for "+e,null,[e]));a([e,n.deps||[],n.exportsFn])}R()},nameToUrl:function(e,t,i){var r,n,o,a,s,u,c=getOwn(g.pkgs,e);if(c&&(e=c),u=getOwn(v,e))return l.nameToUrl(u,t,i);if(req.jsExtRegExp.test(e))a=e+(t||"");else{for(r=g.paths,o=(n=e.split("/")).length;0<o;o-=1)if(s=getOwn(r,n.slice(0,o).join("/"))){isArray(s)&&(s=s[0]),n.splice(0,o,s);break}a=n.join("/"),a=("/"===(a+=t||(/^data\:|^blob\:|\?/.test(a)||i?"":".js")).charAt(0)||a.match(/^[\w\+\.\-]+:/)?"":g.baseUrl)+a}return g.urlArgs&&!/^blob\:/.test(a)?a+g.urlArgs(e,a):a},load:function(e,t){req.load(l,e,t)},execCb:function(e,t,i,r){return t.apply(r,i)},onScriptLoad:function(e){if("load"===e.type||readyRegExp.test((e.currentTarget||e.srcElement).readyState)){interactiveScript=null;var t=s(e);l.completeLoad(t.id)}},onScriptError:function(e){var i=s(e);if(!w(i.id)){var r=[];return eachProp(p,function(e,t){0!==t.indexOf("_@r")&&each(e.depMaps,function(e){if(e.id===i.id)return r.push(t),!0})}),O(makeError("scripterror",'Script error for "'+i.id+(r.length?'", needed by: '+r.join(", "):'"'),e,[i.id]))}}}).require=l.makeRequire(),l}function getInteractiveScript(){return interactiveScript&&"interactive"===interactiveScript.readyState||eachReverse(scripts(),function(e){if("interactive"===e.readyState)return interactiveScript=e}),interactiveScript}}(this,"undefined"==typeof setTimeout?void 0:setTimeout); \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/systems/collision.js b/Homework/cs5410/bbiy/src/systems/collision.js
new file mode 100644
index 0000000..0732c74
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/collision.js
@@ -0,0 +1,93 @@
+game.system.Collision = (entitiesGrid) => {
+ const update = (elapsedTime, entities, changedIds) => {
+ const thisChangedIds = new Set();
+ for (let entity of Object.keys(entities).map((id) => entities[id])) {
+ if (entity.hasComponent("position") && entity.hasComponent("gridPosition") && (entity.hasComponent("burnable") || entity.hasComponent("sinkable")) && entity.hasComponent("alive")) {
+ for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) {
+ if (!equivalence(entity, collided) && collided.hasComponent("alive")){
+ if (entity.hasComponent("burnable") && collided.hasComponent("burn")) {
+ const burnedParticleSpawner = game.createBorderParticles({colors: ["#f58d42", "#d6600b", "#c7a312", "#f2b844"]});
+ burnedParticleSpawner.addComponent(game.components.Position(collided.components.position));
+ burnedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim}));
+ game.entities[burnedParticleSpawner.id] = burnedParticleSpawner;
+ entity.removeComponent("alive");
+ game.assets.death.play();
+ break;
+ } else if (entity.hasComponent("sinkable") && collided.hasComponent("sink")) {
+ const sunkParticleSpawner = game.createBorderParticles({colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"]});
+ sunkParticleSpawner.addComponent(game.components.Position(collided.components.position));
+ sunkParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim}));
+ game.entities[sunkParticleSpawner.id] = sunkParticleSpawner;
+ entity.removeComponent("alive");
+ collided.removeComponent("alive");
+ game.assets.death.play();
+ break;
+ }
+ }
+ }
+ }
+ if (entity.hasComponent("controllable") && entity.hasComponent("gridPosition")) {
+ for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) {
+ if (collided.hasComponent("win")) {
+ game.assets.win.play();
+ game.win = true;
+ game.systems.menu.bringUpMenu();
+ game.systems.menu.setState("levelSelect");
+ }
+ }
+
+ if (entity.hasComponent("momentum")) {
+ const momentum = unitize(entity.components.momentum);
+
+ let found;
+ const proposed = {x: entity.components.gridPosition.x + momentum.dx, y: entity.components.gridPosition.y + momentum.dy};
+ const entitiesToPush = [];
+ let wall = false;
+ do {
+ const proposedClampedInBounds = clamp(proposed, game.config.xDim-1, game.config.yDim-1);
+ if (!equivalence(proposed, proposedClampedInBounds)) {
+ break;
+ }
+
+ found = false;
+
+ const entitiesInCell = entitiesGrid[proposed.y][proposed.x];
+
+ for (let next of entitiesInCell.values()) {
+ if (next.hasComponent("alive")) {
+ if (next.hasComponent("stop")) {
+ wall = next;
+ found = false;
+ break;
+ }
+ if (next.hasComponent("pushable")) {
+ entitiesToPush.push(next);
+ found = true;
+ }
+ }
+ }
+
+ proposed.x += momentum.dx;
+ proposed.y += momentum.dy;
+ } while(found);
+
+ if (wall) {
+ entity.removeComponent("momentum");
+ } else {
+ game.assets.move.play();
+ entitiesToPush.map((e) => {
+ const pushedParticleSpawner = game.createBorderParticles({maxSpeed: 0.1, minAmount: 10, maxAmount: 15});
+ pushedParticleSpawner.addComponent(game.components.Position(e.components.position));
+ pushedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim}));
+ game.entities[pushedParticleSpawner.id] = pushedParticleSpawner;
+
+ e.addComponent(game.components.Momentum({...momentum}));
+ });
+ }
+ }
+ }
+ }
+ return thisChangedIds;
+ };
+ return { update };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/grid.js b/Homework/cs5410/bbiy/src/systems/grid.js
new file mode 100644
index 0000000..6d4cf84
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/grid.js
@@ -0,0 +1,71 @@
+game.system.Grid = (entitiesGrid) => {
+ let gridWidth = game.canvas.width / game.config.xDim;
+ let gridHeight = game.canvas.height / game.config.yDim;
+
+ const gameCoordsToGrid = ({ x, y }) => {
+ return { x: Math.floor((x+gridWidth/2) / game.canvas.width * game.config.yDim), y: Math.floor((y+gridHeight/2) / game.canvas.height * game.config.yDim) };
+ };
+
+ const gridCoordsToGame = ({ x, y }) => {
+ return { x: x * gridWidth, y: y * gridHeight };
+ };
+
+ const rebuildGrid = (entities) => {
+ let changedIds = new Set();
+ entities.map(entity => {
+ const { x, y } = entity.components.gridPosition;
+ if (!entitiesGrid[y][x].has(entity.id)) {
+ changedIds.add(entity.id);
+ }
+ });
+ entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => {
+ for (let id of entitiesInCell.keys()) {
+ if (changedIds.has(id)) {
+ entitiesInCell.delete(id);
+ }
+ }
+ }));
+ changedIds.forEach(id => {
+ // TODO: Figure out why we HAVE to use game.entities rather than entities
+ // Hint: it breaks when changing a level in the menu
+ const entity = game.entities[id];
+ const { x, y } = entity.components.gridPosition;
+ entitiesGrid[y][x].set(entity.id, entity);
+ });
+ };
+
+ const update = (_elapsedTime, entities, changedIds) => {
+ gridEntities = Object.keys(entities).filter((x) => entities[x].hasComponent("gridPosition")).map((x) => entities[x]);
+ const thisChangedIds = new Set();
+ gridEntities.map((entity) => {
+ if (entity.hasComponent("appearance")) {
+ entity.components.appearance.width = gridWidth;
+ entity.components.appearance.height = gridHeight;
+ }
+ if (entity.hasComponent("gridPosition")) {
+ const oldGridCoords = entity.components.gridPosition;
+ if (entity.hasComponent("position")) {
+ const gameCoords = gridCoordsToGame(entity.components.gridPosition);
+ if (Math.abs(entity.components.position.x - gameCoords.x) >= gridWidth/2 || Math.abs(entity.components.position.y - gameCoords.y) >= gridHeight/2) {
+ entity.components.gridPosition = gameCoordsToGrid(entity.components.position);
+ if (entity.hasComponent("momentum")) {
+ entity.removeComponent("momentum");
+ }
+ }
+ }
+ if (!entity.hasComponent("position") || !equivalence(entity.components.gridPosition, oldGridCoords)) {
+ entity.components.position = {
+ ...entity.components.position,
+ ...gridCoordsToGame(entity.components.gridPosition)
+ };
+ thisChangedIds.add(entity.id);
+ }
+ }
+ });
+ rebuildGrid(gridEntities);
+ return thisChangedIds;
+ };
+
+
+ return { gameCoordsToGrid, gridCoordsToGame, update, gridWidth, gridHeight };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/keyboardInput.js b/Homework/cs5410/bbiy/src/systems/keyboardInput.js
new file mode 100644
index 0000000..1b399ca
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/keyboardInput.js
@@ -0,0 +1,46 @@
+game.system.KeyboardInput = () => {
+ "use strict";
+ const keys = {};
+ const keyPress = (event) => {
+ if (!event.repeat) {
+ keys[event.key] = true;
+ }
+ };
+ const removeKey = (event) => {
+ delete keys[event.key];
+ };
+ const update = (elapsedTime, entities, changedIds) => {
+ for (let id in entities) {
+ const entity = entities[id];
+ if (entity.hasComponent('controllable') && entity.hasComponent('alive')) {
+ const controls = entity.components.controllable.controls;
+ if (!changedIds.has(entity.id)) {
+ if (controls.includes('left') && keys[game.controls.left]) {
+ entity.addComponent(game.components.Momentum({ dx: -1, dy: 0 }));
+ } else if (controls.includes('right') && keys[game.controls.right]) {
+ entity.addComponent(game.components.Momentum({ dx: 1, dy: 0 }));
+ } else if (controls.includes('up') && keys[game.controls.up]) {
+ entity.addComponent(game.components.Momentum({ dx: 0, dy: -1 }));
+ } else if (controls.includes('down') && keys[game.controls.down]) {
+ entity.addComponent(game.components.Momentum({ dx: 0, dy: 1 }));
+ }
+ }
+ }
+ }
+ if (keys[game.controls.undo]) {
+ game.systems.undo.undo(entities);
+ }
+ if (keys[game.controls.reset]) {
+ game.loadLevelIndex(game.level);
+ }
+ if (keys["Escape"]) {
+ game.systems.menu.bringUpMenu();
+ }
+ Object.keys(keys).map((key) => delete keys[key]);
+
+ return new Set();
+ };
+ window.addEventListener("keydown", keyPress);
+ window.addEventListener("keyup", removeKey);
+ return { keys, update };
+}
diff --git a/Homework/cs5410/bbiy/src/systems/logic.js b/Homework/cs5410/bbiy/src/systems/logic.js
new file mode 100644
index 0000000..e8854c1
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/logic.js
@@ -0,0 +1,149 @@
+game.system.Logic = (entitiesGrid) => {
+ "use strict";
+ let currentVerbRules = [];
+ let previousVerbState = {
+ controllable: new Set(),
+ win: new Set(),
+ };
+ const isWord = (entity) => entity.hasComponent("gridPosition") && (entity.hasComponent("verb") || entity.hasComponent("noun"));
+
+ const getFirstWordEntity = (gridPosition) => {
+ if (!equivalence(gridPosition, clamp(gridPosition, game.config.xDim, game.config.yDim))) {
+ return null;
+ }
+ for (let entity of entitiesGrid[gridPosition.y][gridPosition.x].values()) {
+ if (isWord(entity)) {
+ return entity;
+ }
+ }
+ return null;
+ };
+
+ const verbActionsToComponent = {
+ "stop": game.components.Stop(),
+ "push": game.components.Pushable(),
+ "you": game.components.Controllable({controls: ['left', 'right', 'up', 'down']}),
+ "burn": game.components.Burn(),
+ "sink": game.components.Sink(),
+ "win": game.components.Win(),
+ };
+
+ const nounsToEntityCreators = {
+ "rock": game.createRock,
+ "wall": game.createWall,
+ "bigblue": game.createBigBlue,
+ "flag": game.createFlag,
+ "lava": game.createLava,
+ "water": game.createWater,
+ };
+
+ const doOnRule = (rule, entities, direction) => {
+ const [applyee, application] = [entities[rule[0]], entities[rule[1]]];
+ const changedEntityIds = [];
+ if (applyee.hasComponent("noun")) {
+ const entityName = applyee.components.noun.select;
+ if (application.hasComponent("verb")) {
+ const verb = application.components.verb.action;
+ if (direction == "apply") {
+ currentVerbRules.push(rule);
+ }
+ for (let id in entities) {
+ const entity = entities[id];
+ if (entity.hasComponent("alive") && entity.hasComponent("name") && entity.components.name.selector == entityName) {
+ changedEntityIds.push(id);
+ const component = verbActionsToComponent[verb];
+ if (component) {
+ if (direction == "apply") {
+ if (verb == "you") {
+ if (!previousVerbState.controllable.has(id)) {
+ const newYouParticleSpawner = game.createBorderParticles({colors: ["#ffc0cb", "#ffb6c1", "#ffc1cc", "#ffbcd9", "#ff1493"], minAmount: 80, maxAmount: 150, maxSpeed: 0.5});
+ newYouParticleSpawner.addComponent(game.components.Position(entity.components.position));
+ newYouParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim}));
+ game.entities[newYouParticleSpawner.id] = newYouParticleSpawner;
+ }
+ }
+ if (verb == "win") {
+ if (!previousVerbState.win.has(id)) {
+ game.assets.win.play();
+ }
+ }
+ entity.addComponent(component);
+ } else if (direction == "deapply") {
+ if (entity.hasComponent("controllable")) {
+ previousVerbState.controllable.add(id);
+ }
+ if (entity.hasComponent("win")) {
+ previousVerbState.win.add(id);
+ }
+ entity.removeComponent(component.name);
+ }
+ }
+ }
+ }
+ if (direction == "apply") {
+ if (changedEntityIds.some((id) => previousVerbState.controllable.has(id))) {
+ previousVerbState.controllable = new Set();
+ }
+ }
+ }
+ if (application.hasComponent("noun")) {
+ const applicationEntityName = application.components.noun.select;
+ for (let id in entities) {
+ const entity = entities[id];
+ if (entity.hasComponent("name") && entity.components.name.selector == entityName) {
+ const e = nounsToEntityCreators[applicationEntityName]();
+ ["name", "sprite", "burnable", "sinkable"].map((name) => {
+ if (e.hasComponent(name)) {
+ entity.components[name] = e.components[name];
+ }
+ });
+ }
+ }
+ }
+ };
+ return changedEntityIds;
+ };
+
+ const parseRules = (entities) => {
+ currentVerbRules.map((rule) => doOnRule(rule, entities, "deapply"));
+ currentVerbRules = [];
+ const isWordGridPositions = [];
+ const changedEntityIds = new Set();
+ entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => {
+ for (let entity of entitiesInCell.values()) {
+ if (isWord(entity) && entity.hasComponent("verb") && entity.components.verb.action == "Is") {
+ isWordGridPositions.push(entity.components.gridPosition);
+ }
+ }
+ }));
+ let newRules = [];
+ isWordGridPositions.forEach((gridPosition) => {
+ const east = getFirstWordEntity({y: gridPosition.y, x: gridPosition.x - 1});
+ const west = getFirstWordEntity({y: gridPosition.y, x: gridPosition.x + 1});
+ const north = getFirstWordEntity({x: gridPosition.x, y: gridPosition.y - 1});
+ const south = getFirstWordEntity({x: gridPosition.x, y: gridPosition.y + 1});
+
+ if (east && west) {
+ newRules.push([east.id, west.id]);
+ }
+ if (north && south) {
+ newRules.push([north.id, south.id]);
+ }
+ });
+ newRules = newRules.sort((a, b) => (entities[b[1]].hasComponent("noun") ? 1 : -1) - (entities[a[1]].hasComponent("noun") ? 1 : -1));
+ newRules.map((rule) => doOnRule(rule, entities, "apply").map((id) => changedEntityIds.add(id)));
+ return changedEntityIds;
+ };
+
+ const update = (_elapsedTime, entities, changedIds) => {
+ for (let id of changedIds) {
+ const changed = entities[id];
+ if (changed.hasComponent("verb") || changed.hasComponent("noun")) {
+ return parseRules(entities);
+ }
+ }
+ return new Set();
+ };
+
+ return { update, parseRules };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/menu.js b/Homework/cs5410/bbiy/src/systems/menu.js
new file mode 100644
index 0000000..abd6748
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/menu.js
@@ -0,0 +1,114 @@
+game.system.Menu = () => {
+ let state;
+
+ const menuElement = document.getElementById("menu");
+
+ const escapeEventListener = (e) => {
+ if (e.key == "Escape") {
+ setState('main');
+ }
+ };
+
+ const setState = (newState) => {
+ state = newState;
+ draw();
+ };
+
+ const bringUpMenu = () => {
+ game.running = false;
+ game.assets.music.pause();
+ window.addEventListener("keydown", escapeEventListener);
+ setState("main");
+ };
+
+ const hide = () => {
+ menuElement.style.display = "none";
+ game.startLoop();
+ };
+
+ const listenFor = (action, elementId) => {
+ const element = document.getElementById(elementId);
+ element.innerHTML = "Listening...";
+ const handleKey = (event) => {
+ window.removeEventListener("keydown", handleKey);
+ if (event.key == "Escape") {
+ element.innerHTML = menu.controls[action];
+ return;
+ }
+ game.controls[action] = event.key;
+ localStorage.setItem("controls", JSON.stringify(game.controls));
+ element.innerHTML = event.key;
+ };
+ window.addEventListener("keydown", handleKey);
+ };
+
+ const setLevel = (index) => {
+ game.loadLevelIndex(index);
+ hide();
+ };
+
+ const draw = () => {
+ menuElement.style.display = "block";
+ menuElement.innerHTML = `<h1><span style='color: blue'>Big Blue</span> Is <span style='color: green'>You</h1>`;
+ if (state == "main") {
+ menuElement.innerHTML += `
+ <div class='menu-button' onclick='game.systems.menu.setState("controls")'>Change Controls</div>
+ <div class='menu-button' onclick='game.systems.menu.setState("credits")'>Credits</div>
+ <div class='menu-button' onclick='game.systems.menu.setState("levelSelect")'>Select Level</div>
+ `;
+ }
+ else if (state == "controls") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ Move left: <button id="moveLeft" onfocus='game.systems.menu.listenFor("left", "moveLeft")'>${game.controls.left}</button>
+ <br>
+ Move right: <button id="moveRight" onfocus='game.systems.menu.listenFor("right", "moveRight")'>${game.controls.right}</button>
+ <br>
+ Move up: <button id="moveUp" onfocus='game.systems.menu.listenFor("up", "moveUp")'>${game.controls.up}</button>
+ <br>
+ Move down: <button id="moveDown" onfocus='game.systems.menu.listenFor("down", "moveDown")'>${game.controls.down}</button>
+ <br>
+ Undo: <button id="undo" onfocus='game.systems.menu.listenFor("undo", "undo")'>${game.controls.undo}</button>
+ <br>
+ Reset: <button id="reset" onfocus='game.systems.menu.listenFor("reset", "reset")'>${game.controls.reset}</button>
+ </p>
+ </div>
+ `;
+ } else if (state == "credits") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ Sprites from Baba Is You, as hosted <a href="https://www.spriters-resource.com/pc_computer/babaisyou/sheet/115231/">here</a>, and a few custom ones.
+ <br>
+ Background is from <a href="https://i.pinimg.com/originals/b2/2a/a2/b22aa22b2f3f55b6468361158d52e2e7.gif">PinImg</a>.
+ <br>
+ Music is <a href="https://www.youtube.com/watch?v=yQjAF3frudY">Fluffing A Duck</a> by Kevin MacLeod.
+ <br>
+ Other sound effects generated on <a href="https://www.sfxr.me/">SFXR</a>.
+ <br>
+ Developed by Logan Hunt, Ethan Payne
+ </p>
+ </div>
+ `;
+ } else if (state == "levelSelect") {
+ menuElement.innerHTML += `
+ <div>
+ <p> Select a level to play: </p>
+ ${
+ game.levels.map((level, index) => {
+ return `<div class='menu-button' onclick='game.systems.menu.setLevel(${index});'>${level.levelName}</div>`;
+ }).join("")
+ }
+ `;
+ }
+ if (!game.win) {
+ menuElement.innerHTML += "<div class='menu-button' onclick='game.systems.menu.hide()'>Resume Game</div>";
+ }
+ if (state !== "main") {
+ menuElement.innerHTML += "<div class='menu-button' onclick='game.systems.menu.setState(\"main\")'>Back</div>";
+ }
+ };
+
+ return { bringUpMenu, setState, listenFor, hide, setLevel, state };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/particle.js b/Homework/cs5410/bbiy/src/systems/particle.js
new file mode 100644
index 0000000..56d8c47
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/particle.js
@@ -0,0 +1,57 @@
+game.system.Particle = () => {
+ "use strict";
+ const particleSpawners = {};
+
+ const particleSpawner = ({colors, maxAmount, minAmount, minLife, maxLife, minRadius, maxRadius, maxSpeed, spawnFunction}) => {
+ return Array(randomInRange(minAmount, maxAmount)).fill(0).map(() => {
+ let particleSpec = {
+ x: Math.random(),
+ y: Math.random(),
+ dx: Math.random() * maxSpeed - maxSpeed / 2,
+ dy: Math.random() * maxSpeed - maxSpeed / 2,
+ radius: randomInRange(minRadius, maxRadius),
+ color: colors[randomInRange(0, colors.length-1)],
+ lifetime: randomInRange(minLife, maxLife),
+ elapsed: 0,
+ };
+ if (spawnFunction) {
+ particleSpec = {...particleSpec, ...spawnFunction(particleSpec)};
+ }
+ return particleSpec;
+ });
+ };
+
+ const update = (elapsedTime, entities, _changedIds) => {
+ for (let id in entities) {
+ const entity = entities[id];
+ if (entity.hasComponent("particles")) {
+ if (!particleSpawners[entity.id]) {
+ particleSpawners[entity.id] = particleSpawner(entity.components.particles.spec.spec);
+ entities[id].particleSprite = game.graphics.Sprite({
+ drawFunction: (elapsedTime, {x, y, width, height}, context) => {
+ let particleSpawner = particleSpawners[entity.id];
+ particleSpawner.map((particleSpec) => particleSpec.elapsed += elapsedTime);
+ particleSpawners[id] = particleSpawner.filter((particleSpec) => particleSpec.lifetime > particleSpec.elapsed);
+ particleSpawner = particleSpawners[id];
+ if (particleSpawner.length === 0) {
+ entities[id].removeComponent("alive");
+ }
+ particleSpawner.map((particleSpec) => {
+ const position = {x: (particleSpec.x * width) + x + particleSpec.dx * particleSpec.elapsed, y: (particleSpec.y * height) + y + particleSpec.dy * particleSpec.elapsed};
+ const fill = context.fillStyle;
+ context.fillStyle = particleSpec.color;
+ context.beginPath();
+ context.arc(position.x, position.y, particleSpec.radius, 0, 2 * Math.PI);
+ context.fill();
+ context.fillStyle = fill;
+ });
+ }
+ });
+ }
+ }
+ }
+ return new Set();
+ };
+
+ return { update };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/physics.js b/Homework/cs5410/bbiy/src/systems/physics.js
new file mode 100644
index 0000000..18c3cb3
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/physics.js
@@ -0,0 +1,16 @@
+game.system.Physics = () => {
+ const update = (elapsedTime, entities, changedIds) => {
+ for (let id in entities) {
+ const entity = entities[id];
+ if (entity.hasComponent("momentum") && entity.hasComponent("appearance")) {
+ const {dx, dy} = entity.components.momentum;
+ entity.components.position.x += dx * elapsedTime;
+ entity.components.position.y += dy * elapsedTime;
+ entity.components.position = clamp(entity.components.position, game.canvas.width - entity.components.appearance.width, game.canvas.height - entity.components.appearance.height);
+ }
+ }
+
+ return new Set();
+ };
+ return { update };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/render.js b/Homework/cs5410/bbiy/src/systems/render.js
new file mode 100644
index 0000000..e0db7e3
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/render.js
@@ -0,0 +1,26 @@
+game.system.Render = (graphics) => {
+ const update = (elapsedTime, entities, _changedIds) => {
+ graphics.clear();
+
+ const entitiesArray = Object.keys(entities).map(key => entities[key]);
+ const sortedEntities = entitiesArray.sort((a, b) => {
+ const aprior = a.hasComponent("loadPriority") ? a.components.loadPriority.priority : 0;
+ const bprior = b.hasComponent("loadPriority") ? b.components.loadPriority.priority : 0;
+ return bprior - aprior;
+ });
+
+ sortedEntities.forEach((entity) => {
+ if (entity.hasComponent("position") && entity.hasComponent("appearance") && entity.hasComponent("alive")) {
+ const drawSpec = {...entity.components.position, ...entity.components.appearance};
+ if (entity.hasComponent("sprite")) {
+ game.sprites[entity.components.sprite.spriteName].draw(elapsedTime, drawSpec);
+ } else if (entity.hasComponent("particles") && entity.particleSprite) {
+ entity.particleSprite.draw(elapsedTime, drawSpec);
+ }
+ }
+ });
+
+ return new Set();
+ };
+ return { update };
+};
diff --git a/Homework/cs5410/bbiy/src/systems/system.js b/Homework/cs5410/bbiy/src/systems/system.js
new file mode 100644
index 0000000..f331401
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/system.js
@@ -0,0 +1 @@
+game.system = {}; \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/systems/undo.js b/Homework/cs5410/bbiy/src/systems/undo.js
new file mode 100644
index 0000000..086d6b4
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/systems/undo.js
@@ -0,0 +1,32 @@
+game.system.Undo = (entitiesGrid, logicSystem, gridSystem) => {
+ const states = [];
+
+ const update = (elapsedTime, entities, changedIds) => {
+ if (changedIds.size) {
+ const state = {};
+ for (let id in entities) {
+ if (entities[id].hasComponent("gridPosition")) {
+ state[id] = JSON.parse(JSON.stringify(entities[id].components));
+ }
+ }
+ states.push(state);
+ }
+ return new Set();
+ };
+
+ const undo = (entities) => {
+ let state = states.slice(0, -1).pop();
+ if (states.length > 1) {
+ states.pop();
+ }
+ for (let id in state) {
+ for (let componentName in state[id]) {
+ entities[id].addComponent({name: componentName, ...state[id][componentName]});
+ }
+ }
+ gridSystem.update(0, entities, new Set());
+ logicSystem.parseRules(entities);
+ };
+
+ return { update, undo };
+};
diff --git a/Homework/cs5410/bbiy/src/utils/clamp.js b/Homework/cs5410/bbiy/src/utils/clamp.js
new file mode 100644
index 0000000..b0da861
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/utils/clamp.js
@@ -0,0 +1,6 @@
+const clamp = (vector, maxX, maxY) => {
+ const newVector = {...vector};
+ newVector.x = Math.max(0, Math.min(maxX, vector.x));
+ newVector.y = Math.max(0, Math.min(maxY, vector.y));
+ return newVector;
+};
diff --git a/Homework/cs5410/bbiy/src/utils/loadLevel.js b/Homework/cs5410/bbiy/src/utils/loadLevel.js
new file mode 100644
index 0000000..3bd86d9
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/utils/loadLevel.js
@@ -0,0 +1,87 @@
+game.loadLevel = (level) => {
+ const entities = {};
+ const config = {...level.gridSize};
+ for (let y = 0; y < level.gridSize.yDim; y++) {
+ for (let x = 0; x < level.gridSize.xDim; x++) {
+ const cell = level.level[y][x];
+ cell.forEach((letter) => {
+ let entity;
+ switch (letter) {
+ case 'b':
+ entity = game.createBigBlue();
+ break;
+ case 'h':
+ entity = game.createHedge();
+ break;
+ case 'r':
+ entity = game.createRock();
+ break;
+ case 'f':
+ entity = game.createFlag();
+ break;
+ case 'g':
+ entity = game.createGrass();
+ break;
+ case 'l':
+ entity = game.createFloor();
+ break;
+ case 'w':
+ entity = game.createWall();
+ break;
+ case 'a':
+ entity = game.createWater();
+ break;
+ case 'A':
+ entity = game.createWordWater();
+ break;
+ case 'N':
+ entity = game.createWordSink();
+ break;
+ case 'V':
+ entity = game.createWordLava();
+ break;
+ case 'v':
+ entity = game.createLava();
+ break;
+ case 'K':
+ entity = game.createWordKill();
+ break;
+ case 'W':
+ entity = game.createWordWall();
+ break;
+ case 'I':
+ entity = game.createWordIs();
+ break;
+ case 'S':
+ entity = game.createWordStop();
+ break;
+ case 'R':
+ entity = game.createWordRock();
+ break;
+ case 'P':
+ entity = game.createWordPush();
+ break;
+ case 'B':
+ entity = game.createWordBigBlue();
+ break;
+ case 'Y':
+ entity = game.createWordYou();
+ break;
+ case 'F':
+ entity = game.createWordFlag();
+ break;
+ case 'X':
+ entity = game.createWordWin();
+ break;
+ default:
+ break;
+ }
+ if (entity) {
+ entity.addComponent(game.components.GridPosition({x, y}));
+ entities[entity.id] = entity;
+ }
+ });
+ }
+ }
+ return [entities, config];
+}; \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/utils/objectEquivalence.js b/Homework/cs5410/bbiy/src/utils/objectEquivalence.js
new file mode 100644
index 0000000..e33dd76
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/utils/objectEquivalence.js
@@ -0,0 +1,14 @@
+const equivalence = (obj1, obj2) => {
+ if (obj1 === null) {
+ return obj1 === null;
+ }
+ return Object.keys(obj1).every(key => {
+ if (obj2[key] === undefined) {
+ return false;
+ }
+ if (typeof obj1[key] === 'object') {
+ return equivalence(obj1[key], obj2[key]);
+ }
+ return obj1[key] === obj2[key];
+ });
+};
diff --git a/Homework/cs5410/bbiy/src/utils/randInRange.js b/Homework/cs5410/bbiy/src/utils/randInRange.js
new file mode 100644
index 0000000..528221a
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/utils/randInRange.js
@@ -0,0 +1,4 @@
+const randomInRange = (min, max) => {
+ // min <= random number <= max
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+} \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/src/utils/unitizeVector.js b/Homework/cs5410/bbiy/src/utils/unitizeVector.js
new file mode 100644
index 0000000..6297ca8
--- /dev/null
+++ b/Homework/cs5410/bbiy/src/utils/unitizeVector.js
@@ -0,0 +1,11 @@
+const unitize = (vector) => {
+ // Not *technically* a unit vector, but has x,y components of |magnitude| = 1
+ Object.keys(vector).forEach((key) => {
+ if (typeof vector[key] === 'object') {
+ vector[key] = vector[key].unitize();
+ } else if (typeof vector[key] === 'number') {
+ vector[key] = (vector[key] === 0 ? 0 : vector[key] / Math.abs(vector[key]));
+ }
+ });
+ return vector;
+} \ No newline at end of file
diff --git a/Homework/cs5410/bbiy/styles/style.css b/Homework/cs5410/bbiy/styles/style.css
new file mode 100644
index 0000000..9f0dc5c
--- /dev/null
+++ b/Homework/cs5410/bbiy/styles/style.css
@@ -0,0 +1,73 @@
+body {
+ margin: 0;
+ font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace;
+ background-image: url("/assets/image/background.gif");
+ background-size: cover;
+ image-rendering: pixelated;
+}
+
+.canvas-holder {
+ padding-top: 4vh;
+ padding-bottom: 4vh;
+}
+.canvas-holder canvas {
+ padding: 0;
+ margin: auto;
+ display: block;
+ height: 90vh;
+ width: auto;
+ border: 3px solid grey;
+ border-radius: 5px;
+ max-width: 100%;
+ background-color: rgba(0, 0, 25, 0.9);
+}
+
+.game-hud {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translate(-50%, -5px);
+ z-index: 1;
+
+ background-color: rgba(255,255,255,0.5);
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ border: 1px solid white;
+ border-radius: 5px;
+}
+
+.game-hud p {
+ margin: 0;
+ padding: 0;
+ font-size: 3vh;
+ text-align: center;
+}
+
+.menu {
+ text-align:center;
+ max-width: 400px;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ position:absolute;
+
+ background-color: rgba(200,200,255,0.90);
+ border: 1px solid #fff;
+ border-radius: 5px;
+ padding: 12px;
+ min-width: 400px;
+}
+
+.menu-button {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+ margin-bottom: 8px;
+ cursor: pointer;
+}
+
+.menu-button:hover {
+ background-color: #d0d0d0;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/assets/images/centipede-assets.png b/Homework/cs5410/centipede/assets/images/centipede-assets.png
new file mode 100644
index 0000000..20b9eac
--- /dev/null
+++ b/Homework/cs5410/centipede/assets/images/centipede-assets.png
Binary files differ
diff --git a/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav b/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav
new file mode 100644
index 0000000..1b9c53f
--- /dev/null
+++ b/Homework/cs5410/centipede/assets/sounds/enemy_hit.wav
Binary files differ
diff --git a/Homework/cs5410/centipede/assets/sounds/laser.wav b/Homework/cs5410/centipede/assets/sounds/laser.wav
new file mode 100644
index 0000000..16159a4
--- /dev/null
+++ b/Homework/cs5410/centipede/assets/sounds/laser.wav
Binary files differ
diff --git a/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav b/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav
new file mode 100644
index 0000000..ef26432
--- /dev/null
+++ b/Homework/cs5410/centipede/assets/sounds/mushroom_hit.wav
Binary files differ
diff --git a/Homework/cs5410/centipede/css/style.css b/Homework/cs5410/centipede/css/style.css
new file mode 100644
index 0000000..7142e28
--- /dev/null
+++ b/Homework/cs5410/centipede/css/style.css
@@ -0,0 +1,63 @@
+body {
+ margin: 0;
+ font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace;
+}
+
+.canvas-holder canvas {
+ padding: 0;
+ margin: auto;
+ display: block;
+ height: 100vh;
+ width: auto;
+ max-width: 100%;
+ background-color: black;
+}
+
+.game-hud {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translate(-50%, -5px);
+ z-index: 1;
+
+ background-color: rgba(255,255,255,0.5);
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ border: 1px solid white;
+ border-radius: 5px;
+}
+
+.game-hud p {
+ margin: 0;
+ padding: 0;
+ font-size: 3vh;
+ text-align: center;
+}
+
+.menu {
+ text-align:center;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ position:absolute;
+
+ background-color: rgba(255,255,255,0.75);
+ border: 1px solid #fff;
+ border-radius: 5px;
+ padding: 12px;
+ min-width: 400px;
+}
+
+.menu-button {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+ margin-bottom: 8px;
+ cursor: pointer;
+}
+
+.menu-button:hover {
+ background-color: #d0d0d0;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/index.html b/Homework/cs5410/centipede/index.html
new file mode 100644
index 0000000..3d73470
--- /dev/null
+++ b/Homework/cs5410/centipede/index.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Centipede</title>
+ <link rel="stylesheet" href="css/style.css">
+ </head>
+
+ <body>
+ <div style="text-align:center">
+ <div class="canvas-holder">
+ <canvas id="game-canvas" width="1400" height="1000"></canvas>
+ <div class="game-hud" id="hud">
+ <p>Hello, world!</p>
+ </div>
+ <div class="menu" style="display: none" id="menu">
+ </div>
+ </div>
+ </div>
+
+ <script src="js/game/game.js"></script>
+ <script src="js/game/input.js"></script>
+ <script src="js/game/menu.js"></script>
+ <script src="js/game/graphics.js"></script>
+ <script src="js/game/sprites.js"></script>
+ <script src="js/game/sounds.js"></script>
+ <script src="js/game/object.js"></script>
+ <script src="js/game/objects/player.js"></script>
+ <script src="js/game/objects/mushroom.js"></script>
+ <script src="js/game/objects/bullet.js"></script>
+ <script src="js/game/objects/centipede.js"></script>
+ <script src="js/game/objects/explosion.js"></script>
+ <script src="js/game/objects/flea.js"></script>
+ <script src="js/game/objects/spider.js"></script>
+ <script src="js/game/objects/scorpion.js"></script>
+
+ <script src="js/main.js"></script>
+ </body>
+</html> \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/game.js b/Homework/cs5410/centipede/js/game/game.js
new file mode 100644
index 0000000..30454f9
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/game.js
@@ -0,0 +1,39 @@
+const game = {
+ stopped: false,
+ width: document.getElementById('game-canvas').width,
+ height: document.getElementById('game-canvas').height,
+ level: 1,
+};
+
+game.resume = () => {
+ game.stopped = false;
+ game.lastTimeStamp = performance.now();
+ menu.reRegisterKeys();
+ requestAnimationFrame(gameLoop);
+}
+
+game.resetObjects = () => {
+ game.player.x = game.width/2;
+ game.player.y = game.height/2;
+ game.bullets = [];
+ game.explosions = [];
+ game.mushroomDims = {width: 40, height: 40};
+ game.mushrooms = game.Mushroom.generateMushrooms(game.mushroomDims);
+ game.centipede = game.Centipede({segments: Math.min(game.level*5 + 5, 15), startX: game.width/2, startY: 0, rot: 180, width: 40, height: 40, dx: 0.2, dy: 0});
+ game.spiders = [];
+ game.fleas = [];
+ game.scorpions = [];
+}
+
+game.gameOver = () => {
+ menu.showMenu();
+ menu.setState('game-over');
+ menu.addScore(game.score);
+
+ menu.onHide = initialize;
+}
+
+game.getObjects = () => [game.player, ...game.bullets, ...game.mushrooms, ...game.spiders, ...game.fleas, ...game.scorpions, game.centipede, ...game.explosions];
+game.getBulletCollidableObjects = () => [...game.mushrooms, ...game.spiders, ...game.fleas, ...game.scorpions, game.centipede];
+game.getMushroomCollidableObjects = () => [game.player, ...game.scorpions, game.centipede];
+game.getPlayerCollidableObjects = () => [...game.spiders, ...game.fleas, ...game.scorpions, game.centipede] \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/graphics.js b/Homework/cs5410/centipede/js/game/graphics.js
new file mode 100644
index 0000000..3a0d7f9
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/graphics.js
@@ -0,0 +1,55 @@
+game.graphics = (
+ (context) => {
+ context.imageSmoothingEnabled = false;
+ const clear = () => {
+ context.clearRect(0, 0, game.width, game.height);
+ };
+
+ const Sprite = ({sheetSrc, spriteX, spriteY, spriteWidth, spriteHeight, timePerFrame, cols, rows, numFrames, drawFunction}) => {
+ timePerFrame = timePerFrame ?? 100;
+ numFrames = numFrames ?? 1;
+ cols = cols ?? numFrames;
+ rows = rows ?? 1;
+
+ let ready = false;
+
+ let image;
+ if (sheetSrc) {
+ image = new Image();
+ image.src = sheetSrc;
+ image.onload = () => { ready = true; };
+ }
+
+ let currentFrame = 0;
+ let lastTime = performance.now();
+
+ let draw;
+ if (!drawFunction) {
+ draw = (_elapsedTime, {x, y, rot, width, height}) => {
+
+ if (ready) {
+ if (numFrames > 1) {
+ if (performance.now()-lastTime > timePerFrame) {
+ lastTime = performance.now();
+ currentFrame = (currentFrame + 1) % numFrames;
+ }
+ }
+ context.save();
+ context.translate(x+width/2, y+height/2);
+ context.rotate(rot * Math.PI / 180);
+ context.translate(-x-width/2, -y-height/2);
+ const row = currentFrame % rows;
+ const col = Math.floor(currentFrame / rows);
+ context.drawImage(image, spriteX+col*spriteWidth, spriteY+row*spriteHeight, spriteWidth, spriteHeight, x, y, width, height);
+ context.restore();
+ }
+ };
+ } else {
+ draw = (elapsedTime, drawSpec) => drawFunction(elapsedTime, drawSpec, context);
+ }
+ return { draw, timePerFrame, numFrames };
+ }
+
+ return { clear, Sprite };
+ }
+)(document.getElementById("game-canvas").getContext("2d")); \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/input.js b/Homework/cs5410/centipede/js/game/input.js
new file mode 100644
index 0000000..6ceff13
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/input.js
@@ -0,0 +1,32 @@
+game.input = (() => {
+ "use strict";
+ const Keyboard = () => {
+ const keys = {};
+ const handlers = {};
+ const keyPress = (event) => {
+ keys[event.key] = event.timeStamp;
+ };
+ const keyRelease = (event) => {
+ delete keys[event.key];
+ };
+ const registerCommand = (key, handler) => {
+ handlers[key] = handler;
+ };
+ const unregisterCommand = (key) => {
+ delete handlers[key];
+ }
+ const update = (elapsedTime) => {
+ for (let key in keys) {
+ if (keys.hasOwnProperty(key)) {
+ if (handlers[key]) {
+ handlers[key](elapsedTime);
+ }
+ }
+ }
+ };
+ window.addEventListener("keydown", keyPress);
+ window.addEventListener("keyup", keyRelease);
+ return {keys, handlers, registerCommand, unregisterCommand, update};
+ }
+ return { Keyboard };
+})(); \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/menu.js b/Homework/cs5410/centipede/js/game/menu.js
new file mode 100644
index 0000000..d4a7fe9
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/menu.js
@@ -0,0 +1,143 @@
+const menu = {};
+menu.initialize = () => {
+ menu.scores = localStorage.getItem("scores") ? JSON.parse(localStorage.getItem("scores")) : [];
+ menu.state = "main";
+
+ menu.controls = localStorage.getItem("controls") ? JSON.parse(localStorage.getItem("controls")) : {
+ "moveUp": "ArrowUp",
+ "moveDown": "ArrowDown",
+ "moveLeft": "ArrowLeft",
+ "moveRight": "ArrowRight",
+ "shoot": " ",
+ };
+}
+
+menu.setState = (state) => {
+ menu.state = state;
+ menu.draw();
+}
+
+menu.escapeEventListener = (e) => {
+ if (e.key == "Escape") {
+ menu.setState('main');
+ menu.draw();
+ }
+}
+
+menu.showMenu = () => {
+ menu.draw();
+ game.stopped = true;
+ window.addEventListener("keydown", menu.escapeEventListener);
+}
+
+menu.reRegisterKeys = () => {
+ Object.keys(game.keyboard.handlers).map(key => game.keyboard.unregisterCommand(key));
+ game.keyboard.registerCommand(menu.controls.moveUp, game.player.moveUp);
+ game.keyboard.registerCommand(menu.controls.moveDown, game.player.moveDown);
+ game.keyboard.registerCommand(menu.controls.moveLeft, game.player.moveLeft);
+ game.keyboard.registerCommand(menu.controls.moveRight, game.player.moveRight);
+ game.keyboard.registerCommand(menu.controls.shoot, game.player.shoot);
+ game.keyboard.registerCommand("Escape", menu.showMenu);
+ localStorage.setItem("controls", JSON.stringify(menu.controls));
+}
+
+menu.addScore = (score) => {
+ menu.scores.push(score);
+ menu.scores.sort((a, b) => b - a);
+ localStorage.setItem("scores", JSON.stringify(menu.scores));
+}
+
+menu.hide = () => {
+ const menuElement = document.getElementById("menu");
+ menuElement.style.display = "none";
+ menu.reRegisterKeys();
+ window.removeEventListener("keydown", menu.escapeEventListener);
+ if (menu.onHide) {
+ menu.onHide();
+ menu.onHide = null;
+ }
+ game.resume();
+}
+
+menu.listenFor = (action, elementId) => {
+ const element = document.getElementById(elementId);
+ element.innerHTML = "Listening...";
+ const handleKey = (event) => {
+ window.removeEventListener("keydown", handleKey);
+ if (event.key == "Escape") {
+ element.innerHTML = menu.controls[action];
+ return;
+ }
+ menu.controls[action] = event.key;
+ element.innerHTML = event.key;
+ }
+ window.addEventListener("keydown", handleKey);
+}
+
+menu.draw = () => {
+ const menuElement = document.getElementById("menu");
+ menuElement.style.display = "block";
+ menuElement.innerHTML = `<h1>Centipede</h1>`;
+ if (menu.state == "main") {
+ menuElement.innerHTML += `
+ <div class='menu-button' onclick='menu.setState("controls")'>Change Controls</div>
+ <div class='menu-button' onclick='menu.setState("credits")'>Credits</div>
+ <div class='menu-button' onclick='menu.setState("scores")'>High Scores</div>
+ `;
+ }
+ else if (menu.state == "controls") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ Move left: <button id="moveLeft" onfocus='menu.listenFor("moveLeft", "moveLeft")'>${menu.controls.moveLeft}</button>
+ <br>
+ Move right: <button id="moveRight" onfocus='menu.listenFor("moveRight", "moveRight")'>${menu.controls.moveRight}</button>
+ <br>
+ Move up: <button id="moveUp" onfocus='menu.listenFor("moveUp", "moveUp")'>${menu.controls.moveUp}</button>
+ <br>
+ Move down: <button id="moveDown" onfocus='menu.listenFor("moveDown", "moveDown")'>${menu.controls.moveDown}</button>
+ <br>
+ Shoot: <button id="shoot" onfocus='menu.listenFor("shoot", "shoot")'>${menu.controls.shoot}</button>
+ </p>
+ </div>
+ `
+ } else if (menu.state == "credits") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ Sounds from <a href="https://opengameart.org/content/laser-fire">dklon</a>
+ <br>
+ Sprites from <a href="https://www.pngkit.com/view/u2w7r5u2e6u2a9r5_general-sprites-centipede-arcade-game-sprites/">PNGKit</a>
+ <br>
+ Some code from <a href="https://www.usu.edu/directory/?person=56DB0BFCCAEECEC8D5">Dr. Mathias</a>
+ <br>
+ Developed by Logan Hunt
+ </p>
+ </div>
+ `
+ } else if (menu.state == "scores") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ ${menu.scores.map((score, index) => `${index + 1}: ${score}<br>`).join("")}
+ </p>
+ </div>
+ `
+ } else if (menu.state == "game-over") {
+ menuElement.innerHTML += `
+ <div>
+ <p>
+ Game Over
+ <br>
+ Your final score was: ${game.score}
+ </div>
+ `
+ }
+
+ menuElement.innerHTML += "<div class='menu-button' onclick='menu.hide()'>Resume Game</div>"
+ if (menu.state !== "main") {
+ menuElement.innerHTML += "<div class='menu-button' onclick='menu.setState(\"main\")'>Back</div>"
+ }
+}
+
+menu.initialize(); \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/object.js b/Homework/cs5410/centipede/js/game/object.js
new file mode 100644
index 0000000..1e22ec6
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/object.js
@@ -0,0 +1,51 @@
+game.Object = (object) => {
+ object.dx = object.dx ?? 0;
+ object.dy = object.dy ?? 0;
+ object.rot = object.rot ?? 0;
+ object.drot = object.drot ?? 0;
+ object.alive = object.alive ?? true;
+
+ object.poisonedTimer = object.poisonedTimer ?? 4000;
+ object.poisoned = false;
+ object.elapsedPoisonedTimer = 0;
+ object.poison = () => {
+ object.poisoned = true;
+ object.elapsedPoisonedTimer = 0;
+ }
+
+ object.intersects = (other) => {
+ if (object.x + object.width <= other.x) {
+ return false;
+ }
+ if (object.x >= other.x + other.width) {
+ return false;
+ }
+ if (object.y + object.height <= other.y) {
+ return false;
+ }
+ if (object.y >= other.y + other.height) {
+ return false;
+ }
+ return true;
+ }
+
+ object.update = (elapsedTime) => {
+ if (object.poisoned && object.y >= game.height - object.height) {
+ object.elapsedPoisonedTimer += elapsedTime;
+ if (object.elapsedPoisonedTimer > object.poisonedTimer) {
+ object.poisoned = false;
+ object.elapsedPoisonedTimer = 0;
+ }
+ }
+
+ object.x += (object.poisoned ? 0 : object.dx)*elapsedTime;
+ object.y += (object.poisoned ? 0.2 : object.dy)*elapsedTime;
+ object.rot += object.drot*elapsedTime;
+ };
+
+ object.draw = (elapsedTime) => {
+ object.sprite.draw(elapsedTime, object);
+ };
+
+ return object;
+};
diff --git a/Homework/cs5410/centipede/js/game/objects/bullet.js b/Homework/cs5410/centipede/js/game/objects/bullet.js
new file mode 100644
index 0000000..5791aca
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/bullet.js
@@ -0,0 +1,11 @@
+game.Bullet = (spec) => {
+ const object = game.Object(spec);
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ if (object.y < 0) {
+ object.alive = false;
+ }
+ };
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/centipede.js b/Homework/cs5410/centipede/js/game/objects/centipede.js
new file mode 100644
index 0000000..7e4c8f6
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/centipede.js
@@ -0,0 +1,105 @@
+game.CentipedePiece = (spec) => {
+ const object = game.Object(spec);
+ object.poisonedTimer = 1000;
+ const parentUpdate = object.update;
+ object.turningState = {
+ turning: false,
+ turnDirectionY: 1,
+ objectStateBeforeTurn: null,
+ };
+ object.turn = () => {
+ object.turningState.objectStateBeforeTurn = {dx: object.dx, dy: object.dy, x: object.x, y: object.y};
+ object.turningState.turning = true;
+ if (object.y >= game.height - object.height) {
+ object.turningState.turnDirectionY = -1;
+ }
+ if (object.y <= 0) {
+ object.turningState.turnDirectionY = 1;
+ }
+ };
+ object.update = (elapsedTime) => {
+ if (object.poisoned) {
+ object.turningState.turning = false;
+ }
+ else if ((object.x+object.width > game.width || object.x < 0) && !object.turningState.turning) {
+ object.x = Math.min(Math.max(object.x, 0), game.width - object.width);
+ object.turn();
+ }
+ if (object.turningState.turning) {
+ object.dx = 0;
+ object.dy = Math.abs(object.turningState.objectStateBeforeTurn.dx) * object.turningState.turnDirectionY;
+ object.rot = object.dy > 0 ? -90 : 90;
+ if (Math.abs(object.turningState.objectStateBeforeTurn.y - object.y) >= object.height) {
+ object.y = object.turningState.objectStateBeforeTurn.y + object.height * object.turningState.turnDirectionY;
+ object.dx = -object.turningState.objectStateBeforeTurn.dx;
+ object.rot = object.dx > 0 ? 180 : 0;
+ object.dy = 0;
+ object.turningState.turning = false;
+ }
+ }
+ parentUpdate(elapsedTime);
+ object.y = Math.min(Math.max(object.y, 0), game.height - object.height);
+ };
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned && object.dy === 0) {
+ object.poison();
+ return;
+ }
+ if (!object.turningState.turning) {
+ if (mushroom.x < object.x && object.dx > 0) {
+ return;
+ }
+ object.turn();
+ }
+ }
+ return object;
+}
+
+game.Centipede = (spec) => {
+ const segments = [
+ ...Array(spec.segments).fill(0).map((_, i) => game.CentipedePiece({...spec, x: spec.startX - spec.width*(i+1), y: spec.startY, sprite: game.sprites.centipedeBody})),
+ game.CentipedePiece({...spec, x: spec.startX, y: spec.startY, sprite: game.sprites.centipedeHead}),
+ ];
+
+ const update = (elapsedTime) => {
+ segments.map((segment) => segment.update(elapsedTime));
+ }
+
+ const draw = (elapsedTime) => {
+ segments.map((segment) => segment.draw(elapsedTime));
+ }
+
+ const intersects = (object) => {
+ return segments.filter((segment) => segment.intersects(object)).length;
+ }
+
+ const onBulletCollision = (bullet) => {
+ if (bullet.alive) {
+ const segment = segments.find((segment) => segment.intersects(bullet));
+ const segmentIndex = segments.indexOf(segment);
+
+ const {mushX, mushY} = game.Mushroom.toMushCoords(segment);
+ game.explosions.push(game.Explosion({...game.Mushroom.toGameCoords({mushX, mushY}), width: segment.width, height: segment.height, sprite: game.sprites.explosionSmall}));
+ if (!game.mushrooms.find((mushroom) => mushroom.mushX === mushX && mushroom.mushY === mushY)) {
+ game.mushrooms.push(game.Mushroom({mushX, mushY, ...game.mushroomDims}));
+ }
+ game.score += segment.sprite === game.sprites.centipedeHead ? 20 : 5;
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ segments.splice(segmentIndex, 1);
+ }
+ bullet.alive = false;
+ }
+
+ const onMushroomCollision = (mushroom) => {
+ segments.find((segment) => segment.intersects(mushroom)).onMushroomCollision(mushroom);
+ }
+
+ const onPlayerCollision = (player) => {
+ player.kill();
+ }
+
+ const alive = () => segments.length ? true : false;
+
+ return {update, draw, segments, intersects, onBulletCollision, onMushroomCollision, onPlayerCollision, alive};
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/explosion.js b/Homework/cs5410/centipede/js/game/objects/explosion.js
new file mode 100644
index 0000000..f38d820
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/explosion.js
@@ -0,0 +1,14 @@
+game.Explosion = (spec) => {
+ const object = game.Object(spec);
+ let explosionTime = 0;
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ explosionTime += elapsedTime;
+
+ if (explosionTime > (object.sprite.numFrames * object.sprite.timePerFrame)) {
+ object.alive = false;
+ }
+ }
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/flea.js b/Homework/cs5410/centipede/js/game/objects/flea.js
new file mode 100644
index 0000000..23479cc
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/flea.js
@@ -0,0 +1,49 @@
+game.Flea = (spec) => {
+ const object = game.Object(spec);
+ const parentUpdate = object.update;
+ object.mushroomCoords = game.Mushroom.toMushCoords(object);
+ object.update = (elapsedTime) => {
+ const newMushroomCoords = game.Mushroom.toMushCoords(object);
+ if (newMushroomCoords.mushY !== object.mushroomCoords.mushY || newMushroomCoords.mushX !== object.mushroomCoords.mushX) {
+ if (Math.random() < Math.min(0.15 + 0.05*game.level, 0.7)) {
+ if (!game.mushrooms.find((mushroom) => mushroom.mushX === newMushroomCoords.mushX && mushroom.mushY === newMushroomCoords.mushY)) {
+ game.mushrooms.push(game.Mushroom({...newMushroomCoords, ...game.mushroomDims}));
+ }
+ }
+ object.mushroomCoords = newMushroomCoords;
+ }
+ parentUpdate(elapsedTime);
+ };
+
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned) {
+ mushroom.state = 0;
+ object.poison();
+ }
+ }
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionSmall}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 20;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ object.explode();
+ object.alive = false;
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/mushroom.js b/Homework/cs5410/centipede/js/game/objects/mushroom.js
new file mode 100644
index 0000000..b1f4787
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/mushroom.js
@@ -0,0 +1,43 @@
+game.Mushroom = (spec) => {
+ spec.state = spec.state ?? 4;
+ const {mushX, mushY} = spec;
+ const objectSpec = {...spec};
+ objectSpec.x = mushX * objectSpec.width;
+ objectSpec.y = mushY * objectSpec.height;
+ const object = {...spec, ...game.Object(objectSpec)};
+ object.onBulletCollision = (bullet) => {
+ if (bullet.alive) {
+ object.state--;
+ game.score += 5;
+ game.sounds.mushroom_hit.load();
+ game.sounds.mushroom_hit.play();
+ }
+ bullet.alive = false;
+ };
+ object.draw = (elapsedTime) => {
+ if (object.state) {
+ object.sprite = object.poisoned ? game.sprites.poisonMushrooms[object.state-1] : game.sprites.regularMushrooms[object.state-1];
+ object.sprite.draw(elapsedTime, object);
+ }
+ }
+ return object;
+};
+
+game.Mushroom.toMushCoords = (coords) => {
+ return {mushX: Math.ceil(coords.x / game.mushroomDims.width), mushY: Math.ceil(coords.y / game.mushroomDims.height)};
+}
+
+game.Mushroom.toGameCoords = (mushCoords) => {
+ return {x: mushCoords.mushX * game.mushroomDims.width, y: mushCoords.mushY * game.mushroomDims.height};
+}
+
+game.Mushroom.generateMushrooms = (mushroomSpec) => {
+ const mushPositions = new Set();
+ for (let i = 0; i < Math.max(Math.random(), 0.05) * game.height / mushroomSpec.height * game.width / mushroomSpec.width * game.level * 0.5; i++) {
+ mushPositions.add(JSON.stringify([Math.floor(Math.random() * game.width / mushroomSpec.width), Math.max(1, Math.floor(Math.random() * (game.height / mushroomSpec.height - 3)))]));
+ }
+ return Array.from(mushPositions).map((pos) => {
+ const [mushX, mushY] = JSON.parse(pos);
+ return game.Mushroom({...mushroomSpec, mushX, mushY});
+ });
+}
diff --git a/Homework/cs5410/centipede/js/game/objects/player.js b/Homework/cs5410/centipede/js/game/objects/player.js
new file mode 100644
index 0000000..a1f6ea0
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/player.js
@@ -0,0 +1,63 @@
+game.Player = (spec) => {
+ const object = game.Object(spec);
+ object.poisonedTimer = 4000;
+ object.elapsedPoisonedTimer = 0;
+ object.poisoned = false;
+ object.bulletTimer = spec.bulletTimer ?? 150;
+ object.maxPlayerHeight = spec.maxPlayerHeight ?? game.height - object.height*6;
+ object.elapsedBulletTimer = 0;
+ object.lives = spec.lives ?? 3;
+
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ object.x = Math.max(0, Math.min(object.x, game.width - object.width));
+ object.y = Math.max(object.maxPlayerHeight, Math.min(object.y, game.height - object.height));
+ object.dx = object.dy = 0;
+ object.elapsedBulletTimer += elapsedTime;
+ };
+ object.moveUp = () => {
+ object.dy = -0.75;
+ }
+ object.moveDown = () => {
+ object.dy = 0.75;
+ }
+ object.moveLeft = () => {
+ object.dx = -0.5;
+ }
+ object.moveRight = () => {
+ object.dx = 0.5;
+ }
+
+ object.shoot = () => {
+ if (object.elapsedBulletTimer > object.bulletTimer) {
+ object.elapsedBulletTimer = 0;
+ game.bullets.push(game.Bullet({x: object.x + object.width/2 - 5, y: object.y-object.height/2, dx: 0, dy: -1.5, width: 5, height: 50, sprite: game.sprites.bullet}));
+ game.sounds.laser.load();
+ game.sounds.laser.play();
+ }
+ }
+
+ object.onMushroomCollision = (mushroom) => {
+ if (mushroom.poisoned) {
+ mushroom.state = 0;
+ object.poison();
+ }
+ if (mushroom.x > object.x) {
+ object.x = mushroom.x - mushroom.width;
+ }
+ if (mushroom.x < object.x) {
+ object.x = mushroom.x + mushroom.width;
+ }
+ }
+
+ object.kill = () => {
+ object.lives--;
+ game.resetObjects();
+ if (object.lives == 0) {
+ game.gameOver();
+ }
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/scorpion.js b/Homework/cs5410/centipede/js/game/objects/scorpion.js
new file mode 100644
index 0000000..036db14
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/scorpion.js
@@ -0,0 +1,32 @@
+game.Scorpion = (spec) => {
+ const object = game.Object(spec);
+
+ const parentUpdate = object.update;
+ object.update = (elapsedTime) => {
+ parentUpdate(elapsedTime);
+ };
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionBig}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 100;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ object.onMushroomCollision = (mushroom) => {
+ mushroom.poisoned = true;
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/objects/spider.js b/Homework/cs5410/centipede/js/game/objects/spider.js
new file mode 100644
index 0000000..732c0a3
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/objects/spider.js
@@ -0,0 +1,45 @@
+game.Spider = (spec) => {
+ const object = game.Object(spec);
+
+ const parentUpdate = object.update;
+
+ object.randomizeVel = () => {
+ object.dx = Math.min(Math.random(), 0.25 + 0.05*game.level) * (Math.random() > 0.5 ? 1 : -1);
+ object.dy = Math.min(Math.random(), 0.25 + 0.05*game.level) * (Math.random() > 0.5 ? 1 : -1);
+ }
+
+ object.update = (elapsedTime) => {
+ if (Math.random() < 0.01*game.level) {
+ object.randomizeVel();
+ }
+ if (object.x < 0 || object.x > game.width - object.width) {
+ object.dx = -object.dx;
+ }
+ if (object.y < 0 || object.y > game.height - object.height) {
+ object.dy = -object.dy;
+ }
+ object.x = Math.max(0, Math.min(game.width - object.width, object.x));
+ object.y = Math.max(0, Math.min(game.height - object.height, object.y));
+ parentUpdate(elapsedTime);
+ };
+
+ object.explode = () => {
+ game.explosions.push(game.Explosion({x: object.x, y: object.y, width: object.width, height: object.height, sprite: game.sprites.explosionBig}));
+ game.sounds.enemy_hit.load();
+ game.sounds.enemy_hit.play();
+ }
+
+ object.onBulletCollision = (bullet) => {
+ game.score += 150;
+ object.alive = false;
+ object.explode();
+ }
+
+ object.onPlayerCollision = (player) => {
+ object.alive = false;
+ player.kill();
+ object.explode();
+ }
+
+ return object;
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/sounds.js b/Homework/cs5410/centipede/js/game/sounds.js
new file mode 100644
index 0000000..584dbd3
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/sounds.js
@@ -0,0 +1,5 @@
+game.sounds = {
+ mushroom_hit: new Audio("assets/sounds/mushroom_hit.wav"),
+ enemy_hit: new Audio("assets/sounds/enemy_hit.wav"),
+ laser: new Audio("assets/sounds/laser.wav"),
+} \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/game/sprites.js b/Homework/cs5410/centipede/js/game/sprites.js
new file mode 100644
index 0000000..3cdd77f
--- /dev/null
+++ b/Homework/cs5410/centipede/js/game/sprites.js
@@ -0,0 +1,120 @@
+game.sprites = {
+ centipedeHead: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 0,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ numFrames: 4,
+ timePerFrame: 100,
+ }),
+ centipedeBody: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 80,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ numFrames: 4,
+ timePerFrame: 100,
+ }),
+ spider: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 160,
+ spriteWidth: 80,
+ spriteHeight: 40,
+ numFrames: 8,
+ timePerFrame: 100,
+ cols: 4,
+ rows: 2,
+ }),
+ flea: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 320,
+ spriteY: 160,
+ spriteWidth: 45,
+ spriteHeight: 40,
+ numFrames: 4,
+ timePerFrame: 500,
+ cols: 2,
+ rows: 2,
+ }),
+ scorpion: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 280,
+ spriteWidth: 80,
+ spriteHeight: 40,
+ numFrames: 4,
+ timePerFrame: 500,
+ cols: 4,
+ }),
+ ship: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 400,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ numFrames: 1,
+ timePerFrame: 0,
+ cols: 1,
+ rows: 1
+ }),
+ bullet: game.graphics.Sprite({
+ drawFunction: (_elapsedTime, {x, y, rot, width, height}, context) => {
+ context.save();
+ context.translate(x+width/2, y+height/2);
+ context.rotate(rot * Math.PI / 180);
+ context.translate(-x-width/2, -y-height/2);
+ const fillStyle = context.fillStyle;
+ context.fillStyle = "#FF0000";
+ context.fillRect(x, y, width, height);
+ context.fillStyle = fillStyle;
+ context.restore();
+ }
+ }),
+ explosionBig: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 0,
+ spriteY: 320,
+ numFrames: 8,
+ spriteWidth: 80,
+ spriteHeight: 40,
+ cols: 4,
+ rows: 2,
+ timePerFrame: 30,
+ }),
+ explosionSmall: game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 320,
+ spriteY: 320,
+ numFrames: 6,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ cols: 3,
+ rows: 2,
+ timePerFrame: 30,
+ }),
+ regularMushrooms: [3,2,1,0].map(i =>
+ game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 320 + i*40,
+ spriteY: 0,
+ numFrames: 1,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ timePerFrame: 0,
+ })
+ ),
+ poisonMushrooms: [3,2,1,0].map(i =>
+ game.graphics.Sprite({
+ sheetSrc: "assets/images/centipede-assets.png",
+ spriteX: 320 + i*40,
+ spriteY: 40,
+ numFrames: 1,
+ spriteWidth: 40,
+ spriteHeight: 40,
+ timePerFrame: 0,
+ })
+ )
+}; \ No newline at end of file
diff --git a/Homework/cs5410/centipede/js/main.js b/Homework/cs5410/centipede/js/main.js
new file mode 100644
index 0000000..f4c954d
--- /dev/null
+++ b/Homework/cs5410/centipede/js/main.js
@@ -0,0 +1,75 @@
+let handleInput;
+const initialize = () => {
+ game.level = 1;
+ game.score = 0;
+ game.totalTime = 0;
+
+ game.keyboard = game.input.Keyboard();
+ handleInput = game.keyboard.update;
+
+ game.lastTimeStamp = performance.now();
+
+ game.player = game.Player({x: game.width/2 - 20, y: game.height-40, width: 40, height: 40, sprite: game.sprites.ship});
+
+ game.resetObjects();
+};
+
+const update = (elapsedTime) => {
+ game.totalTime += elapsedTime;
+
+ game.mushrooms.map((mushroom) => game.getMushroomCollidableObjects().filter((object) => object.intersects(mushroom))).map((objects, i) => {
+ objects.map((object => object.onMushroomCollision ? object.onMushroomCollision(game.mushrooms[i]) : null));
+ });
+ game.bullets.map((bullet) => game.getBulletCollidableObjects().filter((object) => object.intersects(bullet))).map((objects, i) => {
+ objects.map((object) => object.onBulletCollision ? object.onBulletCollision(game.bullets[i]) : null)
+ })
+ game.getPlayerCollidableObjects().map((object) => object.intersects(game.player) ? object.onPlayerCollision(game.player) : null);
+
+ game.bullets = game.bullets.filter((bullet) => bullet.alive);
+ game.spiders = game.spiders.filter((spider) => spider.alive);
+ game.explosions = game.explosions.filter((explosion) => explosion.alive);
+ game.mushrooms = game.mushrooms.filter((mushroom) => mushroom.state > 0);
+ game.scorpions = game.scorpions.filter((scorpion) => scorpion.x >= 0 && scorpion.x <= game.width - scorpion.width && scorpion.alive);
+ game.fleas = game.fleas.filter((flea) => flea.y < game.height - flea.height && flea.alive);
+ game.getObjects().map((object) => object.update(elapsedTime));
+
+ if (Math.random() < 0.002 * game.level && game.spiders.length < game.level) {
+ game.spiders.push(game.Spider({x: game.width/2, y: 0, width: 80, height: 40, rot: 0, dx: -0.2, dy: 0, sprite: game.sprites.spider}));
+ }
+ if (Math.random() < 0.001 * game.level && game.fleas.length < game.level) {
+ game.fleas.push(game.Flea({x: Math.floor(Math.random() * game.width / game.mushroomDims.width) * game.mushroomDims.width, y: 0, width: 40, height: 40, rot: 0, dx: 0, dy: 0.2, sprite: game.sprites.flea}));
+ }
+ if (Math.random() < 0.001 * game.level && game.scorpions.length < game.level) {
+ game.scorpions.push(game.Scorpion({y: Math.floor(Math.random() * game.height / game.mushroomDims.height) * game.mushroomDims.height, x: 0, width: 80, height: 40, rot: 0, dx: 0.2, dy: 0, sprite: game.sprites.scorpion}));
+ }
+
+ if (!game.centipede.alive()) {
+ game.resetObjects();
+ game.level++;
+ game.score += game.level*400;
+ }
+};
+
+const render = (elapsedTime) => {
+ game.graphics.clear();
+ game.getObjects().map((object) => object.draw(elapsedTime));
+
+ document.getElementById("hud").innerHTML = `Level: ${game.level} Lives: ${game.player.lives} Score: ${game.score} ${game.player.poisoned ? "<span style='color:green'>POISONED<span>" : ""}`;
+};
+
+const gameLoop = (time) => {
+ const elapsedTime = time - game.lastTimeStamp;
+ game.lastTimeStamp = time;
+
+ handleInput(elapsedTime);
+ update(elapsedTime);
+ render(elapsedTime);
+
+ if (!game.stopped) {
+ requestAnimationFrame(gameLoop);
+ }
+};
+
+initialize();
+menu.reRegisterKeys();
+requestAnimationFrame(gameLoop); \ No newline at end of file
diff --git a/Homework/cs5410/maize-maze/LICENSE.md b/Homework/cs5410/maize-maze/LICENSE.md
new file mode 100644
index 0000000..47a36cd
--- /dev/null
+++ b/Homework/cs5410/maize-maze/LICENSE.md
@@ -0,0 +1,21 @@
+Copyright (c) 2012-2022 Scott Chacon and others
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/Homework/cs5410/maize-maze/README.md b/Homework/cs5410/maize-maze/README.md
new file mode 100644
index 0000000..d48c881
--- /dev/null
+++ b/Homework/cs5410/maize-maze/README.md
@@ -0,0 +1,9 @@
+# A Simple Maze Game
+
+Controls:
++ Arrow-keys / WASD / IJKL
++ h to toggle hint
++ p to toggle path
++ b to toggle breadcrumbs
+
+![Screenshot](./screenshot.png)
diff --git a/Homework/cs5410/maize-maze/css/styles.css b/Homework/cs5410/maize-maze/css/styles.css
new file mode 100644
index 0000000..4c8aac0
--- /dev/null
+++ b/Homework/cs5410/maize-maze/css/styles.css
@@ -0,0 +1,24 @@
+body {
+ margin: 0;
+ padding: 0;
+ overflow: scroll;
+ /* Font from https://www.cssfontstack.com/Lucida-Console */
+ font-family: Lucida Console,Lucida Sans Typewriter,monaco,Bitstream Vera Sans Mono,monospace;
+ background: radial-gradient(circle, transparent 20%, black 80vw), white;
+}
+
+.canvas-holder canvas {
+ padding: 0;
+ margin: auto;
+ display: block;
+ height: 70vh;
+ width: auto;
+ max-width: 100%;
+}
+
+.button {
+ border: 1px solid black;
+ border-radius: 5px;
+ padding: 5px;
+ cursor: pointer;
+} \ No newline at end of file
diff --git a/Homework/cs5410/maize-maze/images/corn.png b/Homework/cs5410/maize-maze/images/corn.png
new file mode 100644
index 0000000..f392216
--- /dev/null
+++ b/Homework/cs5410/maize-maze/images/corn.png
Binary files differ
diff --git a/Homework/cs5410/maize-maze/images/fire.png b/Homework/cs5410/maize-maze/images/fire.png
new file mode 100644
index 0000000..5e7b2ec
--- /dev/null
+++ b/Homework/cs5410/maize-maze/images/fire.png
Binary files differ
diff --git a/Homework/cs5410/maize-maze/images/popcorn.jpg b/Homework/cs5410/maize-maze/images/popcorn.jpg
new file mode 100644
index 0000000..ad73e91
--- /dev/null
+++ b/Homework/cs5410/maize-maze/images/popcorn.jpg
Binary files differ
diff --git a/Homework/cs5410/maize-maze/index.html b/Homework/cs5410/maize-maze/index.html
new file mode 100644
index 0000000..36bae40
--- /dev/null
+++ b/Homework/cs5410/maize-maze/index.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Amazeing Maize Maze</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
+ <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
+ <link href="css/styles.css" rel="stylesheet">
+ </head>
+ <body>
+
+ <div class="modal fade" id="help-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h5 class="modal-title" id="exampleModalLabel">Controls</h5>
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <ul>
+ <li>
+ Move with arrow keys, WASD, or IJKL
+ </li>
+ <li>
+ h to toggle a hint
+ </li>
+ <li>
+ p to toggle the shortest path
+ </li>
+ <li>
+ b to toggle breadcrumbs
+ </li>
+ </ul>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div style="text-align: center">
+ <h1>The A-maze-ing Maize Maze!</h1>
+ <p>Get to the fire to make popcorn! Current Time: <span style="color: green; font-size:24px" id="elapsed-time"></span> seconds</p>
+ <p>
+ <button type="button" class="button" data-toggle="modal" data-target="#help-modal">
+ Show me the controls!
+ </button>
+ </p>
+ <p>
+ <a onclick="initialize(5)" class="button">5x5</a>
+ <a onclick="initialize(10)" class="button">10x10</a>
+ <a onclick="initialize(15)" class="button">15x15</a>
+ <a onclick="initialize(20)" class="button">20x20</a>
+ </p>
+ </div>
+ <div class="canvas-holder">
+ <canvas id="canvas" width="1000" height="1000"></canvas>
+ </div>
+ <div style="text-align: center;">
+ <br>
+ "Low" scores (player path length - shortest path length):
+ <div id="scores" style="max-height: 5vh; overflow-y: scroll"></div>
+ </div>
+ <script src="js/assets.js"></script>
+ <script src="js/helpers.js"></script>
+ <script src="js/json-ds.js"></script>
+ <script src="js/keyboard.js"></script>
+ <script src="js/maze.js"></script>
+ <script src="js/game.js"></script>
+ </body>
+</html>
diff --git a/Homework/cs5410/maize-maze/js/assets.js b/Homework/cs5410/maize-maze/js/assets.js
new file mode 100644
index 0000000..54ea6bb
--- /dev/null
+++ b/Homework/cs5410/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/Homework/cs5410/maize-maze/js/game.js b/Homework/cs5410/maize-maze/js/game.js
new file mode 100644
index 0000000..1249a20
--- /dev/null
+++ b/Homework/cs5410/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/Homework/cs5410/maize-maze/js/helpers.js b/Homework/cs5410/maize-maze/js/helpers.js
new file mode 100644
index 0000000..1bc6579
--- /dev/null
+++ b/Homework/cs5410/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/Homework/cs5410/maize-maze/js/json-ds.js b/Homework/cs5410/maize-maze/js/json-ds.js
new file mode 100644
index 0000000..feb0622
--- /dev/null
+++ b/Homework/cs5410/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/Homework/cs5410/maize-maze/js/keyboard.js b/Homework/cs5410/maize-maze/js/keyboard.js
new file mode 100644
index 0000000..2196834
--- /dev/null
+++ b/Homework/cs5410/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/Homework/cs5410/maize-maze/js/maze.js b/Homework/cs5410/maize-maze/js/maze.js
new file mode 100644
index 0000000..8bede6b
--- /dev/null
+++ b/Homework/cs5410/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);
+ }
+ }
+ }
+}
diff --git a/Homework/cs5410/maize-maze/screenshot.png b/Homework/cs5410/maize-maze/screenshot.png
new file mode 100644
index 0000000..965eb61
--- /dev/null
+++ b/Homework/cs5410/maize-maze/screenshot.png
Binary files differ