commit 4a486480ed0899653cfb4d248c3e6e4952b98843 Author: Braeden Sowinski Date: Sun Sep 13 12:27:49 2026 -0700 lab 01 diff --git a/labs/01/css/style.css b/labs/01/css/style.css new file mode 100644 index 0000000..29ea05b --- /dev/null +++ b/labs/01/css/style.css @@ -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; +} diff --git a/labs/01/index.html b/labs/01/index.html new file mode 100644 index 0000000..1f7c9a2 --- /dev/null +++ b/labs/01/index.html @@ -0,0 +1,33 @@ + + + + + + + + + +
+
+
+ +
+ + + + +

+
+ +
+
+ + + + diff --git a/labs/01/js/script.js b/labs/01/js/script.js new file mode 100644 index 0000000..24180cb --- /dev/null +++ b/labs/01/js/script.js @@ -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(); diff --git a/labs/01/lang/messages/en/user.js b/labs/01/lang/messages/en/user.js new file mode 100644 index 0000000..ffbd41c --- /dev/null +++ b/labs/01/lang/messages/en/user.js @@ -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!" +};