Веб дизајн/К2 2022
Drugi kolokvijum 2022. godine održan je 5. maja. Postavka nije dostupna sa stranice predmeta.
Поставка
Потребно је направити игру меморије. Треба направити квадрат 3x3 и слајдер за избор броја случајно генерисаних поља. Игра почиње тако што се генерише изабрани број случајних поља и поља се обоје у плаво (поља се боје једно по једно, и држе се обојена 1 s након чега се враћају у белу боју). Након тога треба да се изаберу та поља притиском миша. Све док се бирају добра поља она се боје у зелено, када се први пут изабере поље које није генерисано сва изабрана поља се боје у црвено и држе се тако 1 s након чега се враћају у белу боју. Треба омогућити да се након тога поново могу погађати поља. Ако се погоде сва поља треба исписати поруку да је игра завршена и омогућити да се поново могу генерисати поља.
Решење
zadatak.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<link href="zadatak.css" rel="stylesheet" />
<script src="zadatak.js"></script>
</head>
<body>
<main>
<table>
<tr>
<td id="field-0"></td>
<td id="field-1"></td>
<td id="field-2"></td>
</tr>
<tr>
<td id="field-3"></td>
<td id="field-4"></td>
<td id="field-5"></td>
</tr>
<tr>
<td id="field-6"></td>
<td id="field-7"></td>
<td id="field-8"></td>
</tr>
</table>
<form>
<input type="range" id="n" min="1" max="9">
<input type="submit" id="start" value="Почни">
</form>
<p class="hidden">Игра је завршена!</p>
</main>
</body>
</html>
zadatak.css
main {
padding: 20px;
text-align: center;
}
table {
margin: 0 auto;
}
td {
border: 1px solid black;
box-sizing: border-box;
height: 100px;
pointer-events: none;
width: 100px;
}
form {
margin-top: 20px;
}
.hidden {
display: none;
}
.preview .selected {
background-color: blue;
}
.playing td {
pointer-events: all;
}
.playing .selected, .finished .selected {
background-color: green;
}
.error .selected {
background-color: red;
}
zadatak.js
$(function() {
'use strict';
// Niz tačnih polja u trenutnoj partiji
let correctFields = null;
// Identifikator intervala koji u 'preview' stanju boji ćelije
let interval = 0;
// DOM elementi
const $startButton = $('#start');
const $n = $('#n');
const $message = $('p');
const $table = $('table');
const $cells = $('td');
/**
* Generiše indekse polja na tabli sa tačnim izborima, za dat broj polja
* koji se generiše i ukupan broj polja.
* @param {number} n Broj polja koji se generiše
* @param {number} max Broj za jedan većeg od najvećeg broja koji se može
* generisati
* @returns {number[]} Niz brojeva koji predstavlja indekse polja na tabli
* koji su tačni izbori
*/
function selectFields(n, max) {
const selected = new Set();
while (selected.size < n) {
selected.add(Math.floor(Math.random() * max));
}
return [...selected];
}
/**
* Dohvata indeks zadate ćelije. Ćelije su numerisane brojevima počev od 0
* i indeks ćelije se čuva u njenom identifikatoru.
* @param {Node} cell DOM ćelija ili jQuery objekat ćelije čiji se indeks
* dohvata
* @returns Indeks zadate ćelije
*/
function getCellIndex(cell) {
return Number($(cell).attr('id').substring(6));
}
/**
* Vraća indekse ćelija koje nisu izabrane.
* @returns {number[]} Niz indeksa svih ćelija koje nisu izabrane
*/
function getUnselectedFields() {
const selectedFields = $('.selected')
.map((_, cell) => getCellIndex(cell))
.toArray();
return correctFields.filter(field => !selectedFields.includes(field));
}
/**
* Označava ćeliju sa zadatim indeksom kao izabranu.
* @param {number} number Indeks ćelije za biranje
*/
function selectField(number) {
$('#field-' + number).addClass('selected');
}
/**
* Uklanja oznaku da su izabrane sa svih ćelija.
*/
function deselectAll() {
$('.selected').removeClass('selected');
}
/**
* Postavlja trenutno stanje igre kao klasu table za igru.
*
* Moguća stanja su:
* - preview: Kada tačne ćelije postaju plave jedna po jedna
* - playing: Kada korisnik može da bira ćelije i one postaju zelene
* - error: Kada korisnik izabere pogrešnu ćeliju i ona postane crvena
* - finished: Kada korisnik završi igru
* @param {string} state Trenutno stanje igre
*/
function setGameState(state) {
$table.attr('class', state);
}
/**
* Poziva se svake sekunde dok je igra u 'preview' stanju i boji jedno
* polje u plavo ukoliko nije već obojeno, ili prelazi u 'playing' stanje
* ako su sva već obojena.
*/
function previewField() {
const fieldsToPreview = getUnselectedFields();
if (fieldsToPreview.length === 0) {
deselectAll();
setGameState('playing');
clearInterval(interval);
} else {
selectField(fieldsToPreview[0]);
}
}
/**
* Vraća igru u 'playing' stanje nakon što je korisnik pogrešio.
*/
function restoreStart() {
setGameState('playing');
deselectAll();
}
/**
* Rukovalac pritiska na dugme za početak.
* @param {ClickEvent} event Podaci događaja o pritisku na dugme
*/
$startButton.click(event => {
event.preventDefault();
deselectAll();
$startButton.attr('disabled', '');
$message.addClass('hidden');
setGameState('preview');
correctFields = selectFields($n.val(), $cells.length);
interval = setInterval(previewField, 1000);
});
/**
* Rukovalac pritiska na ćeliju na tabli.
* @param {ClickEvent} event Podaci događaja o pritisku na ćeliju
*/
$cells.click(event => {
const $cell = $(event.currentTarget);
$cell.addClass('selected');
if (correctFields.includes(getCellIndex($cell))) {
if (getUnselectedFields().length === 0) {
$message.removeClass('hidden');
$startButton.removeAttr('disabled');
setGameState('finished');
}
} else {
setGameState('error');
setTimeout(restoreStart, 1000);
}
});
});