Przejdź do głównej treści
INF.03-07-26.06-SGCzerwiec 2026 · 42 kroki · ok. 77 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Plansza kółko i krzyżyk (Wersja podstawowa)

Rozwiązanie buduje planszę do gry w kółko i krzyżyk: baza gryTowarzyskie z jedną tabelą i cztery zapytania - filtr z warunkiem liczbowym, średnia z aliasem AVG(...) AS "średnia w minutach", zapytanie zagnieżdżone z MAX (wszystkie gry o najdłuższym czasie, nie tylko pierwsza) i wyszukiwanie fragmentu tekstu LIKE, potem strona gra.html z tabelą 3 x 3 wypełnioną obrazami nic.png, style w styl.css (trzy sekcje obok siebie, prawa ukryta przez visibility: hidden, komórka podświetlana przy kliknięciu) i skrypt JavaScript, który pilnuje kolejki graczy i podmienia obrazy.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy ma polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypt jest najpierw pisany najprościej, tak jak podpowiada tabela 1 arkusza (atrybut onclick, getElementById, style), a na końcu zostaje przerobiony na wersję z prawdziwych projektów: nasłuchiwacze zdarzeń, jedna ścieżka zamiast dwóch prawie identycznych gałęzi i - już ponad arkusz - sprawdzanie wygranej, które arkusz zapowiada „w przyszłości”. W tym arkuszu nie ma PHP.

Obok jest druga wersja tego rozwiązania - zakładka Nowoczesny kod (grid, data-*): te same punkty, ale układ na siatce CSS, skrypt w osobnym pliku z nasłuchiwaczami zdarzeń, a widoczność sekcji sterowana atrybutem data-player i regułami CSS.

Baza i obrazy nic.png, o.png, x.png pochodzą z prawdziwego archiwum pliki8 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy uruchomionej w MariaDB z XAMPP-a - na egzaminie robisz je sam, z całego ekranu. Plansza w podglądzie działa: od kroku ze skryptem można w nią klikać jak na ilustracji 4.

