Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ost/we1/testat-rockpaperscissoirs
1 result
Show changes
Commits on Source (4)
......@@ -9,7 +9,8 @@
<body>
<h1>Rock Paper Scissors Well Matchstick</h1>
<div id="login">
<section id="login">
<button id="change-online-mode-button" class="mode-change-enabled"></button>
<form id="login-form">
<label for="username-input">Username:</label>
<input id="username-input" placeholder="Please enter an username">
......@@ -27,9 +28,9 @@
</thead>
<tbody id="ranking-table"></tbody>
</table>
</div>
</section>
<div id="game">
<section id="game">
<label id="username-display"></label>
<div id="options" class="options-enabled">
<button class="option" id="rock">Rock</button>
......@@ -39,6 +40,8 @@
<button class="option" id="matchstick">Matchstick</button>
</div>
<label id="wait-label">&nbsp;</label>
<table id="game-table">
<tbody>
<tr><td class="hand-row-entry"><label id="player-hand" class="hand"></label></td></tr>
......@@ -60,7 +63,7 @@
</thead>
<tbody id="history"></tbody>
</table>
</div>
</section>
</body>
</html>
......@@ -17,9 +17,9 @@ const playerStats = {
},
};
function getRankingsFromPlayerStats() {
function getRankingsFromPlayerStats(stats) {
const ranking = [];
const playerValues = Object.values(playerStats);
const playerValues = Object.values(stats);
playerValues.sort((a, b) => b.win - a.win);
for (const playerValue of playerValues) {
......@@ -51,8 +51,15 @@ export function isConnected() {
}
export function getRankings(rankingsCallbackHandlerFn) {
const rankingsArray = getRankingsFromPlayerStats();
setTimeout(() => rankingsCallbackHandlerFn(rankingsArray), DELAY_MS);
if (isConnected()) {
fetch('https://stone.sifs0005.infs.ch/ranking')
.then((res) => res.json())
.then((json) => getRankingsFromPlayerStats(json))
.then((rankings) => rankingsCallbackHandlerFn(rankings));
} else {
const rankings = getRankingsFromPlayerStats(playerStats);
rankingsCallbackHandlerFn(rankings);
}
}
const evalLookup = {
......@@ -93,21 +100,39 @@ const evalLookup = {
},
};
const translationLookup = {
Rock: 'Stein',
Paper: 'Papier',
Scissors: 'Schere',
Well: 'Quelle',
Matchstick: 'Streichholz',
};
function enDeTranslation(key) {
return translationLookup[key];
}
function deEnTranslation(key) {
const reversed = {};
for (const k of Object.keys(translationLookup)) {
reversed[translationLookup[k]] = k;
}
return reversed[key];
}
function getGameEval(playerHand, systemHand) {
return evalLookup[playerHand.toLowerCase()][systemHand.toLowerCase()];
}
export function evaluateHand(playerName, playerHand, gameRecordHandlerCallbackFn) {
const systemHand = HANDS[Math.floor(Math.random() * 5)];
const gameEval = getGameEval(playerHand, systemHand);
// eslint-disable-next-line @web-and-design/wed/use-action-map
if (gameEval > 0) {
playerStats[playerName].win += 1;
} else if (gameEval < 0) {
playerStats[playerName].lost += 1;
function reevaluateHandsFromServer(playerHand, systemHand, gameEval) {
// if gameEval === false => player has lost OR draw
if (!gameEval) {
return getGameEval(playerHand, systemHand);
}
return 1; // if gameEval === true => player has won
}
function evaluateGame(playerHand, systemHand, gameEval, gameRecordHandlerCallbackFn) {
setTimeout(() => gameRecordHandlerCallbackFn({
playerHand,
systemHand,
......@@ -115,6 +140,35 @@ export function evaluateHand(playerName, playerHand, gameRecordHandlerCallbackFn
}), DELAY_MS);
}
function evaluateFromServer(playerHand, systemHand, gameEval, gameRecordHandlerCallbackFn) {
const gameEvalAsNumber = reevaluateHandsFromServer(playerHand, systemHand, gameEval);
evaluateGame(playerHand, systemHand, gameEvalAsNumber, gameRecordHandlerCallbackFn);
}
export function evaluateHand(playerName, playerHand, gameRecordHandlerCallbackFn) {
// eslint-disable-next-line @web-and-design/wed/use-action-map
if (isConnected()) {
const translatedPlayerHand = enDeTranslation(playerHand);
const url = `https://stone.sifs0005.infs.ch/play?playerName=${playerName}&playerHand=${translatedPlayerHand}`;
fetch(url)
.then((res) => res.json())
.then((json) => evaluateFromServer(playerHand, deEnTranslation(json.choice),
json.win, gameRecordHandlerCallbackFn));
} else {
const systemHand = HANDS[Math.floor(Math.random() * 5)];
const gameEval = getGameEval(playerHand, systemHand);
// eslint-disable-next-line @web-and-design/wed/use-action-map
if (gameEval > 0) {
playerStats[playerName].win += 1;
} else if (gameEval < 0) {
playerStats[playerName].lost += 1;
}
evaluateGame(playerHand, systemHand, gameEval, gameRecordHandlerCallbackFn);
}
}
export function createUserIfNotExists(username) {
if (playerStats[username] === undefined) {
playerStats[username] = {user: username, win: 0, lost: 0};
......
......@@ -2,13 +2,15 @@
README, as well as source code, can be found at https://git.420joos.dev/ost/we1/testat-rockpaperscissoirs/-/blob/dev/README.md
*/
import {getRankings, evaluateHand, createUserIfNotExists} from './game-service.js';
import {getRankings, evaluateHand, createUserIfNotExists, isConnected, setConnected} from './game-service.js';
const loginScreen = document.querySelector('#login');
const gameScreen = document.querySelector('#game');
const options = document.querySelector('#options');
const waitLabel = document.querySelector('#wait-label');
const changeModeButton = document.querySelector('#change-online-mode-button');
const loginForm = document.querySelector('#login-form');
const usernameInput = document.querySelector('#username-input');
const rankingTable = document.querySelector('#ranking-table');
......@@ -28,6 +30,8 @@ const visibleClass = 'visible';
const hiddenClass = 'hidden';
const optionsDisabledClass = 'options-disabled';
const optionsEnabledClass = 'options-enabled';
const modeChangeDisabledClass = 'mode-change-disabled';
const modeChangeEnabledClass = 'mode-change-enabled';
function addToHistory(userHand, opponentHand, winText) {
historyTableBody.innerHTML = `<tr><td>${winText}</td>\t<td>${userHand}</td>\t<td>${opponentHand}\n</td></tr>${historyTableBody.innerHTML}`;
......@@ -50,7 +54,22 @@ function handleOpponentPicked(userHand, opponentHand, gameEval) {
addToHistory(userHand, opponentHand, winText);
options.classList.replace(optionsDisabledClass, optionsEnabledClass);
let timeout = 3;
waitLabel.innerText = 'Next round starts in soon';
const countdown = setInterval(() => {
if (timeout > 0) {
waitLabel.innerText = `Next round starts in ${timeout}`;
timeout--;
} else {
clearTimeout(countdown);
waitLabel.innerText = '\n';
options.classList.replace(optionsDisabledClass, optionsEnabledClass);
}
}, 1000);
}
function sanitizePlayername(playerName) {
return playerName.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
}
function showRankings(rankings) {
......@@ -58,14 +77,23 @@ function showRankings(rankings) {
for (const ranking of rankings) {
rankingsHtml += `<tr><td>${ranking.rank}</td><td>${ranking.wins}</td><td>`;
for (let i = 0; i < ranking.players.length - 1; i++) {
rankingsHtml += `${ranking.players[i]}, `;
const playerName = sanitizePlayername(ranking.players[i]);
rankingsHtml += `${playerName}, `;
}
rankingsHtml += `${ranking.players[ranking.players.length - 1]}</td></tr>`;
const playerName = sanitizePlayername(ranking.players[ranking.players.length - 1]);
rankingsHtml += `${playerName}</td></tr>`;
}
rankingTable.innerHTML = rankingsHtml;
}
function updateRankings(rankings) {
if (changeModeButton.classList.contains(modeChangeDisabledClass)) {
changeModeButton.classList.replace(modeChangeDisabledClass, modeChangeEnabledClass);
}
showRankings(rankings);
}
function onOptionClick(event) {
const userHand = event.target.innerText;
playerHandLabel.innerText = userHand;
......@@ -150,9 +178,28 @@ function onMainMenuClick() {
getRankings(showRankings);
}
function updateOnlineButton() {
const preText = 'Change to';
if (isConnected()) {
changeModeButton.innerText = `${preText} local`;
} else {
changeModeButton.innerText = `${preText} online`;
}
}
function triggerOnlineState() {
changeModeButton.classList.replace(modeChangeEnabledClass, modeChangeDisabledClass);
setConnected(!isConnected());
updateOnlineButton();
getRankings(updateRankings);
}
options.addEventListener('click', (event) => onOptionClick(event));
loginForm.addEventListener('submit', onLoginClick);
mainMenuButton.addEventListener('click', onMainMenuClick);
changeModeButton.addEventListener('click', triggerOnlineState);
window.addEventListener('DOMContentLoaded', () => setScreenVisible(false));
window.addEventListener('DOMContentLoaded', () => getRankings(showRankings));
window.addEventListener('DOMContentLoaded', () => getRankings(updateRankings));
window.addEventListener('DOMContentLoaded', updateOnlineButton);
......@@ -68,3 +68,13 @@ td {
.options-enabled {
pointer-events: auto;
}
.mode-change-enabled {
pointer-events: auto;
color: black;
}
.mode-change-disabled {
pointer-events: none;
color: gray;
}