Created
August 12, 2025 08:37
-
-
Save quintuple-mallard/c6cbc5318508023e58d9174b2d1124e2 to your computer and use it in GitHub Desktop.
Maze Promises
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <link rel="stylesheet" href="style.css" /> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Document</title> | |
| </head> | |
| <body> | |
| <main> | |
| <div id="maze"> | |
| <div class="cell start"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell wall"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell space"></div> | |
| <div class="cell target"></div> | |
| <div id="blob"> | |
| <div class="eye left"></div> | |
| <div class="eye right"></div> | |
| </div> | |
| </div> | |
| <div id="won-screen">You won</div> | |
| <div id="lost-screen">You lost</div> | |
| </main> | |
| </body> | |
| <script src="script.js"></script> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const cellsPerRow = 7; | |
| const blob = { | |
| elem: document.querySelector("#blob"), | |
| row: 0, | |
| col: 0, | |
| direction: "down" | |
| } | |
| function getCellAt(row, col) { | |
| // We use +1 because nth-child is one-based but | |
| // our counting is zero-based. | |
| const idx = (row * cellsPerRow) + col + 1 | |
| return document.querySelector(`.cell:nth-child(${idx})`) | |
| } | |
| function cellEnterable(row, col) { | |
| if(row < 0 || col < 0) { return false } | |
| if(row >= cellsPerRow || col >= cellsPerRow) { return false } | |
| const cell = getCellAt(row, col) | |
| return ['space', 'start', 'target'] | |
| .some((cls) => cell.classList.contains(cls)) | |
| } | |
| function move() { | |
| return new Promise((resolve, reject) => { | |
| if(blob.direction == "down") { | |
| blob.row += 1; | |
| } else if(blob.direction == "up") { | |
| blob.row -= 1; | |
| } else if (blob.direction == "right") { | |
| blob.col += 1 | |
| } else if (blob.direction == "left") { | |
| blob.col -= 1 | |
| } | |
| if(!cellEnterable(blob.row, blob.col)) { | |
| reject() | |
| } | |
| blob.elem.addEventListener('transitionend', resolve) | |
| blob.elem.style.setProperty('--cell-row', blob.row) | |
| blob.elem.style.setProperty('--cell-col', blob.col) | |
| }) | |
| } | |
| function turnLeft() { | |
| return new Promise((resolve, reject) => { | |
| if(blob.direction == "up") { | |
| blob.direction = "left" | |
| } else if(blob.direction == "down") { | |
| blob.direction = "right" | |
| } else if (blob.direction == "right") { | |
| blob.direction = "up" | |
| } else if (blob.direction == "left") { | |
| blob.direction = "down" | |
| } | |
| const rotation = parseInt( | |
| getComputedStyle(blob.elem).getPropertyValue('--rotation') | |
| ) - 90 | |
| blob.elem.addEventListener('transitionend', resolve) | |
| blob.elem.style.setProperty('--rotation', `${rotation}deg`) | |
| }) | |
| } | |
| function turnRight() { | |
| return new Promise((resolve, reject) => { | |
| if(blob.direction == "up") { | |
| blob.direction = "right" | |
| } else if(blob.direction == "down") { | |
| blob.direction = "left" | |
| } else if (blob.direction == "right") { | |
| blob.direction = "down" | |
| } else if (blob.direction == "left") { | |
| blob.direction = "up" | |
| } | |
| const rotation = parseInt( | |
| getComputedStyle(blob.elem).getPropertyValue('--rotation') | |
| ) + 90 | |
| blob.elem.addEventListener('transitionend', resolve) | |
| blob.elem.style.setProperty('--rotation', `${rotation}deg`) | |
| }) | |
| } | |
| function showWinScreen() { | |
| document.querySelector('#won-screen').style.display = "grid" | |
| } | |
| function showLostScreen() { | |
| document.querySelector('#lost-screen').style.display = "grid" | |
| } | |
| function checkForWin() { | |
| if(getCellAt(blob.row, blob.col).classList.contains("target")) { | |
| showWinScreen() | |
| } | |
| else { | |
| showLostScreen() | |
| } | |
| } | |
| move().then(move) | |
| .then(turnLeft) | |
| .then(move) | |
| .then(move) | |
| .then(turnLeft) | |
| .then(move) | |
| .then(move) | |
| .then(turnRight) | |
| .then(move) | |
| .then(move) | |
| .then(turnRight) | |
| .then(move) | |
| .then(move) | |
| .then(move) | |
| .then(move) | |
| .then(move) | |
| .then(move) | |
| .then(turnLeft) | |
| .then(move) | |
| .then(move) | |
| .then(checkForWin) | |
| .catch(() => { | |
| showLostScreen() | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| :root { | |
| --num-cols: 7; | |
| --cell-size: calc(100% / var(--num-cols)); | |
| } | |
| body { | |
| background: black; | |
| } | |
| main { | |
| background:white; | |
| height:80vmin; | |
| width:80vmin; | |
| margin: 10vmin auto; | |
| } | |
| #maze { | |
| height:100%; | |
| display:grid; | |
| grid-template-columns: repeat(var(--num-cols), 1fr); | |
| position: relative; | |
| } | |
| .cell { | |
| border:1px solid black; | |
| &.start { | |
| background: #e4e6ff; | |
| } | |
| &.target { | |
| background: limegreen; | |
| } | |
| &.wall { | |
| background: #f9dcdc; | |
| } | |
| } | |
| #blob { | |
| --size: calc(var(--cell-size) / 5 * 3); | |
| --spacing: calc(var(--cell-size) / 5 * 1); | |
| --cell-row: 0; | |
| --cell-col: 0; | |
| --rotation: 0deg; | |
| width: var(--size); | |
| height: var(--size); | |
| margin: var(--spacing); | |
| top: calc(var(--cell-size) * var(--cell-row)); | |
| left: calc(var(--cell-size) * var(--cell-col)); | |
| rotate: var(--rotation); | |
| position: absolute; | |
| background:blue; | |
| border-radius:100%; | |
| transition: all 0.5s; | |
| .eye { | |
| content: ""; | |
| position:absolute; | |
| width:30%; | |
| height:30%; | |
| background:black; | |
| border-radius:100%; | |
| bottom:-15%; | |
| display:grid; | |
| place-items:center; | |
| &:before { | |
| content: ""; | |
| border-radius:100%; | |
| background:white; | |
| width:25%; | |
| height:25%; | |
| } | |
| &.left { | |
| left:10%; | |
| } | |
| &.right { | |
| right:10%; | |
| } | |
| } | |
| } | |
| #won-screen, #lost-screen { | |
| position:absolute; | |
| inset:0; | |
| font-size: 20vmin; | |
| display:grid; | |
| place-items:center; | |
| color:black; | |
| font-weight:bold; | |
| } | |
| #lost-screen { | |
| background:rgba(255,0,0, 0.5); | |
| display:none; | |
| } | |
| #won-screen { | |
| background:rgba(0,255,0, 0.5); | |
| display:none; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment