This commit is contained in:
SowinskiBraeden committed 2026-09-13 12:27:49 -07:00
commit 4a486480ed
4 files changed
+363

No files matched your search

+39
View File
@@ -0,0 +1,39 @@
#count-input {
width: 12em;
}
#go-button {
width: 3.5em;
}
#game-area {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 1rem;
}
.memory-button {
color: black;
/*font-size: 16px;*/
font-weight: 600;
width: 10em;
height: 5em;
}
.memory-button:not(:disabled):hover {
cursor: pointer;
}
/* hide arrows on input */
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<main>
<section id="controls">
<div>
<label id="count-label" for="count-input"></label>
</div>
<input
id="count-input"
type="number"
min="3"
max="7"
step="1"
>
<button id="go-button"></button>
<p id="message"></p>
</section>
<section id="game-area"></section>
</main>
<script type="module" src="./js/script.js"></script>
</body>
</html>
+283
View File
@@ -0,0 +1,283 @@
import { STRINGS } from "../lang/messages/en/user.js";
class MemoryGame {
constructor(ui) {
this.ui = ui;
this.buttons = [];
this.buttonCount = 0;
this.expectedOrder = 1;
this.gameId = 0;
}
start() {
this.ui.setGoHandler(() => {
this.handleGo();
});
}
handleGo() {
this.ui.clearMessage();
const count = this.ui.getButtonCount();
if (!this.validateInput(count)) {
this.ui.showMessage(STRINGS.INVALID_INPUT);
return;
}
this.resetGame();
this.buttonCount = count;
this.createButtons();
this.runGame(this.gameId);
}
validateInput(count) {
return Number.isInteger(count) && count >= 3 && count <= 7;
}
resetGame() {
this.gameId++;
this.buttons = [];
this.buttonCount = 0;
this.expectedOrder = 1;
this.ui.clearGameArea();
}
createButtons() {
MemoryButton.resetColorPool();
for (let i = 1; i <= this.buttonCount; i++) {
const button = new MemoryButton(i, (clickedButton) => {
this.handleButtonClick(clickedButton);
});
button.disable();
this.buttons.push(button);
this.ui.addGameButton(button.getElement());
}
}
async runGame(currentGameId) {
// memorize time
await this.delay(this.buttonCount * 1000);
if (currentGameId !== this.gameId) {
return;
}
// move buttons every two seconds, n times.
for (let i = 0; i < this.buttonCount; i++) {
await this.delay(2000);
if (currentGameId !== this.gameId) {
return;
}
this.scrambleButtons();
}
this.hideAllNumbers();
this.enableAllButtons();
}
scrambleButtons() {
for (const button of this.buttons) {
button.randomPosition();
}
}
hideAllNumbers() {
for (const button of this.buttons) {
button.hideNumber();
}
}
revealAllButtons() {
for (const button of this.buttons) {
button.showNumber();
}
}
enableAllButtons() {
for (const button of this.buttons) {
button.enable();
}
}
disableAllButtons() {
for (const button of this.buttons) {
button.disable();
}
}
handleButtonClick(button) {
if (button.order === this.expectedOrder) {
this.handleCorrectClick(button);
} else {
this.handleWrongClick();
}
}
handleCorrectClick(button) {
button.showNumber();
button.disable();
this.expectedOrder++;
if (this.expectedOrder > this.buttonCount) {
this.handleWin();
}
}
handleWrongClick() {
this.revealAllButtons();
this.disableAllButtons();
this.ui.showMessage(STRINGS.WRONG_ORDER);
}
handleWin() {
this.disableAllButtons();
this.ui.showMessage(STRINGS.SUCCESS);
}
delay(milliseconds) {
return new Promise((resolve) => {
setTimeout(resolve, milliseconds);
});
}
}
class MemoryButton {
static COLORS = [
"#ef5350",
"#ffa726",
"#ffee58",
"#66bb6a",
"#26c6da",
"#5c6bc0",
"#ab47bc",
];
static colorPool = [];
static resetColorPool() {
// prevent original COLORS to be modified
MemoryButton.colorPool = [...MemoryButton.COLORS];
}
static randomColor() {
const idx = Math.floor(
Math.random() * MemoryButton.colorPool.length
);
// remove and return one color
return MemoryButton.colorPool.splice(idx, 1)[0];
}
constructor(order, clickHandler) {
this.order = order;
this.element = document.createElement("button");
this.element.classList.add("memory-button");
this.element.style.backgroundColor = MemoryButton.randomColor();
this.element.textContent = this.order;
this.element.addEventListener("click", () => {
clickHandler(this);
});
}
getElement() {
return this.element;
}
showNumber() {
this.element.textContent = this.order;
}
hideNumber() {
this.element.textContent = "";
}
enable() {
this.element.disabled = false;
}
disable() {
this.element.disabled = true;
}
randomPosition() {
const viewportWidth = document.documentElement.clientWidth;
const viewportHeight = document.documentElement.clientHeight;
const rect = this.element.getBoundingClientRect();
const maxX = Math.max(0, viewportWidth - rect.width);
const maxY = Math.max(0, viewportHeight - rect.height);
const x = Math.floor(Math.random() * (maxX + 1));
const y = Math.floor(Math.random() * (maxY + 1));
this.element.style.position = "fixed";
this.element.style.left = `${x}px`;
this.element.style.top = `${y}px`;
}
}
class UIManager {
constructor() {
this.input = document.getElementById("count-input");
this.goButton = document.getElementById("go-button");
this.message = document.getElementById("message");
this.gameArea = document.getElementById("game-area");
this.countLabel = document.getElementById("count-label");
}
init() {
document.title = STRINGS.PAGE_TITLE;
this.countLabel.textContent = STRINGS.INPUT_LABEL;
this.goButton.textContent = STRINGS.GO_BUTTON;
}
getButtonCount() {
return Number(this.input.value);
}
setGoHandler(callback) {
this.goButton.addEventListener("click", callback);
}
showMessage(message) {
this.message.textContent = message;
}
clearMessage() {
this.message.textContent = "";
}
clearGameArea() {
this.gameArea.replaceChildren();
}
addGameButton(element) {
this.gameArea.appendChild(element);
}
}
const ui = new UIManager();
const game = new MemoryGame(ui);
ui.init();
game.start();
+8
View File
@@ -0,0 +1,8 @@
export const STRINGS = {
PAGE_TITLE: "Memory Game",
INPUT_LABEL: "How many buttons to create?",
GO_BUTTON: "Go!",
INVALID_INPUT: "Please enter an integer between 3 and 7.",
SUCCESS: "Excellent memory!",
WRONG_ORDER: "Wrong order!"
};