lab 01
This commit is contained in:
4 files changed
+363
No files matched your search
@@ -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;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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();
|
||||||
@@ -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!"
|
||||||
|
};
|
||||||
Reference in new issue
Block a user