Jak liczą się punkty. Klucz ma 34 kryteria (R.1.1 - R.5.7), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 26 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Baza danych

    Kroki 1-7 · po tym etapie masz 6 z 34 kryteriów (pkt)

    Krok 1: Baza danych gryTowarzyskie

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie gryTowarzyskie, z zestawem polskich znaków (np. utf8_polish_ci).

    Rozpakuj pliki8.7z z pulpitu (hasło KoLko+KrzyZyk - wielkość liter ma znaczenie) do folderu z numerem zdającego: plik z tabelą i trzy obrazy nic.png, o.png, x.png. W phpMyAdmin: Nowa, nazwa gryTowarzyskie, porównywanie utf8_polish_ci. MariaDB na Windows i tak pokaże nazwę małymi literami (grytowarzyskie) - to ustawienie serwera, nie błąd.

  2. Krok 2: Import tabeli z pliku

    ok. 2 min
    Polecenie z arkusza

    Do utworzonej bazy zaimportuj tabelę z pliku gryTowarzyskie.sql.

    Wybierz bazę, potem Import → plik z archiwum → Wykonaj. W archiwum plik nazywa się grytowarzyskie.sql (małymi literami) - to ten sam plik, o którym mówi arkusz. Powstaje jedna tabela grytowarzyskie z 12 grami: nazwa, liczba graczy, potrzebne materiały i średni czas rozgrywki w minutach.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych gryTowarzyskie - plik import.png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.

    Print Screen, wklejasz do edytora grafiki i zapisujesz jako import.png - w tym arkuszu wszystkie zrzuty są w PNG. Na zrzucie zostawiasz zielony komunikat phpMyAdmina o udanym imporcie albo widok tabeli z rekordami.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: gry dla więcej niż 4 graczy

    Kryteria: ,

    R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające jedynie nazwy i potrzebne materiały do gier przeznaczonych dla więcej niż 4 graczy. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, potrzebne FROM grytowarzyskie WHERE liczbaGraczy > 4; oraz na zrzucie są dokładnie 2 rekordy z nazwami: Państwa - miasta i Kalambury

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie nazwy i potrzebne materiały do gier przeznaczonych dla więcej niż 4 graczy.

    • SELECT nazwa, potrzebne - tylko dwie kolumny, o które prosi arkusz,
    • FROM grytowarzyskie - jedyna tabela bazy,
    • WHERE liczbaGraczy > 4 - „więcej niż 4”, więc ostro większe: gry dla dokładnie 4 osób (Remik, Makao, Kości) odpadają.

    Wynik: 2 wiersze - Państwa - miasta i Kalambury, jak w kluczu. Zapytania zapisujesz w kwerendy.txt, zrzut jako kw1.png.

    Typowe błędy

    liczbaGraczy >= 4 dokłada trzy gry dla czterech osób - na zrzucie jest 5 wierszy zamiast 2.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa, potrzebne FROM grytowarzyskie WHERE liczbaGraczy > 4;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: średni czas gier dla dwóch osób

    Kryteria:

    R.1.4 Wykonane zapytanie 2 liczące średnią arytmetyczną czasu trwania gier, które są przeznaczone jedynie dla dwóch graczy, nazwa kolumny (alias) „średnia w minutach”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT AVG(czasRozgrywki) AS "średnia w minutach" FROM grytowarzyskie WHERE liczbaGraczy = 2; oraz na zrzucie jest widoczna wartość 12.7500 z dowolnym zaokrągleniem

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: liczące średnią arytmetyczną czasu trwania gier, które są przeznaczone jedynie dla dwóch graczy, nazwa kolumny (alias) „średnia w minutach”.

    • SELECT AVG(czasRozgrywki) - funkcja agregująca liczy średnią arytmetyczną z wierszy, które przejdą przez WHERE,
    • AS "średnia w minutach" - alias, czyli nazwa kolumny wyniku; ma spacje, więc musi być w cudzysłowie (albo w odwrotnych apostrofach),
    • WHERE liczbaGraczy = 2 - Statki (10), Kółko i krzyżyk (1), Piotruś Pan (20) i Domino (20).

    (10 + 1 + 20 + 20) / 4 = 12.7500 - MariaDB pokazuje średnią z czterema miejscami po przecinku, klucz przyjmuje dowolne zaokrąglenie. Zrzut: kw2.png.

    Typowe błędy

    Alias ze spacją bez cudzysłowu (AS średnia w minutach) kończy się błędem składni - serwer bierze „średnia” za alias, a dalszych słów nie rozumie.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, potrzebne FROM grytowarzyskie WHERE liczbaGraczy > 4;
    
    -- Zapytanie 2
    SELECT AVG(czasRozgrywki) AS "średnia w minutach" FROM grytowarzyskie WHERE liczbaGraczy = 2;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: gry o najdłuższym czasie rozgrywki

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające jedynie nazwy gier o najdłuższym czasie rozgrywki. Należy posłużyć się kwerendą zagnieżdżoną. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM grytowarzyskie WHERE czasRozgrywki = (SELECT MAX(czasRozgrywki) FROM grytowarzyskie); (sortowanie i LIMIT 1 jest błędem) oraz na zrzucie są dokładnie 2 rekordy: Państwa - miasta i Kalambury

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie nazwy gier o najdłuższym czasie rozgrywki. Jeśli kilka gier ma ten sam, najdłuższy czas rozgrywki to wszystkie ich nazwy powinny być wybrane. Należy posłużyć się kwerendą zagnieżdżoną.

    Zapytanie czytasz od środka:

    • (SELECT MAX(czasRozgrywki) FROM grytowarzyskie) - zapytanie zagnieżdżone zwraca jedną liczbę: najdłuższy czas, tu 30 minut,
    • SELECT nazwa FROM grytowarzyskie WHERE czasRozgrywki = (zapytanie wewnętrzne) - zapytanie zewnętrzne wybiera wszystkie gry, których czas jest równy tej liczbie.

    Wynik: 2 wiersze - Państwa - miasta i Kalambury, obie po 30 minut. Zrzut: kw3.png.

    Typowe błędy

    ORDER BY czasRozgrywki DESC LIMIT 1 zwraca tylko jedną grę (sprawdzone na tej bazie: same Państwa - miasta), a Kalambury z tym samym czasem przepadają. Klucz pisze wprost, że sortowanie z LIMIT 1 jest błędem.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, potrzebne FROM grytowarzyskie WHERE liczbaGraczy > 4;
    
    -- Zapytanie 2
    SELECT AVG(czasRozgrywki) AS "średnia w minutach" FROM grytowarzyskie WHERE liczbaGraczy = 2;
    
    -- Zapytanie 3
    SELECT nazwa FROM grytowarzyskie WHERE czasRozgrywki = (SELECT MAX(czasRozgrywki) FROM grytowarzyskie);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: gry karciane dla mniej niż 4 graczy

    Kryteria:

    R.1.6 Wykonane zapytanie 4 wybierające jedynie nazwy gier karcianych (pole potrzebne zawiera cząstkę „karty”) przeznaczonych dla mniej niż 4 graczy. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM grytowarzyskie WHERE potrzebne LIKE "%karty%" AND liczbaGraczy < 4; lub "karty%" oraz na zrzucie są dokładnie 3 rekordy: Piotruś Pan, Pasjans, Tysiąc

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: wybierające jedynie nazwy gier karcianych (pole potrzebne zawiera cząstkę „karty”) przeznaczonych dla mniej niż 4 graczy.

    • potrzebne LIKE '%karty%' - znak % zastępuje dowolny ciąg znaków (także pusty), więc wzorzec pasuje do „Karty” i do „Karty do Piotrusia”,
    • AND liczbaGraczy < 4 - oba warunki naraz; Remik i Makao (po 4 graczy) odpadają.

    Wynik: 3 wiersze - Piotruś Pan, Pasjans, Tysiąc. W bazie jest „Karty” z wielkiej litery, a we wzorcu „karty” z małej - mimo to wiersze się znajdują, bo porównywanie z końcówką _ci (case insensitive) nie rozróżnia wielkości liter. Sprawdzone: z LIKE BINARY wynik byłby pusty. Zrzut: kw4.png.

    Typowe błędy

    LIKE 'karty' bez znaków % szuka napisu dokładnie równego „karty” i pomija „Karty do Piotrusia” - wynik ma 2 wiersze zamiast 3.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, potrzebne FROM grytowarzyskie WHERE liczbaGraczy > 4;
    
    -- Zapytanie 2
    SELECT AVG(czasRozgrywki) AS "średnia w minutach" FROM grytowarzyskie WHERE liczbaGraczy = 2;
    
    -- Zapytanie 3
    SELECT nazwa FROM grytowarzyskie WHERE czasRozgrywki = (SELECT MAX(czasRozgrywki) FROM grytowarzyskie);
    
    -- Zapytanie 4
    SELECT nazwa FROM grytowarzyskie WHERE potrzebne LIKE '%karty%' AND liczbaGraczy < 4;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Strona HTML

    Kroki 8-20 · po tym etapie masz 15 z 34 kryteriów (pkt)

    Krok 8: Plik gra.html w HTML5

    ok. 2 min
    Polecenie z arkusza

    Nazwa pliku gra.html. Zapisana w języku HTML5.

    Deklaracja <!DOCTYPE html> w pierwszej linii mówi przeglądarce, że to dokument HTML5. Plik zapisujesz jako gra.html w folderze z numerem zdającego, obok trzech obrazów z archiwum - strona będzie się do nich odwoływać samą nazwą.

    gra.html HTML nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  9. Krok 9: Język strony

    Kryteria:

    R.2.1 W pliku gra.html znajduje się deklaracja HTML5 <!DOCTYPE HTML> i deklaracja języka zawartości: polski np. <html lang="pl">

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    Atrybut lang="pl" w znaczniku <html>. Razem z deklaracją z poprzedniego kroku to kryterium R.2.1.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  10. Krok 10: Kodowanie polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Jawnie zastosowany właściwy standard kodowania polskich znaków.

    <meta charset="UTF-8"> jako pierwszy element <head> - bez niego „kółko” i „krzyżyk” mogą się wyświetlić jako krzaczki.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  11. Krok 11: Tytuł strony

    Kryteria:

    R.2.2 W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony "Gra"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „Gra”.

    <title> w <head> - tekst na karcie przeglądarki. Kodowanie i tytuł razem dają R.2.2.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  12. Krok 12: Podpięcie arkusza stylów

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony.

    Nazwa: styl.css (nie style.css). Klucz R.3.2 sprawdza też, że całe formatowanie pochodzi z tego pliku - żadnych atrybutów style w HTML-u ani bloku <style>.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  13. Krok 13: Bloki: nagłówek, blok główny z trzema sekcjami, stopka

    Kryteria:

    R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header, main -> section + section + section, footer (dopuszcza się stosowanie bloków pomocniczych)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: nagłówkowy, główny, stopka. Blok główny zawiera trzy bloki sekcji. Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.

    Dokładnie to, czego chce klucz R.2.3: header, main z trzema section, footer. Sekcje dostają identyfikatory po angielsku - left, middle, right - bo i styl, i skrypt muszą je rozróżnić: lewa i prawa będą się chować na zmianę. Na razie bloki stoją jeden pod drugim; obok siebie ustawisz je w CSS.

    gra.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <main>
            <section id="left">
            </section>
            <section id="middle">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  14. Krok 14: Nagłówek strony

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: Nagłówek pierwszego stopnia o treści: „Zagraj w kółko i krzyżyk”.

    <h1> w <header>.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
            </section>
            <section id="middle">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  15. Krok 15: Sekcja lewa: „Gra kółko”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku sekcji lewej: Nagłówek drugiego stopnia o treści: „Gra kółko”.

    <h2> w lewej sekcji. Ten blok będzie widoczny, gdy ruch należy do kółka.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  16. Krok 16: Tabela 3 x 3

    Kryteria:

    R.2.5 W bloku sekcji środkowej znajduje się tabela o trzech kolumnach i trzech wierszach (znaczniki <table>, <tr>, <td>)

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku sekcji środkowej: Tabela o trzech wierszach i trzech kolumnach.

    <table> z trzema wierszami <tr>, a w każdym trzy komórki <td> - razem dziewięć pól planszy (R.2.5). Kolumn nie deklaruje się osobno: tabela ma tyle kolumn, ile komórek jest w wierszu. Puste komórki mają na razie zerową wysokość, więc w podglądzie tabeli prawie nie widać.

    gra.html HTML zmienione: 17 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td></td>
                        <td></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td></td>
                        <td></td>
                    </tr>
                </table>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  17. Krok 17: Obraz nic.png w każdej komórce

    Kryteria: ,

    R.2.6 Na stronie znajduje się przynajmniej jeden obraz nic.png

    R.2.7 Wszystkie komórki tabeli są wypełnione obrazami

    ok. 2 min
    Polecenie z arkusza

    Każda komórka tabeli jest wypełniona obrazem nic.png.

    W każdej z dziewięciu komórek <img src="nic.png" alt="puste pole">. nic.png jest prawie całkowicie przezroczysty - to „puste pole”, w które gracz kliknie, a skrypt podmieni je na o.png albo x.png. Tekst alternatywny opisuje, co jest w polu. Obrazy mają po 200 x 200 px, więc tabela jest na razie bardzo duża; zmniejszy ją styl img.

    Typowe błędy

    Obraz tylko w części komórek kosztuje R.2.7 - wszystkie dziewięć pól musi mieć nic.png, bo inaczej nie ma w co kliknąć.

    gra.html HTML zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  18. Krok 18: Sekcja prawa: „Gra krzyżyk”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku sekcji prawej: Nagłówek drugiego stopnia o treści: „Gra krzyżyk”.

    Drugi <h2>, tym razem w prawej sekcji. Za chwilę styl ją ukryje - pojawi się dopiero, gdy ruch należy do krzyżyka.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  19. Krok 19: Odnośnik „Zagraj w statki” w nowym oknie

    Kryteria:

    R.3.3 Kliknięcie odnośnika „Zagraj w statki” powoduje otwarcie strony https://pl.battleship-game.org/ w nowym oknie przeglądarki

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku stopki: Odnośnik do strony https://pl.battleship-game.org/ o treści „Zagraj w statki”. Odnośnik otwiera się w nowym oknie.

    target="_blank" otwiera stronę w nowym oknie (karcie) przeglądarki - bez tego gra w statki zastąpiłaby planszę (R.3.3). Adres przepisujesz dokładnie, z https://.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  20. Krok 20: Stopka: autor gry

    Kryteria:

    R.2.4 W bloku nagłówkowym znajduje się <h1>: "Zagraj w kółko i krzyżyk", w bloku sekcji lewej <h2>: "Gra kółko", prawej <h2>: "Gra krzyżyk" (może być ukryty ), w stopce <p> z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Paragraf o treści „Grę opracował: ”, dalej wstawiony numer zdającego.

    Akapit <p> pod odnośnikiem. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Ten akapit zamyka komplet nagłówków i stopki z kryterium R.2.4: <h1>, dwa <h2> i <p> z numerem.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  21. Etap 3: Styl CSS

    Kroki 21-31 · po tym etapie masz 26 z 34 kryteriów (pkt)

    Krok 21: Plik styl.css: krój czcionki

    Kryteria:

    R.4.1 domyślne formatowanie selektorów (*): krój czcionki "Lucida Console" - jako pierwszy, monospace - jako ostatni

    ok. 1 min
    Polecenie z arkusza

    Domyślnie, dla wszystkich selektorów: krój czcionki Lucida Console, w przypadku braku monospace.

    Selektor * obejmuje wszystkie elementy. Nazwa kroju ze spacją idzie w cudzysłów, a po przecinku stoi krój zastępczy monospace - ogólna rodzina czcionek o stałej szerokości, której przeglądarka użyje, gdy Lucida Console nie ma w systemie (R.4.1).

    styl.css CSS nowy plik
    * {
        font-family: "Lucida Console", monospace;
    }
    Podgląd strony po tym kroku (gra.html)
  22. Krok 22: Ciało strony: tło i wyśrodkowanie

    Kryteria:

    R.4.5 wyrównanie tekstu: ciało strony - do środka

    ok. 1 min
    Polecenie z arkusza

    Dla ciała strony: kolor tła HoneyDew, tekst wyrównany do środka.

    Selektor body. text-align: center dziedziczą wszystkie bloki, więc nagłówki i stopka są wyśrodkowane, a obrazy (elementy liniowe) w komórkach też (R.4.5).

    styl.css CSS zmienione: 4 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    Podgląd strony po tym kroku (gra.html)
  23. Krok 23: Nagłówek i stopka: marginesy wewnętrzne

    ok. 1 min
    Polecenie z arkusza

    Dla bloków nagłówkowego i stopki: marginesy wewnętrzne 20 px.

    Jedna reguła dla dwóch selektorów oddzielonych przecinkiem. Margines wewnętrzny to padding (zewnętrzny to margin).

    styl.css CSS zmienione: 3 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    Podgląd strony po tym kroku (gra.html)
  24. Krok 24: Sekcje boczne: tło, szerokość, marginesy, zaokrąglenie

    Kryteria:

    R.4.2 kolor tła: ciało strony - HoneyDew, blok sekcji lewej i prawej - PaleGreen

    ok. 2 min
    Polecenie z arkusza

    Dla bloków sekcji lewej i prawej: kolor tła PaleGreen, szerokość 20%, marginesy wewnętrzne górny i dolny 80 px, boczne 0, zaokrąglenie rogów 40 px.

    Selektory identyfikatorów #left, #right. padding: 80px 0 - dwie wartości: pierwsza dla góry i dołu, druga dla boków. Tło PaleGreen razem z tłem HoneyDew ciała strony dają kryterium R.4.2. Szerokość 20% zadziała w pełni dopiero, gdy sekcje staną obok siebie.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    Podgląd strony po tym kroku (gra.html)
  25. Krok 25: Sekcja prawa ukryta

    Kryteria:

    R.4.8 blok sekcji prawej jest niewidoczny (visibility: hidden lub opacity: 0) (display: none jest błędem)

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo dla bloku sekcji prawej: blok jest niewidoczny (ukryty).

    visibility: hidden - blok jest niewidoczny, ale nadal zajmuje miejsce w układzie. Dzięki temu plansza nie skacze w bok, gdy sekcje lewa i prawa zamieniają się widocznością - na ilustracji 4 tabela stoi zawsze w tym samym miejscu (R.4.8).

    Typowe błędy

    display: none usuwa blok z układu: plansza przesuwa się przy każdym ruchu, a klucz wprost uznaje to za błąd.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    Podgląd strony po tym kroku (gra.html)
  26. Krok 26: Sekcja środkowa: szerokość i cień

    Kryteria:

    R.4.4 styl bloków sekcji lewej i prawej: zaokrąglenie rogów (border-radius) - 40px styl bloku sekcji środkowej: cień bloku box-shadow: 0 0 10px DarkGreen;

    ok. 1 min
    Polecenie z arkusza

    Dla bloku sekcji środkowej: szerokość 60%, cień bloku bez przesunięcia o rozmyciu 10 px i kolorze DarkGreen.

    box-shadow: 0 0 10px DarkGreen - kolejno przesunięcie w poziomie, przesunięcie w pionie, rozmycie i kolor. „Bez przesunięcia” to dwa zera, więc cień rozlewa się równo dookoła bloku. Razem z zaokrągleniem sekcji bocznych to kryterium R.4.4.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    Podgląd strony po tym kroku (gra.html)
  27. Krok 27: Układ trzech sekcji zgodny z ilustracją 3

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position; żaden blok nie zachodzi na inne bloki - sprawdzić w inspektorze)

    ok. 2 min
    Polecenie z arkusza

    Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.

    display: flex na bloku głównym ustawia trzy sekcje w jednym rzędzie, a ich szerokości 20% + 60% + 20% wypełniają cały wiersz. align-items: flex-start przyciąga sekcje do góry: bez tego flex rozciąga je na wysokość najwyższej (tabeli), a na ilustracji 2 zielony blok „Gra kółko” jest niski i stoi przy górnej krawędzi. Flex zamiast float, bo nie trzeba niczego czyścić (clear) przed stopką (R.3.1).

    Typowe błędy

    Suma szerokości ponad 100% (np. marginesy boczne dodane sekcjom) zawija albo ściska bloki - klucz każe sprawdzić w inspektorze, że żaden blok nie zachodzi na inny.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    main {
        display: flex;
        align-items: flex-start;
    }
    Podgląd strony po tym kroku (gra.html)
  28. Krok 28: Obraz: szerokość, marginesy, kursor

    Kryteria:

    R.4.7 styl obrazu: cursor: pointer;

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: szerokość 80%, marginesy zewnętrzne 10 px, typ kursora pointer.

    Selektor znacznika img, jak wymaga uwaga pod listą stylów. Szerokość 80% liczy się od komórki, więc obrazy dopasowują się do tabeli, a nie mają swoich 200 px. cursor: pointer zmienia kursor w rączkę - gracz widzi, że w pole da się kliknąć (R.4.7).

    styl.css CSS zmienione: 5 linii
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    main {
        display: flex;
        align-items: flex-start;
    }
    img {
        width: 80%;
        margin: 10px;
        cursor: pointer;
    }
    Podgląd strony po tym kroku (gra.html)
  29. Krok 29: Tabela: szerokość, marginesy, połączone obramowania

    Kryteria: ,

    R.4.3 szerokość: bloki sekcji lewej i prawej - 20%, środkowej - 60% (width lub grid-template- columns lub flex ), selektor img - 80%, selektor table - 90%

    R.4.6 marginesy wewnętrzne (padding ): blok nagłówkowy, stopka - 20px, bloki sekcji lewej i prawej - górny i dolny - 80px, boczne - 0 lub nieustawione marginesy zewnętrzne (margin ): obraz i tabela - 10px

    ok. 1 min
    Polecenie z arkusza

    Dla selektora tabeli: szerokość 90%, marginesy zewnętrzne 10 px, obramowanie tabeli i komórek połączone.

    border-collapse: collapse łączy sąsiednie obramowania komórek w jedną linię - bez tego każda komórka miałaby osobną ramkę z odstępem. Tu domykają się dwa kryteria zbierane przez kilka reguł: szerokości (sekcje 20% i 60%, obraz 80%, tabela 90% - R.4.3) i marginesy (nagłówek i stopka, sekcje boczne, obraz i tabela - R.4.6).

    styl.css CSS zmienione: 5 linii
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    main {
        display: flex;
        align-items: flex-start;
    }
    img {
        width: 80%;
        margin: 10px;
        cursor: pointer;
    }
    table {
        width: 90%;
        margin: 10px;
        border-collapse: collapse;
    }
    Podgląd strony po tym kroku (gra.html)
  30. Krok 30: Komórka: obramowanie

    Kryteria:

    R.4.9 obramowanie: selektor td - 3px SeaGreen dowolna, pojedyncza linia ciągła; tabela - border-collapse: collapse;

    ok. 1 min
    Polecenie z arkusza

    Dla selektora komórki tabeli: obramowanie linią ciągłą o szerokości 3 px i kolorze SeaGreen.

    Skrót border: grubość, styl (solid - linia ciągła) i kolor. Teraz widać siatkę planszy jak na ilustracji 2. Razem z border-collapse z poprzedniego kroku to kryterium R.4.9.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    main {
        display: flex;
        align-items: flex-start;
    }
    img {
        width: 80%;
        margin: 10px;
        cursor: pointer;
    }
    table {
        width: 90%;
        margin: 10px;
        border-collapse: collapse;
    }
    td {
        border: 3px solid SeaGreen;
    }
    Podgląd strony po tym kroku (gra.html)
  31. Krok 31: Komórka podświetlana przy kliknięciu

    Kryteria:

    R.4.10 gdy komórka tabeli zostanie kliknięta, kolor tła zmienia się na SeaGreen (np. :active lub za pomocą obsługi kliknięcia w JavaScript)

    ok. 1 min
    Polecenie z arkusza

    Gdy komórka tabeli zostanie kliknięta, kolor tła zmienia się na SeaGreen.

    Pseudoklasa :active działa, dopóki przycisk myszy jest wciśnięty na elemencie. Obrazy są przezroczyste, więc zielone tło komórki prześwituje spod nich. Przytrzymaj kliknięcie na polu w podglądzie (R.4.10). Klucz dopuszcza też zmianę tła w JavaScript, ale jedna linia CSS jest prostsza.

    Typowe błędy

    td:hover zmienia tło już po najechaniu kursorem, a arkusz mówi o kliknięciu - to inne zachowanie niż wymagane.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: "Lucida Console", monospace;
    }
    body {
        background-color: HoneyDew;
        text-align: center;
    }
    header, footer {
        padding: 20px;
    }
    #left, #right {
        background-color: PaleGreen;
        width: 20%;
        padding: 80px 0;
        border-radius: 40px;
    }
    #right {
        visibility: hidden;
    }
    #middle {
        width: 60%;
        box-shadow: 0 0 10px DarkGreen;
    }
    main {
        display: flex;
        align-items: flex-start;
    }
    img {
        width: 80%;
        margin: 10px;
        cursor: pointer;
    }
    table {
        width: 90%;
        margin: 10px;
        border-collapse: collapse;
    }
    td {
        border: 3px solid SeaGreen;
    }
    td:active {
        background-color: SeaGreen;
    }
    Podgląd strony po tym kroku (gra.html)
  32. Etap 4: JavaScript

    Kroki 32-38 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 32: Funkcja uruchamiana kliknięciem obrazu

    Kryteria: ,

    R.3.4 Dla przynajmniej jednego obrazu lub komórki tabeli zostało zdefiniowane zdarzenie kliknięcia, które uruchamia funkcję skryptu

    R.5.1 Skrypt w języku JavaScript zawiera przynajmniej jedną poprawną składniowo instrukcję wynikającą z treści zadania

    ok. 3 min
    Polecenie z arkusza

    Dla każdego obrazu, gdy zostanie kliknięty, uruchamia się skrypt.

    Skrypt piszesz w bloku <script> na końcu <body> - wtedy wszystkie elementy <img> są już w drzewie dokumentu (DOM), gdy przeglądarka go czyta (same pliki obrazów mogą się jeszcze pobierać, ale skryptowi to nie przeszkadza). Na razie jedna pusta funkcja makeMove(image) („wykonaj ruch”, nazwa po angielsku i mówiąca, co robi - R.5.1).

    Każdy z dziewięciu obrazów dostaje atrybut onclick="makeMove(this)" (zdarzenie z tabeli 1). Słowo this w atrybucie to właśnie kliknięty element, więc funkcja od razu wie, który obraz podmienić - nie trzeba nadawać obrazom dziewięciu identyfikatorów (R.3.4).

    Typowe błędy

    onclick="makeMove()" bez this też uruchomi funkcję, ale ta nie dostanie klikniętego obrazu i nie będzie wiedziała, co podmienić.

    gra.html HTML zmienione: 13 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            function makeMove(image) {
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  33. Krok 33: Zmienna z aktualnym graczem

    Kryteria: ,

    R.5.2 Zastosowana przynajmniej jedna zmienna lub funkcja oraz nazewnictwo jest w języku polskim lub angielskim i odzwierciedla cel zastosowania

    R.5.3 Gra rozpoczyna się od kółka (np. ustawiona wartość początkowa zmiennej)

    ok. 1 min
    Polecenie z arkusza

    Stan początkowy: aktualny gracz to kółko.

    Zmienna currentPlayer zapisana poza funkcją - żyje przez cały czas otwarcia strony i pamięta, czyja jest kolejka między kliknięciami. Wartość początkowa 'o' oznacza, że grę zaczyna kółko (R.5.3). let, nie const, bo wartość będzie się zmieniać. Nazwa mówi, co przechowuje (R.5.2).

    Typowe błędy

    Zmienna zadeklarowana wewnątrz funkcji (let currentPlayer = 'o' w makeMove) przy każdym kliknięciu startuje od nowa - zawsze gra kółko i naprzemienność przepada.

    gra.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  34. Krok 34: Kółko: obraz o.png w klikniętym polu

    ok. 2 min
    Polecenie z arkusza

    Gdy gracz kółko kliknie w komórkę tabeli z obrazem nic.png: w komórce jest podmieniany obraz na o.png.

    Instrukcja warunkowa sprawdza, kto gra. Dla kółka zmieniasz atrybut src klikniętego obrazu (element.attribute_name = "wartość" z tabeli 1) - przeglądarka od razu wczytuje o.png. Kliknij pole w podglądzie: pojawia się kółko. Na razie każde kolejne kliknięcie też rysuje kółko, bo gracz się nie zmienia.

    Typowe błędy

    if (currentPlayer = 'o') z jednym = to przypisanie, a nie porównanie - warunek zawsze jest prawdziwy i krzyżyk nigdy nie zagra.

    gra.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (currentPlayer == 'o') {
                    image.src = 'o.png';
                }
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  35. Krok 35: Kółko: zamiana widocznych sekcji

    ok. 2 min
    Polecenie z arkusza

    Blok sekcji lewej staje się ukryty. Blok sekcji prawej staje się widoczny.

    document.getElementById('left') znajduje sekcję po identyfikatorze, a .style.visibility (tabela 1: element.style.property_name) nadpisuje dla niej wartość z CSS. Lewa dostaje 'hidden', prawa 'visible' - po ruchu kółka widać „Gra krzyżyk”, jak w kroku 2 ilustracji 4.

    gra.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (currentPlayer == 'o') {
                    image.src = 'o.png';
                    document.getElementById('left').style.visibility = 'hidden';
                    document.getElementById('right').style.visibility = 'visible';
                }
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  36. Krok 36: Kółko: kolejka przechodzi na krzyżyk

    Kryteria:

    R.5.4 Uczestnicy grają naprzemiennie: raz kółko, raz krzyżyk (wystarczy np. warunek sprawdzający, kto aktualnie gra, oraz zmiana tej wartości na inną lub przeciwną )

    ok. 1 min
    Polecenie z arkusza

    Aktualny gracz jest zmieniany na krzyżyk.

    Na końcu gałęzi kółka currentPlayer = 'x'. Przy następnym kliknięciu warunek currentPlayer == 'o' nie będzie spełniony - kolejka przeszła na drugiego gracza. To właśnie sprawdza klucz w R.5.4: warunek, kto gra, i zmiana tej wartości.

    gra.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (currentPlayer == 'o') {
                    image.src = 'o.png';
                    document.getElementById('left').style.visibility = 'hidden';
                    document.getElementById('right').style.visibility = 'visible';
                    currentPlayer = 'x';
                }
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  37. Krok 37: Krzyżyk: obraz x.png, sekcje i powrót do kółka

    Kryteria: ,

    R.5.5 Kiedy ruch należy do kółka, wyświetlony jest blok sekcji lewej, a ukryty prawej. Kiedy ruch należy do krzyżyka wyświetlony jest blok sekcji prawej, a ukryty lewej (dopuszcza się również zastosowanie display= "none")

    R.5.6 Po kliknięciu komórki tabeli lub obrazu nic.png, kiedy ruch należy do kółka, wyświetlany jest tam obraz o.png, a kiedy ruch należy do krzyżyka - obraz x.png

    ok. 3 min
    Polecenie z arkusza

    Gdy gracz krzyżyk kliknie w komórkę tabeli z obrazem nic.png: w komórce jest podmieniany obraz na x.png, blok sekcji lewej staje się widoczny, blok sekcji prawej staje się ukryty, aktualny gracz jest zmieniany na kółko.

    Gałąź else to lustrzane odbicie gałęzi kółka: obraz x.png, lewa sekcja widoczna, prawa ukryta, kolejka wraca do 'o'. Gracze grają już na zmianę - zagraj w podglądzie cztery ruchy z ilustracji 4 (R.5.5, R.5.6).

    gra.html HTML zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (currentPlayer == 'o') {
                    image.src = 'o.png';
                    document.getElementById('left').style.visibility = 'hidden';
                    document.getElementById('right').style.visibility = 'visible';
                    currentPlayer = 'x';
                } else {
                    image.src = 'x.png';
                    document.getElementById('left').style.visibility = 'visible';
                    document.getElementById('right').style.visibility = 'hidden';
                    currentPlayer = 'o';
                }
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  38. Krok 38: Zajęte pole: brak akcji

    Kryteria:

    R.5.7 Jeżeli w komórce tabeli znaduje się obraz kółka lub krzyżyka, ponowne kliknięcie w komórkę tabeli lub w obraz nie powoduje zmian obrazu

    ok. 3 min
    Polecenie z arkusza

    Gdy dowolny gracz kliknie komórkę tabeli z obrazem kółka lub krzyżyka – brak akcji.

    Wszystko, co dotąd zostało napisane, obejmujesz warunkiem: ruch wykonuje się tylko wtedy, gdy w polu jest jeszcze nic.png. Kliknięcie w kółko albo krzyżyk nie spełnia warunku, więc nic się nie dzieje - ani obraz, ani kolejka się nie zmieniają (R.5.7).

    Dlaczego getAttribute('src'), a nie image.src? Właściwość src zwraca pełny adres obrazu (np. http://localhost/.../nic.png), więc porównanie z samym 'nic.png' nigdy by się nie udało. getAttribute oddaje dokładnie to, co jest zapisane w atrybucie. Sprawdź w podglądzie: kliknięcie zajętego pola nie zmienia gracza.

    Typowe błędy

    if (image.src == 'nic.png') jest zawsze fałszywe (pełny adres) - plansza przestaje reagować na jakiekolwiek kliknięcie.

    gra.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                        <td><img src="nic.png" alt="puste pole" onclick="makeMove(this)"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (image.getAttribute('src') == 'nic.png') {
                    if (currentPlayer == 'o') {
                        image.src = 'o.png';
                        document.getElementById('left').style.visibility = 'hidden';
                        document.getElementById('right').style.visibility = 'visible';
                        currentPlayer = 'x';
                    } else {
                        image.src = 'x.png';
                        document.getElementById('left').style.visibility = 'visible';
                        document.getElementById('right').style.visibility = 'hidden';
                        currentPlayer = 'o';
                    }
                }
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  39. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 39-41 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 39: Nasłuchiwacze zamiast dziewięciu atrybutów onclick

    ok. 3 min
    Polecenie z arkusza

    Dla każdego obrazu, gdy zostanie kliknięty, uruchamia się skrypt.

    Dziewięć kopii onclick="makeMove(this)" to dziewięć miejsc do poprawiania przy każdej zmianie. W prawdziwych projektach HTML opisuje tylko strukturę, a zachowanie dopina skrypt: querySelectorAll('td img') (tabela 1) zwraca wszystkie obrazy z komórek, a pętla for...of dodaje każdemu nasłuchiwacz addEventListener('click', ...). Funkcja anonimowa woła makeMove(field) z właściwym obrazem - tak jak wcześniej this. Stara postać obrazu zostaje w komentarzu nad tabelą.

    Klucz R.3.4 przyjmuje obie drogi. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    Typowe błędy

    field.addEventListener('click', makeMove(field)) z nawiasami wywołuje funkcję od razu przy wczytaniu strony - wszystkie pola zapełniłyby się na zmianę kółkami i krzyżykami bez żadnego kliknięcia.

    gra.html HTML zmienione: 18 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <!-- wersja z egzaminu: <img src="nic.png" alt="puste pole" onclick="makeMove(this)"> -->
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (image.getAttribute('src') == 'nic.png') {
                    if (currentPlayer == 'o') {
                        image.src = 'o.png';
                        document.getElementById('left').style.visibility = 'hidden';
                        document.getElementById('right').style.visibility = 'visible';
                        currentPlayer = 'x';
                    } else {
                        image.src = 'x.png';
                        document.getElementById('left').style.visibility = 'visible';
                        document.getElementById('right').style.visibility = 'hidden';
                        currentPlayer = 'o';
                    }
                }
            }
    
            // zamiast atrybutu onclick w każdym obrazie
            const fields = document.querySelectorAll('td img');
            for (const field of fields) {
                field.addEventListener('click', function () {
                    makeMove(field);
                });
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  40. Krok 40: Jedna ścieżka zamiast dwóch gałęzi i opis pola dla czytnika

    ok. 4 min
    Polecenie z arkusza

    Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.

    Gałęzie kółka i krzyżyka różniły się tylko literą - to zaproszenie do błędu (poprawka w jednej, zapomniana w drugiej). Teraz:

    • zajęte pole kończy funkcję od razu (return) - zamiast obejmować całą treść warunkiem,
    • nazwa obrazu powstaje z gracza: currentPlayer + '.png' daje o.png albo x.png,
    • operator warunkowy warunek ? a : b zmienia gracza i ustawia widoczność obu sekcji,
    • przy okazji alt dostaje „kółko” albo „krzyżyk” - czytnik ekranu nie mówi już „puste pole” o zajętym polu.

    Plansza działa tak samo, stara funkcja zostaje w komentarzu /* */. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    gra.html HTML zmienione: 13 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <!-- wersja z egzaminu: <img src="nic.png" alt="puste pole" onclick="makeMove(this)"> -->
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
    
            function makeMove(image) {
                if (image.getAttribute('src') != 'nic.png') {
                    return;
                }
                image.src = currentPlayer + '.png';
                image.alt = (currentPlayer == 'o') ? 'kółko' : 'krzyżyk';
                currentPlayer = (currentPlayer == 'o') ? 'x' : 'o';
                document.getElementById('left').style.visibility = (currentPlayer == 'o') ? 'visible' : 'hidden';
                document.getElementById('right').style.visibility = (currentPlayer == 'x') ? 'visible' : 'hidden';
            }
    
            /* wersja z egzaminu:
            function makeMove(image) {
                if (image.getAttribute('src') == 'nic.png') {
                    if (currentPlayer == 'o') {
                        image.src = 'o.png';
                        document.getElementById('left').style.visibility = 'hidden';
                        document.getElementById('right').style.visibility = 'visible';
                        currentPlayer = 'x';
                    } else {
                        image.src = 'x.png';
                        document.getElementById('left').style.visibility = 'visible';
                        document.getElementById('right').style.visibility = 'hidden';
                        currentPlayer = 'o';
                    }
                }
            }
            */
    
            // zamiast atrybutu onclick w każdym obrazie
            const fields = document.querySelectorAll('td img');
            for (const field of fields) {
                field.addEventListener('click', function () {
                    makeMove(field);
                });
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  41. Krok 41: Ponad arkusz: rozstrzyganie wygranej

    ok. 5 min
    Polecenie z arkusza

    Rozstrzyganie wygranej zostanie zaimplementowane w przyszłości – nie trzeba sprawdzać czy dany układ kółek i krzyżyków daje wygraną.

    Arkusz zapowiada to „w przyszłości” - tu pokazujesz, jak taka rozbudowa wygląda. Tablica LINES zawiera osiem trójek numerów pól (trzy wiersze, trzy kolumny, dwie przekątne), licząc od 0 w kolejności, w jakiej obrazy stoją w tabeli. Funkcja checkWinner() sprawdza każdą trójkę: jeśli trzy pola mają ten sam obraz i nie jest to nic.png, zwraca zwycięzcę. Po wygranej zmienna gameOver blokuje dalsze ruchy, a w nagłówku pojawia się komunikat w nowym akapicie <p id="message">.

    Zagraj w podglądzie trzy kółka w rzędzie. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza, a arkusz wprost tego nie wymaga.

    gra.html HTML zmienione: 21 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gra</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zagraj w kółko i krzyżyk</h1>
            <p id="message"></p>
        </header>
        <main>
            <section id="left">
                <h2>Gra kółko</h2>
            </section>
            <section id="middle">
                <!-- wersja z egzaminu: <img src="nic.png" alt="puste pole" onclick="makeMove(this)"> -->
                <table>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                    <tr>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                        <td><img src="nic.png" alt="puste pole"></td>
                    </tr>
                </table>
            </section>
            <section id="right">
                <h2>Gra krzyżyk</h2>
            </section>
        </main>
        <footer>
            <a href="https://pl.battleship-game.org/" target="_blank">Zagraj w statki</a>
            <p>Grę opracował: Bartosz Bryniarski</p>
        </footer>
        <script>
            let currentPlayer = 'o';
            let gameOver = false;
            const LINES = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]];
    
            function checkWinner() {
                const cells = document.querySelectorAll('td img');
                for (const line of LINES) {
                    const first = cells[line[0]].getAttribute('src');
                    if (first != 'nic.png' && first == cells[line[1]].getAttribute('src') && first == cells[line[2]].getAttribute('src')) {
                        return first;
                    }
                }
                return null;
            }
    
            function makeMove(image) {
                if (gameOver || image.getAttribute('src') != 'nic.png') {
                    return;
                }
                image.src = currentPlayer + '.png';
                image.alt = (currentPlayer == 'o') ? 'kółko' : 'krzyżyk';
                const winner = checkWinner();
                if (winner) {
                    gameOver = true;
                    document.getElementById('message').innerText = (winner == 'o.png') ? 'Wygrało kółko!' : 'Wygrał krzyżyk!';
                    return;
                }
                currentPlayer = (currentPlayer == 'o') ? 'x' : 'o';
                document.getElementById('left').style.visibility = (currentPlayer == 'o') ? 'visible' : 'hidden';
                document.getElementById('right').style.visibility = (currentPlayer == 'x') ? 'visible' : 'hidden';
            }
    
            /* wersja z egzaminu:
            function makeMove(image) {
                if (image.getAttribute('src') == 'nic.png') {
                    if (currentPlayer == 'o') {
                        image.src = 'o.png';
                        document.getElementById('left').style.visibility = 'hidden';
                        document.getElementById('right').style.visibility = 'visible';
                        currentPlayer = 'x';
                    } else {
                        image.src = 'x.png';
                        document.getElementById('left').style.visibility = 'visible';
                        document.getElementById('right').style.visibility = 'hidden';
                        currentPlayer = 'o';
                    }
                }
            }
            */
    
            // zamiast atrybutu onclick w każdym obrazie
            const fields = document.querySelectorAll('td img');
            for (const field of fields) {
                field.addEventListener('click', function () {
                    makeMove(field);
                });
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (gra.html)
  42. Etap 6: Oddanie pracy

    Krok 42 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 42: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz planszę.

    W folderze z numerem zdającego: gra.html, styl.css, kwerendy.txt, import.png, kw1.png - kw4.png, nic.png, o.png, x.png i przeglądarka.txt. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

    Podgląd strony bez zmian - taki jak po kroku 41.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.