First cut of Mahjong scorecard
This commit is contained in:
parent
e74906e0c4
commit
e020f2a4b6
5 changed files with 556 additions and 0 deletions
209
site/mahjong/main.js
Normal file
209
site/mahjong/main.js
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
|
||||
import { GameState, getGameState, setGameState, calculateScore } from "./models.js";
|
||||
|
||||
function emitGameStateEvent(details) {
|
||||
// window.setTimeout(() => {
|
||||
let ev = new CustomEvent("gamestatechanged", { detail: details });
|
||||
window.dispatchEvent(ev);
|
||||
// }, 1);
|
||||
}
|
||||
|
||||
|
||||
window.Stimulus = Application.start();
|
||||
|
||||
Stimulus.register("scorecard", class extends Controller {
|
||||
static targets = ["prevailing"];
|
||||
|
||||
initialize() {
|
||||
}
|
||||
|
||||
connect() {
|
||||
// this._rebuildTable();
|
||||
// this.element.classList.remove("hidden");
|
||||
}
|
||||
|
||||
handleGameState(ev) {
|
||||
switch (ev.detail.mode) {
|
||||
case "endround":
|
||||
this.element.classList.add("hidden");
|
||||
break;
|
||||
case "startgame":
|
||||
case "nextround":
|
||||
this._rebuildTable();
|
||||
this.element.classList.remove("hidden");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endRound(ev) {
|
||||
ev.preventDefault();
|
||||
console.log("end round");
|
||||
emitGameStateEvent({mode: "endround"});
|
||||
}
|
||||
|
||||
_rebuildTable() {
|
||||
let gameState = getGameState();
|
||||
|
||||
let tbl = document.createElement("table");
|
||||
tbl.classList.add("scorecard");
|
||||
|
||||
let thead = document.createElement("thead");
|
||||
let thr = document.createElement("tr");
|
||||
let headRows = gameState.players.map(player => {
|
||||
let th = document.createElement("th");
|
||||
th.textContent = player.name + " (" + player.wind + ")";
|
||||
return th;
|
||||
});
|
||||
thr.append(...headRows);
|
||||
thead.append(thr);
|
||||
tbl.append(thead);
|
||||
|
||||
let tbody = document.createElement("tbody");
|
||||
for (let r of gameState.rounds) {
|
||||
let tr = document.createElement("tr");
|
||||
for (let c of r) {
|
||||
let td = document.createElement("td");
|
||||
td.textContent = c.s;
|
||||
if (c.w) {
|
||||
td.classList.add("winner");
|
||||
td.textContent += " 🏆";
|
||||
}
|
||||
tr.append(td);
|
||||
}
|
||||
tbody.append(tr);
|
||||
}
|
||||
tbl.append(tbody);
|
||||
|
||||
let tfoot = document.createElement("tfoot");
|
||||
for (let t of gameState.playerTotals()) {
|
||||
let td = document.createElement("td");
|
||||
td.textContent = t;
|
||||
tfoot.append(td);
|
||||
}
|
||||
tbl.append(tfoot);
|
||||
|
||||
this.element.querySelector("table.scorecard").replaceWith(tbl);
|
||||
|
||||
this.prevailingTarget.textContent = `Prevailing: ${gameState.prevaling}`;
|
||||
}
|
||||
});
|
||||
|
||||
Stimulus.register("newgame", class extends Controller {
|
||||
static targets = ["playerName"];
|
||||
|
||||
connect() {
|
||||
this.element.classList.remove("hidden");
|
||||
}
|
||||
|
||||
handleGameState(ev) {
|
||||
switch (ev.detail.mode) {
|
||||
case "startgame":
|
||||
case "endround":
|
||||
case "nextround":
|
||||
this.element.classList.add("hidden");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
startGame() {
|
||||
let players = [];
|
||||
this.playerNameTargets.forEach(el => {
|
||||
if (el.value != "") {
|
||||
players.push(el.value);
|
||||
}
|
||||
});
|
||||
|
||||
setGameState(GameState.newGame(players));
|
||||
this.element.classList.add("hidden");
|
||||
emitGameStateEvent({mode: "startgame"});
|
||||
}
|
||||
});
|
||||
|
||||
Stimulus.register("endround", class extends Controller {
|
||||
static targets = ["form", "input", "wind"];
|
||||
|
||||
connect() {
|
||||
// this.element.classList.remove("hidden");
|
||||
}
|
||||
|
||||
handleGameState(ev) {
|
||||
switch (ev.detail.mode) {
|
||||
case "startgame":
|
||||
case "nextround":
|
||||
this.element.classList.add("hidden");
|
||||
break;
|
||||
case "endround":
|
||||
this._prepForms();
|
||||
this.element.classList.remove("hidden");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updatePreview(ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
let scoreExprs = this._readScoreExprs();
|
||||
let nextRound = getGameState().determineNextRound(scoreExprs);
|
||||
|
||||
for (let i in nextRound.roundScores) {
|
||||
let previewElem = this.element.querySelector(`.preview[data-player="${i}"]`);
|
||||
previewElem.textContent = nextRound.roundScores[i].score;
|
||||
if (parseInt(i) === nextRound.roundWinner) {
|
||||
previewElem.textContent += " 🏆";
|
||||
}
|
||||
}
|
||||
|
||||
if (nextRound.windsBump) {
|
||||
this.windTarget.textContent = `${getGameState().players[nextRound.nextRoundEast].name} will be East next round`;
|
||||
} else {
|
||||
this.windTarget.textContent = `${getGameState().players[nextRound.nextRoundEast].name} will remain East next round`;
|
||||
}
|
||||
}
|
||||
|
||||
nextRound(ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
let scoreExprs = this._readScoreExprs();
|
||||
getGameState().startNextRound(scoreExprs);
|
||||
|
||||
emitGameStateEvent({mode: "nextround"});
|
||||
}
|
||||
|
||||
_prepForms() {
|
||||
let newFormElems = getGameState().players.map((player, i) => {
|
||||
let outerDiv = document.createElement("div");
|
||||
|
||||
let label = document.createElement("label");
|
||||
label.textContent = player.name + " (" + player.wind + ")";
|
||||
label.setAttribute("for", `player-${i}`);
|
||||
|
||||
let div = document.createElement("div");
|
||||
div.classList.add("score-input-group");
|
||||
|
||||
let input = document.createElement("input");
|
||||
input.name = `player-${i}`;
|
||||
input.dataset["endroundTarget"] = "input";
|
||||
input.dataset["action"] = "keyup->endround#updatePreview";
|
||||
input.dataset["player"] = i;
|
||||
|
||||
let preview = document.createElement("div");
|
||||
preview.classList.add("preview");
|
||||
preview.textContent = "0";
|
||||
preview.dataset["player"] = i;
|
||||
|
||||
div.append(input, preview);
|
||||
outerDiv.append(label, div);
|
||||
return outerDiv;
|
||||
});
|
||||
this.formTarget.replaceChildren(...newFormElems);
|
||||
}
|
||||
|
||||
_readScoreExprs() {
|
||||
let scoreExprs = [];
|
||||
for (let playerIndex in getGameState().players) {
|
||||
let thisScoreExpr = this.formTarget.querySelector(`input[data-player="${playerIndex}"]`).value;
|
||||
scoreExprs.push(thisScoreExpr);
|
||||
}
|
||||
return scoreExprs;
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue