Skip to content

Instantly share code, notes, and snippets.

@quintuple-mallard
Created August 12, 2025 08:37
Show Gist options
  • Select an option

  • Save quintuple-mallard/c6cbc5318508023e58d9174b2d1124e2 to your computer and use it in GitHub Desktop.

Select an option

Save quintuple-mallard/c6cbc5318508023e58d9174b2d1124e2 to your computer and use it in GitHub Desktop.
Maze Promises
<!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>
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()
})
: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