Веб дизајн/К2 2022 — разлика између измена
Пређи на навигацију
Пређи на претрагу
(додат К2 2022 из Веб дизајна) |
м (postavka je dostupna) |
||
| (Нису приказане 3 међуизмене другог корисника) | |||
| Ред 1: | Ред 1: | ||
{{tocright}} | {{tocright}} | ||
'''Drugi kolokvijum 2022. godine''' održan je 5. maja. Postavka je dostupna [https://rti.etf.bg.ac.rs/rti/si2vd/rokovi/VD_2122_K2.pdf sa stranice predmeta.]. ''jQuery'' biblioteka se uvozila preko minifikovanog fajla koji je bio dat u materijalima. | |||
== | == Решење == | ||
=== <code>zadatak.html</code> === | |||
<syntaxhighlight lang="html"> | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>K2 2022</title> | |||
<meta charset="utf-8" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<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> | |||
</syntaxhighlight> | |||
=== <code>zadatak.css</code> === | |||
<syntaxhighlight lang="css"> | |||
body { | |||
font-family: Arial, Helvetica, sans-serif; | |||
} | |||
main { | |||
padding: 20px; | |||
text-align: center; | |||
} | |||
table { | |||
border-collapse: collapse; | |||
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:not(.previous) { | |||
background-color: blue; | |||
} | |||
.playing td { | |||
pointer-events: all; | |||
} | |||
.playing .selected, .finished .selected { | |||
background-color: green; | |||
} | |||
== | .error .selected { | ||
background-color: red; | |||
} | |||
</syntaxhighlight> | |||
=== <code>zadatak.js</code> === | |||
<syntaxhighlight lang="javascript"> | |||
$(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').removeClass('previous'); | |||
} | |||
/** | |||
* 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 { | |||
$('.selected').addClass('previous'); | |||
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); | |||
} | |||
}); | |||
}); | |||
</syntaxhighlight> | |||
[[Категорија:Веб дизајн]] | [[Категорија:Веб дизајн]] | ||
[[Категорија:Рокови]] | [[Категорија:Рокови]] | ||
Тренутна верзија на датум 18. април 2024. у 12:50
Drugi kolokvijum 2022. godine održan je 5. maja. Postavka je dostupna sa stranice predmeta.. jQuery biblioteka se uvozila preko minifikovanog fajla koji je bio dat u materijalima.
Решење
zadatak.html
<!DOCTYPE html>
<html>
<head>
<title>K2 2022</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<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
body {
font-family: Arial, Helvetica, sans-serif;
}
main {
padding: 20px;
text-align: center;
}
table {
border-collapse: collapse;
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:not(.previous) {
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').removeClass('previous');
}
/**
* 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 {
$('.selected').addClass('previous');
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);
}
});
});