From 69a4772b765e159193e2f9c45cf7d58605274de5 Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 18:49:45 +0200 Subject: [PATCH 01/26] add js folder --- game.html | 2 +- gst.html | 4 ++-- game.js => js/game.js | 0 gst.js => js/gst.js | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename game.js => js/game.js (100%) rename gst.js => js/gst.js (100%) diff --git a/game.html b/game.html index a8c9a21..fa2b3fb 100644 --- a/game.html +++ b/game.html @@ -70,7 +70,7 @@ diff --git a/game.js b/js/game.js similarity index 100% rename from game.js rename to js/game.js diff --git a/gst.js b/js/gst.js similarity index 100% rename from gst.js rename to js/gst.js From 1fb4e3f8e375ea3937a448119b701b62f0feb56d Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 19:56:51 +0200 Subject: [PATCH 02/26] add statistic class --- js/statistics.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 js/statistics.js diff --git a/js/statistics.js b/js/statistics.js new file mode 100644 index 0000000..d7aa863 --- /dev/null +++ b/js/statistics.js @@ -0,0 +1,23 @@ +class Stats { + #score; + #highScore; + #highScoreStorageKey; + + constructor(highScoreStorageKey) { + // used as key for localStorage + + this.#highScoreStorageKey = highScoreStorageKey; + + this.#score = 0; + this.#highScore = localStorage.getItem(this.#highScoreStorageKey) ?? 0; + } + + incrementScore(value = 1) { + this.#score += value; + + if (this.#highScore < this.#score) { + this.#highScore = this.#score; + localStorage.setItem(this.#highScoreStorageKey, this.#highScore); + } + } +} \ No newline at end of file From f3812e9a7f59922248abcd97d1f2b3aa02963fe4 Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 19:57:11 +0200 Subject: [PATCH 03/26] move data.json --- data.json => js/data.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data.json => js/data.json (100%) diff --git a/data.json b/js/data.json similarity index 100% rename from data.json rename to js/data.json From 5f61cf50bea370bc9e8b313aea8018ecdb16ef51 Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 19:57:22 +0200 Subject: [PATCH 04/26] add cpuRepository class --- js/cpuRepository.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 js/cpuRepository.js diff --git a/js/cpuRepository.js b/js/cpuRepository.js new file mode 100644 index 0000000..ad84a99 --- /dev/null +++ b/js/cpuRepository.js @@ -0,0 +1,35 @@ +class cpuRepository { + #cpuList; + + #currentCPU; + #nextCPU; + + async init() { + const fetchResult = await fetch("./js/data.json"); + this.#cpuList = await fetchResult.json(); + + this.#currentCPU = this.getRandomCpu(); + this.#nextCPU = this.getRandomCpu(); + } + + get currentCpu() { + return this.#currentCpu; + } + + get nextCpu() { + return this.#nextCpu; + } + + getRandomCpu() { + let randomIndex = this.getRandomInt(0, this.#cpuList.length); + this.#cpuList[randomIndex]["name"] = this.#cpuList[randomIndex]["name"].split('@')[0]; + return this.#cpuList[randomIndex]; + } + + getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive + } + +} \ No newline at end of file From 026f58b3ccaf88945b2c82d563976bfa5558bd44 Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 20:03:14 +0200 Subject: [PATCH 05/26] add getter --- js/statistics.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/js/statistics.js b/js/statistics.js index d7aa863..f44c017 100644 --- a/js/statistics.js +++ b/js/statistics.js @@ -1,4 +1,4 @@ -class Stats { +export class Stats { #score; #highScore; #highScoreStorageKey; @@ -20,4 +20,12 @@ class Stats { localStorage.setItem(this.#highScoreStorageKey, this.#highScore); } } + + get highScore() { + return this.#highScore; + } + + get score() { + return this.#score; + } } \ No newline at end of file From 545832726fda99c325f22614e75d9d5e8a965397 Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Wed, 19 Apr 2023 20:20:08 +0200 Subject: [PATCH 06/26] make use of stats class --- game.html | 2 +- js/game.js | 36 ++++++++++++------------------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/game.html b/game.html index fa2b3fb..e1c9353 100644 --- a/game.html +++ b/game.html @@ -68,7 +68,7 @@ Processor icons created by kerismaker - Flaticon --> - + diff --git a/src/game.ts b/src/game.ts index b947bc8..5ca8743 100644 --- a/src/game.ts +++ b/src/game.ts @@ -3,81 +3,166 @@ import { CountUp } from "https://cdnjs.cloudflare.com/ajax/libs/countup.js/2.6.0 import { Stats } from "./statistics.js"; import { CpuRepository } from "./cpuRepository.js" -var repo: CpuRepository; -var localStats: Stats; +class UI { + #model: ViewModel; -export async function main() { - localStats = new Stats("highScore_cpu"); + #btnLower: HTMLElement; + #btnHigher: HTMLElement; + #btnScore: HTMLElement; + #btnHighScore: HTMLElement; + + #curCpuTitle: HTMLElement; + #curCpuScore: HTMLElement; + #nextCpuTitle: HTMLElement; + #nextCpuScore: HTMLElement; + + #background: HTMLElement; - repo = new CpuRepository(); - await repo.init(); - - updateLayout(); -} - -export function btnLowerClick() { - repo.nextCpu.cpuScore < repo.currentCpu.cpuScore ? showResult(true) : showResult(false); -} - -export function btnHigherClick() { - repo.nextCpu.cpuScore > repo.currentCpu.cpuScore ? showResult(true) : showResult(false); -} - -function showResult(isCorrect) { - document.getElementById("btnHigher").setAttribute("disabled", ""); - document.getElementById("btnLower").setAttribute("disabled", ""); - - document.getElementById("col2").style.backgroundColor = isCorrect ? "lightgreen" : "#FF4444"; - - isCorrect ? localStats.incrementScore() : localStats.resetScore(); - - document.getElementById("highScore").innerText = localStats.highScore.toString(); - document.getElementById("score").innerText = localStats.score.toString(); - - countUp(); -} - -// updates view based on the cpu objects -function updateLayout() { - document.getElementById("highScore").innerText = localStats.highScore.toString(); - - document.getElementById("currentCpuTitle").innerText = repo.currentCpu.name; - // add "." to large numbers - document.getElementById("currentCpuScore").innerText = new Intl.NumberFormat().format(repo.currentCpu.cpuScore) - document.getElementById("nextCpuTitle").innerText = repo.nextCpu.name; - - document.getElementById("nextCpuScore").innerText = "?"; - - document.getElementById("col2").style.backgroundColor = ""; -} - -function delay(time) { - return new Promise(resolve => setTimeout(resolve, time)); -} - -async function countUp() { - const options = { - startVal: repo.nextCpu.cpuScore / 2, - separator: '.', - decimal: ',', - duration: 2 - }; - let counter = new CountUp('nextCpuScore', repo.nextCpu.cpuScore, options); - if (!counter.error) { - counter.start(); - } else { - console.log(counter.error); + constructor() { + this.#model = new ViewModel(); } - await delay(2500) - nextRound(); + async init() { + await this.#model.init(); - document.getElementById("btnHigher").removeAttribute("disabled"); - document.getElementById("btnLower").removeAttribute("disabled"); + this.#btnLower = document.getElementById("btnLower"); + this.#btnHigher = document.getElementById("btnHigher"); + this.#btnScore = document.getElementById("score"); + this.#btnHighScore = document.getElementById("highScore"); + + this.#curCpuTitle = document.getElementById("currentCpuTitle"); + this.#curCpuScore = document.getElementById("currentCpuScore"); + this.#nextCpuTitle = document.getElementById("nextCpuTitle"); + this.#nextCpuScore = document.getElementById("nextCpuScore"); + + this.#background = document.getElementById("col2"); + + this.#btnLower.onclick = () => this.handleButtonLowerClick(); + this.#btnHigher.onclick = () => this.handleButtonHigherClick(); + + this.updateLayout(); + } + + updateLayout() { + this.#btnHighScore.innerText = this.#model.highScore.toString(); + + this.#curCpuTitle.innerText = this.#model.currentCpu.name; + // add "." to large numbers + this.#curCpuScore.innerText = new Intl.NumberFormat().format(this.#model.currentCpu.cpuScore); + this.#nextCpuTitle.innerText = this.#model.nextCpu.name; + + this.#nextCpuScore.innerText = "?"; + + this.#background.style.backgroundColor = ""; + } + + handleButtonLowerClick() { + let result = this.#model.buttonClicked("lower"); + this.#showResult(result); + } + + handleButtonHigherClick() { + let result = this.#model.buttonClicked("higher"); + this.#showResult(result); + } + + #showResult(isCorrect) { + this.#btnHigher.setAttribute("disabled", ""); + this.#btnLower.setAttribute("disabled", ""); + + this.#background.style.backgroundColor = isCorrect ? "lightgreen" : "#FF4444"; + + isCorrect ? this.#model.incrementScore() : this.#model.resetScore(); + + this.#btnHighScore.innerText = this.#model.highScore.toString(); + this.#btnScore.innerText = this.#model.score.toString(); + + this.#countUp(); + } + + #delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); + } + + async #countUp() { + const options = { + startVal: this.#model.nextCpu.cpuScore / 2, + separator: '.', + decimal: ',', + duration: 2 + }; + let counter = new CountUp('nextCpuScore', this.#model.nextCpu.cpuScore, options); + if (!counter.error) { + counter.start(); + } else { + console.log(counter.error); + } + + await this.#delay(2500) + this.#model.nextRound(); + + this.#btnHigher.removeAttribute("disabled"); + this.#btnLower.removeAttribute("disabled"); + + this.updateLayout(); + } } -function nextRound() { - repo.nextRound(); +class ViewModel { + #repo: CpuRepository; + #localStats: Stats; + + constructor() { + this.#repo = new CpuRepository(); + this.#localStats = new Stats("highScore_cpu"); + } - updateLayout(); + async init() { + await this.#repo.init(); + } + + nextRound(): void { + this.#repo.nextRound(); + } + + // "lower" and "higher" + buttonClicked(value: string): boolean { + if (value == "higher") { + return this.#repo.nextCpu.cpuScore > this.#repo.currentCpu.cpuScore; + } + if (value == "lower") { + return this.#repo.nextCpu.cpuScore < this.#repo.currentCpu.cpuScore; + } + console.log("nothing found for '" + value + "'"); + return false; + } + + incrementScore() { + this.#localStats.incrementScore(); + } + + resetScore() { + this.#localStats.resetScore(); + } + + get currentCpu() { + return this.#repo.currentCpu; + } + + get nextCpu() { + return this.#repo.nextCpu; + } + + get highScore() { + return this.#localStats.highScore; + } + + get score() { + return this.#localStats.score; + } +} + +export async function main() { + const ui = new UI(); + await ui.init(); } \ No newline at end of file From 70dd1dbf23cace1bd4d227d9e3c5a9cf7757719b Mon Sep 17 00:00:00 2001 From: Florian Schmid Date: Sun, 23 Apr 2023 19:17:27 +0200 Subject: [PATCH 26/26] add mvvm --- gst.html | 3 +- src/gst.ts | 276 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 162 insertions(+), 117 deletions(-) diff --git a/gst.html b/gst.html index 598769c..742a0ba 100644 --- a/gst.html +++ b/gst.html @@ -68,8 +68,7 @@ diff --git a/src/gst.ts b/src/gst.ts index ec39821..f57ecae 100644 --- a/src/gst.ts +++ b/src/gst.ts @@ -1,120 +1,166 @@ +import { CpuRepository } from "./cpuRepository.js"; import { Stats } from "./statistics.js"; -var cpuList; -var currentCpu; +type CPU = { + name: string; + type: string; +} -var stats: Stats; +class UI { + #model: ViewModel; + + #btnDesktop: HTMLElement; + #btnLaptop: HTMLElement; + #btnServer: HTMLElement; + #btnMobile: HTMLElement; + + #btns: HTMLElement[]; + + #cpuName: HTMLElement; + #score: HTMLElement; + #highScore: HTMLElement; + #mainCol: HTMLElement; + + constructor() { + this.#model = new ViewModel(); + + this.#btnDesktop = document.getElementById("btnDesktop"); + this.#btnDesktop.onclick = () => this.btnClick(0); + this.#btnLaptop = document.getElementById("btnLaptop"); + this.#btnLaptop.onclick = () => this.btnClick(1); + this.#btnMobile = document.getElementById("btnMobile"); + this.#btnMobile.onclick = () => this.btnClick(2); + this.#btnServer = document.getElementById("btnServer"); + this.#btnServer.onclick = () => this.btnClick(3); + + this.#btns = [this.#btnDesktop, this.#btnLaptop, this.#btnMobile, this.#btnServer]; + + this.#cpuName = document.getElementById("cpuName"); + this.#score = document.getElementById("score"); + this.#highScore = document.getElementById("highScore"); + this.#mainCol = document.getElementById("mainCol"); + } + + async init() { + await this.#model.init(); + + this.#nextRound(); + } + + #updateScores() { + this.#score.innerText = this.#model.score.toString(); + this.#highScore.innerText = this.#model.highScore.toString(); + } + + async #delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); + } + + #nextRound() { + this.#model.nextRound(); + + this.#cpuName.innerText = this.#model.currentCpu.name; + + this.#mainCol.style.backgroundColor = ""; + } + + async btnClick(typ) { + // 0 -> Desktop + // 1 -> Laptop + // 2 -> Mobile/Embedded + // 3 -> Server + + this.#btns.forEach((el) => { + el.setAttribute("disabled", ""); + }) + + switch (typ) { + case 0: + this.#btnDesktop.style.backgroundColor = "#FF4444"; + break; + case 1: + this.#btnLaptop.style.backgroundColor = "#FF4444"; + break; + case 2: + this.#btnMobile.style.backgroundColor = "#FF4444"; + break; + case 3: + this.#btnServer.style.backgroundColor = "#FF4444"; + break; + } + + const currentType = this.#model.currentCpu.type; + if(currentType.includes("Desktop")) { + this.#btnDesktop.style.backgroundColor = "lightgreen"; + } + if(currentType.includes("Laptop")) { + this.#btnLaptop.style.backgroundColor = "lightgreen"; + } + if(currentType.includes("Mobile/Embedded")) { + this.#btnMobile.style.backgroundColor = "lightgreen"; + } + if(currentType.includes("Server")) { + this.#btnServer.style.backgroundColor = "lightgreen"; + } + + // Score + if (this.#btns[typ].style.backgroundColor == "lightgreen") { + this.#model.incrementScore(); + } else { + this.#model.resetScore(); + } + this.#updateScores(); + + await this.#delay(1000); + + this.#btns.forEach( (el) => { + el.style.backgroundColor = "#3CC3FA"; + el.removeAttribute("disabled"); + }) + + this.#nextRound(); + } +} + +class ViewModel { + #repo: CpuRepository; + #stats: Stats; + + constructor() { + this.#stats = new Stats("highScore_socket"); + this.#repo = new CpuRepository(); + } + + async init() { + await this.#repo.init(); + } + + nextRound() { + this.#repo.reset(); + } + + incrementScore() { + this.#stats.incrementScore(); + } + + resetScore() { + this.#stats.resetScore(); + } + + get currentCpu(): CPU { + return this.#repo.currentCpu; + } + + get score(): number { + return this.#stats.score; + } + + get highScore(): number { + return this.#stats.highScore; + } +} export async function main() { - // init cpu list - await (fetch('./data.json') - .then((response) => response.json()) - .then((json) => cpuList = json)); - - stats = new Stats("highScore_socket"); - - updateScores(); - - nextRound(); -} - -function nextRound() { - currentCpu = getRandomCpu(); - - document.getElementById("cpuName").innerText = currentCpu.name; - - document.getElementById("mainCol").style.backgroundColor = ""; -} - -function getRandomCpu() { - let randomIndex; - do { - randomIndex = getRandomInt(0, cpuList.length) - } while (typeof(cpuList[randomIndex]["type"]) == null || cpuList[randomIndex]["type"] == "null" || cpuList[randomIndex]["type"] == null); - - - return { - name: cpuList[randomIndex]["name"].split('@')[0], - type: cpuList[randomIndex]["type"] - } -} - -function delay(time) { - return new Promise(resolve => setTimeout(resolve, time)); -} - -export async function btnClick(typ) { - // 0 -> Desktop - // 1 -> Laptop - // 2 -> Mobile/Embedded - // 3 -> Server - - let btnDesktop = document.getElementById("btnDesktop"); - let btnLaptop = document.getElementById("btnLaptop"); - let btnMobile = document.getElementById("btnMobile"); - let btnServer = document.getElementById("btnServer"); - - let btns = [btnDesktop, btnLaptop, btnMobile, btnServer]; - - btns.forEach((el) => { - el.setAttribute("disabled", ""); - }) - - switch (typ) { - case 0: - btnDesktop.style.backgroundColor = "#FF4444"; - break; - case 1: - btnLaptop.style.backgroundColor = "#FF4444"; - break; - case 2: - btnMobile.style.backgroundColor = "#FF4444"; - break; - case 3: - btnServer.style.backgroundColor = "#FF4444"; - break; - } - - if(currentCpu.type.includes("Desktop")) { - btnDesktop.style.backgroundColor = "lightgreen"; - } - if(currentCpu.type.includes("Laptop")) { - btnLaptop.style.backgroundColor = "lightgreen"; - } - if(currentCpu.type.includes("Mobile/Embedded")) { - btnMobile.style.backgroundColor = "lightgreen"; - } - if(currentCpu.type.includes("Server")) { - btnServer.style.backgroundColor = "lightgreen"; - } - - // Score - if (btns[typ].style.backgroundColor == "lightgreen") { - stats.incrementScore(); - } else { - stats.resetScore(); - } - updateScores(); - - await delay(1000); - - btns.forEach( (el) => { - el.style.backgroundColor = "#3CC3FA"; - el.removeAttribute("disabled"); - }) - - nextRound(); -} - -function updateScores() { - document.getElementById("score").innerText = stats.score.toString(); - document.getElementById("highScore").innerText = stats.highScore.toString(); -} - -function getRandomInt(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive -} - -main(); \ No newline at end of file + const ui = new UI(); + await ui.init(); +} \ No newline at end of file