Added tracking of a player's state

This commit is contained in:
Leon Mika 2025-06-20 14:00:23 +02:00
parent 64a2d4f9cb
commit 332cfd9fca
10 changed files with 95 additions and 19 deletions

View file

@ -15,6 +15,7 @@ func main() {
questions := models.QuestionSet{
Questions: []models.Question{
{
ID: "1",
Text: "What is 1 + 1?",
Choices: []models.Choice{
{Text: "1"},
@ -25,6 +26,7 @@ func main() {
Fact: "1 + 1 = 2",
},
{
ID: "2",
Text: "What is 3 * 5?",
Choices: []models.Choice{
{Text: "5"},

View file

@ -17,6 +17,7 @@ type Choice struct {
}
type Question struct {
ID string
Text string
Choices []Choice
Fact string
@ -38,6 +39,7 @@ func (q Question) Render() (RenderedQuestion, error) {
}
return RenderedQuestion{
ID: q.ID,
Question: q.Text,
Fact: q.Fact,
Choices: choices,
@ -51,6 +53,7 @@ type RenderedChoice struct {
}
type RenderedQuestion struct {
ID string
Question string
Fact string
Choices []RenderedChoice

View file

@ -0,0 +1,9 @@
import { Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
import { gameState } from "./gamestate.js";
export default class extends Controller {
startGame(ev) {
console.log("Start game");
gameState.clearChoices();
}
}

View file

@ -0,0 +1,32 @@
const GAME_STATE_KEY = "gameState";
class GameState {
getQuestionChoice(qId) {
let savedItem = this._readGameState();
if (qId in savedItem) {
return savedItem[qId];
}
return null;
}
setQuestionChoice(qId, cId) {
let savedItem = this._readGameState();
savedItem[qId] = cId;
localStorage.setItem(GAME_STATE_KEY, JSON.stringify(savedItem));
}
clearChoices() {
localStorage.removeItem(GAME_STATE_KEY);
}
_readGameState() {
let savedItem = localStorage.getItem(GAME_STATE_KEY);
if (savedItem === null) {
return {};
} else {
return JSON.parse(savedItem);
}
}
}
export let gameState = new GameState();

View file

@ -1,30 +1,57 @@
import { Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
import { gameState } from "./gamestate.js";
export default class extends Controller {
static targets = ["radio", "answerDetails"];
static targets = ["radio", "answerDetails", "submit"];
static values = {
qid: String,
answer: String
};
connect() {
let hasAnswer = gameState.getQuestionChoice(this.qidValue);
if (hasAnswer) {
this._revealAnswer();
let e = this.radioTargets.find((e) => e.value == hasAnswer);
if (e) {
e.checked = true;
}
}
}
checkRadio(ev) {
this.submitTarget.disabled = false;
}
submitAnswer(ev) {
ev.preventDefault();
this.submitTarget.disabled = false;
let e = this.radioTargets.find((e) => e.checked);
if (!e) {
alert("Please select an item");
return;
}
gameState.setQuestionChoice(this.qidValue, e.value);
this.element.classList.add("reveal");
window.setTimeout(() => { this._revealAnswer(); });
}
_revealAnswer() {
this.element.classList.add("reveal");
window.setTimeout(() => {
this.radioTargets.forEach(e => {
e.disabled = true;
if (e.value === this.answerValue) {
e.classList.add("answer");
} else {
e.classList.add("wrong");
}
});
}, 1);
this.radioTargets.forEach(e => {
e.disabled = true;
if (e.value === this.answerValue) {
e.classList.add("answer");
} else {
e.classList.add("wrong");
}
});
this.answerDetailsTarget.classList.remove("hidden");
}

View file

@ -1,7 +1,9 @@
import { Application } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
import ClearStateController from "./controllers/clearstate.js";
import PickerController from "./controllers/picker.js";
window.Stimulus = Application.start();
Stimulus.register("picker", PickerController);
Stimulus.register("picker", PickerController);
Stimulus.register("clearstate", ClearStateController);

View file

@ -24,6 +24,7 @@ label:has(input[type=radio]) {
font-size: 0.9em;
font-weight: bold;
box-sizing: border-box;
cursor: pointer;
}
label:has(input[type=radio]):hover {

View file

@ -2,4 +2,4 @@
<p>Welcome to the quiz</p>
<a href="{{prefix}}/1">Lets go</a>
<a data-controller="clearstate" data-action="clearstate#startGame" href="{{prefix}}/1">Lets go</a>

View file

@ -6,6 +6,7 @@
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
<link rel="stylesheet" href="{{prefix}}/assets/style.css">
<link rel="stylesheet" href="{{prefix}}/assets/fontello/css/fontello.css">
<script src="{{prefix}}/assets/scripts/main.js" type="module"></script>
</head>
<body>
{{embed}}

View file

@ -3,12 +3,13 @@
<i class="icon-ok"></i>
</div>
<div class="question" data-controller="picker" data-picker-answer-value="{{.q.RightChoice}}">
<div class="question" data-controller="picker"
data-picker-qid-value="{{.q.ID}}" data-picker-answer-value="{{.q.RightChoice}}">
<p>{{.q.Question}}</p>
{{range .q.Choices}}
<label>
<input type="radio" name="ans" value="{{.ID}}" data-picker-target="radio">
<input type="radio" name="ans" value="{{.ID}}" data-picker-target="radio" data-action="picker#checkRadio">
{{if eq .ID $.q.RightChoice}}
<i class="icon-ok"></i>
{{else}}
@ -18,7 +19,7 @@
</label>
{{end}}
<button data-action="picker#submitAnswer">Submit</button>
<button disabled data-picker-target="submit" data-action="picker#submitAnswer">Submit</button>
<div data-picker-target="answerDetails" class="hidden">
<p>{{.q.Fact}}</p>
@ -26,6 +27,4 @@
<a href="{{.nextURL}}">Next</a>
</div>
</div>
</div>
<script src="{{prefix}}/assets/scripts/main.js" type="module"></script>
</div>