diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a799fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +_site/ diff --git a/assets/scripts/controllers/keyboard.js b/assets/scripts/controllers/keyboard.js new file mode 100644 index 0000000..f1daf77 --- /dev/null +++ b/assets/scripts/controllers/keyboard.js @@ -0,0 +1,42 @@ +import { Controller } from "https://unpkg.com/@hotwired/stimulus@v3.2.2/dist/stimulus.js"; + +import { MARKERS, GameController } from "../models/gamecontroller.js"; + +export default class extends Controller { + static targets = [ "key" ]; + static outlets = [ "playfield" ]; + + tappedKey(ev) { + ev.preventDefault(); + + let key = ev.target.dataset["key"]; + this.playfieldOutlet.tappedKey(key); + } + + colorizeKeys(ev) { + let hits = ev.detail.hits; + + for (let k in hits) { + let thisKey = k.toLowerCase(); + let marker = hits[k]; + + let keyElement = this.keyTargets.filter((e) => e.dataset.key == thisKey)[0]; + switch (marker) { + case MARKERS.RIGHT_POS: + keyElement.classList.value = "right-pos"; + break; + case MARKERS.RIGHT_CHAR: + if (!keyElement.classList.contains("right-pos")) { + keyElement.classList.add("right-char"); + } + break; + case MARKERS.MISS: + if (keyElement.classList.length == 0) { + keyElement.classList.add("miss"); + } + break; + } + } + + } +} \ No newline at end of file diff --git a/assets/scripts/controllers/playfield.js b/assets/scripts/controllers/playfield.js new file mode 100644 index 0000000..913a7d1 --- /dev/null +++ b/assets/scripts/controllers/playfield.js @@ -0,0 +1,81 @@ +import { Controller } from "https://unpkg.com/@hotwired/stimulus@v3.2.2/dist/stimulus.js" + +import { MARKERS, GameController } from "../models/gamecontroller.js"; + +export default class extends Controller { + static targets = ["row"]; + + connect() { + this._gameController = new GameController(); + + this._activeRowIndex = 0; + this._activeLetter = 0; + + this._buildPlayfield(this._gameController.guesses(), this._gameController.wordLength()); + } + + tappedKey(key) { + console.log(`Key ${key} was tapped via outliet`); + + this._addLetter(key); + } + + _addLetter(letter) { + let rowElem = this.rowTargets[this._activeRowIndex]; + let colElem = rowElem.querySelectorAll("span")[this._activeLetter]; + + colElem.innerText = letter.toUpperCase(); + + this._activeLetter += 1; + if (this._activeLetter >= this._gameController.wordLength()) { + this._colorizeRow(rowElem); + + this._activeRowIndex += 1; + this._activeLetter = 0; + } + } + + _buildPlayfield(rows, wordLength) { + let newRows = []; + for (let r = 0; r < rows; r++) { + let divElem = document.createElement("div"); + divElem.classList.add("row"); + divElem.setAttribute("data-playfield-target", "row"); + + for (let c = 0; c < wordLength; c++) { + let letterSpan = document.createElement("span"); + divElem.appendChild(letterSpan); + } + + newRows.push(divElem); + } + + this.element.replaceChildren.apply(this.element, newRows); + } + + _colorizeRow(row) { + let guessedWord = Array.from(row.querySelectorAll("span")).map((x) => x.innerText).join(""); + console.log("The guessed word is: " + guessedWord); + + let results = this._gameController.checkGuess(guessedWord); + let markers = results.markers; + + for (let i = 0; i < this._gameController.wordLength(); i++) { + switch (markers[i]) { + case MARKERS.RIGHT_POS: + row.children[i].classList.add("right-pos"); + break; + case MARKERS.RIGHT_CHAR: + row.children[i].classList.add("right-char"); + break; + case MARKERS.MISS: + row.children[i].classList.add("miss"); + break; + } + } + + window.dispatchEvent(new CustomEvent("guessResults", { + detail: results + })); + } +} \ No newline at end of file diff --git a/assets/scripts/main.js b/assets/scripts/main.js new file mode 100644 index 0000000..5da7dea --- /dev/null +++ b/assets/scripts/main.js @@ -0,0 +1,12 @@ +import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus@v3.2.2/dist/stimulus.js" + +import "./models/gamecontroller.js"; + +import PlayfieldController from "./controllers/playfield.js"; +import KeyboardController from "./controllers/keyboard.js"; + + +window.Stimulus = Application.start(); + +Stimulus.register("playfield", PlayfieldController); +Stimulus.register("keyboard", KeyboardController); \ No newline at end of file diff --git a/assets/scripts/models/gamecontroller.js b/assets/scripts/models/gamecontroller.js new file mode 100644 index 0000000..05b0b98 --- /dev/null +++ b/assets/scripts/models/gamecontroller.js @@ -0,0 +1,71 @@ +export const MARKERS = { + MISS: 'm', + RIGHT_POS: 'g', + RIGHT_CHAR: 'y' +}; + +export class GameController { + constructor() { + this._currentWord = "DEERS"; + this._guesses = 5; + } + + wordLength() { + return this._currentWord.length; + } + + guesses() { + return this._guesses; + } + + checkGuess(guess) { + if (guess.length != this._currentWord.length) { + throw Error(`Expected length to be ${this._currentWord.length} but was ${guess.length}`); + } + + // Check correct placements + let markers = new Array(guess.length); + let misses = {}; + let hits = {}; + + for (let i = 0; i < guess.length; i++) { + if (guess[i] == this._currentWord[i]) { + markers[i] = MARKERS.RIGHT_POS; + hits[guess[i]] = MARKERS.RIGHT_POS; + } else { + if (this._currentWord[i] in misses) { + misses[this._currentWord[i]] += 1; + } else { + misses[this._currentWord[i]] = 1; + } + } + } + + // Check words that are wrong placement but are in the word + // Distribute based on the words position + for (let i = 0; i < guess.length; i++) { + if (markers[i]) { + continue; + } + + if (misses[guess[i]] && misses[guess[i]] > 0) { + misses[guess[i]] -= 1; + markers[i] = MARKERS.RIGHT_CHAR; + + if (!hits[guess[i]]) { + hits[guess[i]] = MARKERS.RIGHT_CHAR; + } + } else { + if (!hits[guess[i]]) { + hits[guess[i]] = MARKERS.MISS; + } + markers[i] = MARKERS.MISS; + } + } + + return { + hits: hits, + markers: markers + }; + } +} diff --git a/src/styles/main.css b/assets/styles/main.css similarity index 100% rename from src/styles/main.css rename to assets/styles/main.css diff --git a/eleventy.config.js b/eleventy.config.js new file mode 100644 index 0000000..1d22253 --- /dev/null +++ b/eleventy.config.js @@ -0,0 +1,4 @@ +export default function(cfg) { + cfg.addPassthroughCopy("assets/styles/main.css"); + cfg.addPassthroughCopy("assets/scripts/**/*.js"); +}; \ No newline at end of file diff --git a/src/index.html b/index.html similarity index 96% rename from src/index.html rename to index.html index 93de54e..218321a 100644 --- a/src/index.html +++ b/index.html @@ -3,7 +3,7 @@
- +