Veb dizajn/Jun K2 2022

Izvor: SI Wiki
< Веб дизајн
Datum izmene: 18. april 2024. u 11:48; autor: DjoleRkc (razgovor | doprinosi) (postavka je dostupna)
(razl) ← Starija izmena | Trenutna verzija (razl) | Novija izmena → (razl)
Pređi na navigaciju Pređi na pretragu

Drugi kolokvijum u junskom roku 2022. godine održan je 14. juna. Postavka je dostupna sa stranice predmeta.. jQuery biblioteka se uvozila preko minifikovanog fajla koji je bio dat u materijalima.

Rešenje

zadatak.html

<!DOCTYPE html>
<html>
    <head>
        <title>Jun 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></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </table>
            <form>
                <input type="range" id="n" min="1" max="9">
                <input type="submit" id="start" value="Počni">
            </form>
            <p class="hidden">Igra je završena!</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;
    font-size: 48px;
    height: 100px;
    pointer-events: none;
    width: 100px;
}

form {
    margin-top: 20px;
}

.hidden {
    display: none;
}

.playing td {
    pointer-events: all;
}

.bomb {
    color: red;
}

zadatak.js

$(function() {
    'use strict';
    // Matrica polja
    const cells = Array(4)
        // Napunimo niz dužine 4
        .fill()
        // i za svako polje tog niza 
        .map(
            (_, i) => $('tr')
                .eq(i)
                // dovučemo <td>ove u tom redu
                .children()
                // pretvorimo ih u niz
                .toArray()
                // a zatim članove tog niza pretvorimo u objekte
                .map(el => ({
                    // koji sadrže jQuery element,
                    $element: $(el),
                    // podatak da li je polje bomba
                    isBomb: false,
                    // kao i podatak da li je polje otkriveno
                    uncovered: false
                }))
        );
    // Broj polja ostao za otkrivanje
    let fieldsLeft = 0;
    // DOM elementi
    const $startButton = $('#start');
    const $n = $('#n');
    const $message = $('p');
    const $table = $('table');
    /**
     * Generiše indekse polja na tabli sa bombama, za dat broj polja
     * koji se generiše i ukupan broj polja.
     *
     * Generisani indeks se posle koristi kako bi se podelio na red i kolonu
     * polja sa bombom.
     * @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];
    }
    /**
     * Za svaku ćeliju poziva funkciju kojoj prosleđuje red, kolonu i podatke
     * iz te ćelije.
     * @param {(cell, row, col) => void} callback Funkcija koja se poziva za
     *                                            svaku ćeliju
     */
    function forEachCell(callback) {
        cells.forEach(
            (row, rowIndex) => row.forEach((cell, colIndex) =>
                callback(cell, rowIndex, colIndex)
        ));
    }
    /**
     * Nalazi broj bombi oko ćelije na zadatoj poziciji.
     * @param {number} row Red ćelije
     * @param {number} col Kolona ćelije
     * @returns {number} Broj bombi oko ćelije
     */
    function countBombs(row, col) {
        let count = 0;
        if (row > 0) {
            count += cells[row-1][col].isBomb;
        }
        if (row < 3) {
            count += cells[row+1][col].isBomb;
        }
        if (col > 0) {
            count += cells[row][col-1].isBomb;
        }
        if (col < 3) {
            count += cells[row][col+1].isBomb;
        }
        if (row > 0 && col > 0) {
            count += cells[row-1][col-1].isBomb;
        }
        if (row > 0 && col < 3) {
            count += cells[row-1][col+1].isBomb;
        }
        if (row < 3 && col > 0) {
            count += cells[row+1][col-1].isBomb;
        }
        if (row < 3 && col < 3) {
            count += cells[row+1][col+1].isBomb;
        }
        return count;
    }
    /**
     * Dovodi igru u završno stanje.
     */
    function endGame() {
        $message.removeClass('hidden');
        $table.removeClass('playing');
        $startButton.removeAttr('disabled');
    }
    /**
     * Rukovalac pritiska na dugme za početak.
     * @param {ClickEvent} event Podaci događaja o pritisku na dugme
     */
    $startButton.click(event => {
        event.preventDefault();
        $startButton.attr('disabled', '');
        $table.addClass('playing');
        $message.addClass('hidden');
        forEachCell(cell => {
            cell.isBomb = false;
            cell.uncovered = false;
            cell.$element.text('').removeClass('bomb');
        });
        const n = Number($n.val());
        fieldsLeft = 16 - n;
        const selectedFields = selectFields(n, $('td').length);
        selectedFields.forEach(index => {
            cells[index % 4][Math.floor(index / 4)].isBomb = true;
        });
        console.info(cells.map(row => row
            .map(cell => cell.isBomb ? 'X' : '-')
            .join(' ')
        ).join('\n'));
    });
    /**
     * Rukovođenje klikom na ćeliju.
     */
    forEachCell((cell, row, col) => {
        cell.$element.click(() => {
            if (cell.uncovered) {
                return;
            }
            cell.uncovered = true;
            const {$element, isBomb} = cell;
            if (isBomb) {
                // Polje je bomba, otkrivamo sve bombe
                forEachCell(({$element, isBomb}) => {
                    if (isBomb) {
                        $element.text('💣💣').addClass('bomb');
                    }
                });
                endGame();
            } else {
                $element.text(countBombs(row, col));
                if (--fieldsLeft === 0) {
                    endGame();
                }
            }
        });
    });
});