In deze oefenzitting zullen we een Sliding Puzzle maken in HTML, CSS en JavaScript.
⚠️ Deze oefenzitting wordt afgewerkt in twee sessies. Zorg ervoor dat je klaar bent met deel 1 en deel 2 voor de start van de tweede oefenzitting.
Start met deze oefenzitting door de repository te clonen naar je eigen machine.
$ git clone https://github.com/informatica-werktuigen/oefenzitting-javascript.git
Video-playlist ter voorbereiding van deze oefenzitting:
- ./hoorcollege: in deze folder kan je de verschillende codevoorbeelden uit de les nakijken
- ./oplossing: in deze folder plaats je je eigen oplossing voor deze oefenzitting
Het is mogelijk HTML, CSS en JavaScript te schrijven met elke mogelijke text editor, zelfs met kladblok. Het is uiteraard een goed idee gebruik te maken van een editor met minstens syntax highlighting.
Op de Linux-machines in de Software labo's kan je gebruik maken van verschillende geïnstalleerde editors zoals Visual Studio Code of Atom.
Als je verkiest op je eigen machine te werken, dan kan je deze editors downloaden en installeren via deze links: Visual Studio Code, Atom.
Andere editors zijn uiteraard ook toegestaan.
HTML-pagina's worden geopend met een web browser.
Elk van deze browsers heeft een eigen toolchain die kan helpen bij het lezen van HTML, CSS en JavaScript.
Deze oefenzitting neemt aan dat gebruik gemaakt wordt van Firefox.
Indien je gebruik maakt van een andere web browser is het je eigen taak om de equivalente functionaliteiten (debugger, console, ...) in die browser te vinden.
Voor je begint aan de oefenzitting is het een goed idee vertrouwd te geraken met de Developer Tools van Firefox.
- Open het laatste voorbeeld uit de oefenzitting (./hoorcollege/ex7/index.html) in Firefox.
cd oefenzitting-javascript
firefox hoorcollege/ex7/index.html
- Druk op de toetsenbordcombinatie CTRL+SHIFT+I (of COMMAND+OPTION+I voor Mac) om de developer Tools te openen.
⚠️ Let er op dat alle aanpassingen die je maakt in de Developer Tools tijdelijk zijn en ongedaan worden gemaakt na het verversen van de pagina. Gebruik voor permanente wijzigingen een editor naar keuze.
Voer onderstaande opdrachten uit met behulp van de Developer tools. Ververs indien nodig de pagina om eventuele wijzigingen ongedaan te maken.
- Verwijder met behulp van de Inspector de Reset-knop op de pagina.
- Open de console. Voer deze functie uit:
update_board(my_board, 0, 1, 2)
. Observeer wat er gebeurt. - Verander de waarden in
update_board
en probeer op die manier een X te plaatsen in het middelste vakje. Hint: met de ↑-toets kan je het vorig ingevoerde commando terug ophalen. - Zoek en open het bestand
code.js
in de Debugger. Plaats een breakpoint in de binnenste for-loop van de functiegenerate_board_html
door op de nummer van die regel te klikken. Klik vervolgens op een vakje van het spelbord. Inspecteer de waarden van de variabeletable_inner_html
in de rechtse kolom van de debugger (onder scopes). - Druk op de Run-pijl bovenaan om de code verder uit te voeren tot het volgende breakpoint. Observeer hoe de waarden van
table_inner_html
enrow_html
evolueren na elke iteratie van de lus. - Open de Style editor en zorg ervoor dat alle rode vakjes paars worden.
Open in de folder oplossing in je repository het bestand met de naam index.html
.
Dit bestand bevat een algemeen skelet dat je kan gebruiken voor elke mogelijke html-pagina.
HTML is een variant van XML waarmee je de lay-out van een webpagina kan beschrijven op een wijze die voor beide mens en machine interpreteerbaar is.
Een HTML-document maakt gebruik van tags met attributen, als volgt:
<tag attribute="value">content</tag>
<body>
Hello, world!
</body>
- Vervang de tekst Hello, world! in
index.html
door een tabel van 3x3. Maak hiervoor gebruik van de tags table, tr en td. Bekijk deze link indien je niet weet hoe je een HTML-tabel moet maken. - Vul in elke cel van de tabel een uniek nummer in van 1 tot en met 8.
- Laat 1 cel leeg. Deze cel stelt het lege vakje op de schuifpuzzel voor.
Om deze tabel wat groter, mooier en duidelijker te maken zullen we door middel van CSS stijlen toevoegen.
Met behulp van CSS kan je stijlen toekennen aan HTML-tags (en hun inhoud).
De basissyntax werkt als volgt:
tag {
property: value;
}
.class {
property: value;
}
#id {
property: value;
}
Onderstaande voorbeeldcode geeft de achtergrondkleur #fffff0
aan elke table-tag in het HTML-document.
table {
background-color: #fffff0;
}
Om stijlen toe te kennen aan individuele tags, kunnen we ze een klasse geven. Het is mogelijk om dezelfde klasse aan meerdere tags toe te kennen.
Onderstaande code kent de klasse my_class toe aan de div en de p tag.
<div class="my_class"></div>
<p class="my_class"></p>
In de CSS stylesheet kunnen we nu de stijl van de klasse my_class vastleggen.
.my_class{
border: 1px solid #000000;
}
Als resultaat krijgen beide de div en de paragraaf (p) een zwarte doorlopende rand van 1 pixel.
- Open het bestand
stylesheet.css
.
Probeer met behulp van CSS de lay-out in de afbeelding bovenaan deze pagina na te maken. De kleuren mag je zelf kiezen.
Zorg ervoor dat:
- De vakjes groot genoeg zijn
- Elk vakje zichtbaar gescheiden is door een rand
- Het lege vakje dezelfde achtergrondkleur heeft als de tabel zelf
- De tekst in de vakjes gecentreerd is
Als voorbeeld kan je kijken naar het bestand ./hoorcollege/ex7/stylesheet.css.
Alle mogelijke stijlen die je via CSS kan toekennen kan je vinden op https://www.w3schools.com/cssref/.
Een sliding puzzle, net als veel andere bordspellen, kunnen we in JavaScript voorstellen als een tweedimensionale lijst.
Onderstaande code definieert een tweedimensionale lijst die de Sliding Puzzle uit de afbeelding bovenaan deze pagina voorstelt. We hebben de waarde 0 gekozen voor het lege vakje.
let my_puzzle = [[0, 1, 2],
[7, 4, 8],
[3, 5, 6]];
Het doel van deze sectie is om de JavaScript-functie generate_puzzle_html
te schrijven. Deze functie zet de bovenstaande lijstrepresentatie om in een HTML-string.
Wanneer de sectie correct is uitgevoerd en je index.html
opent met Firefox, zal je puzzel visueel verschijnen.
Onderstaande code toont het einddoel van deze sectie met behulp van de JavaScript-console.
De functie generate_puzzle_html
wordt opgeroepen met als input de lijstrepresentatie van onze puzzel.
Het resultaat van de functie is een JavaScript-string met daarin een HTML-voorstelling van diezelfde puzzel.
De JavaScript-functie generate_puzzle_html
converteert dus de lijstrepresentatie in my_puzzle
naar een HTML-representatie:
generate_puzzle_html(my_puzzle)
>> "<table><tr><td class=\"emptyTile\"></td><td>1</td><td>2</td></tr><tr><td>7</td><td>4</td><td>8</td></tr><tr><td>3</td><td>5</td><td>6</td></tr></table>"
- Voeg aan je HTML-bestand een div toe met als id puzzle_container. Hierin zal de gegenereerde HTML-code toegevoegd worden.
<div id="puzzle_container"></div>
- Vul nu de functie generate_puzzle_html in code.js aan zodat het resultaat van de functie een HTML-weergave is van de meegegeven puzzel. De uitvoering van generate_puzzle_html moet in de JavaScript-console een HTML-string als resultaat geven.
Baseer je op de HTML die je geschreven hebt in het eerste deel van deze oefenzitting.
Indien de code correct werkt, zal de pagina na een refresh de gegenereerde sliding puzzle toevoegen aan puzzle_container
.
De code die hiervoor zorgt is reeds meegeleverd in de JavaScript-functie draw_puzzle
. Na de pagina te verversen zal je puzzel dus visueel verschijnen.
💡 Bestudeer voor tips de oplossing in ./hoorcollege/ex7/code.js. De functie generate_board_html van deze oefening werkt zeer gelijkaardig.
💡 Indien de code niet werkt zoals verwacht, open dan de Developer Tools van Firefox. Open vervolgens de debugger en plaats breakpoints op kritische punten in je code. Inspecteer de waarden van je variabelen en probeer te achterhalen wat fout loopt.
Op dit punt in de oefenzitting heeft je spel een lay-out die automatisch gegenereerd kan worden vanuit een interne lijstrepresentatie.
Indien je aan de start van de tweede oefenzitting nog niet op dit punt bent gekomen, kan je voor de volgende delen verder werken vanaf een modeloplossing.
Indien je eigen aanpassingen hebt gemaakt aan de bestanden in solution, zal je deze wijzigingen eerst moeten committen.
$ cd /pad/naar/oefenzitting-javascript
$ git add code.js
$ git add stylesheet.css
$ git add index.html
$ git commit -m "Eigen oplossing"
Deze code maakt een back-up van je eigen oplossingsbestanden. Je kan deze in de toekomst dus telkens herstellen.
Voer vervolgens de volgende commando's uit om de modeloplossing te laden:
$ git checkout deel2
Door dit commando uit te voeren wordt de inhoud van de modeloplossing in de folder solution geplaatst.
In deze sectie schrijven we JavaScript-functies die op basis van de interne lijstrepresentatie van een puzzel ons toelaten het spel te spelen.
Voeg onderstaande functies toe aan code.js
. Gebruik telkens de Console in de Developer Tools om deze functies te testen. De voorbeelden tonen telkens de console-output die we verwachten indien je functie correct is geschreven.
-
function check_game_complete(puzzle)
Deze functie krijgt als argument de puzzel (voorgesteld als lijst). De functie moet
true
returnen indien de sliding puzzle correct is opgelost, en 'false' op alle andere momenten. De puzzel is correct opgelost indien alle nummers in de juiste volgorde staan met het lege vakje onderaan rechts.- Implementeer de functie en test met behulp van de console:
>> check_game_complete(my_puzzle) false >> check_game_complete([[1, 2, 3], [4, 5, 6], [7, 8, 0]]) true
💡 Vergelijk twee lijsten door met een lus elk indivueel element apart te vergelijken
-
function swap_empty_square(puzzle, row, col)
Deze functie krijgt als invoer de huidige puzzel voorgesteld als lijst en een rij en kolom op het bord. De functie wisselt het vakje op die positie op het spelbord met het lege vakje.
- Implementeer de functie en test met behulp van de console:
>> swap_empty_square(my_puzzle, 1, 0) undefined >> draw_puzzle(my_puzzle) undefined
Na uitvoering van deze functies zou het lege vakje moeten wisselen met het vakje met waarde 7.
- Zorg er nu ook voor dat de wissel enkel wordt uitgevoerd indien het lege vakje naast de meegegeven positie ligt. Verifieer nadien opnieuw met de console.
-
function square_click_handler(cell)
Ten slotte schrijven we de functie die opgeroepen zal worden telkens wanneer we klikken op een plaats op het spelbord.
Met onderstaande code kan je opvragen op welke positie er geklikt werd:
let col = cell.cellIndex; let row = cell.parentNode.rowIndex;
- Implementeer deze functie.
- Zorg ervoor dat de code gebruik maakt van de functie
swap_empty_square
om het vakje waarop geklikt werd te wisselen met het lege vakje. - Zorg er vervolgens voor dat het spelbord opnieuw getekend wordt met behulp van
draw_puzzle
. - Controleer met
check_game_complete
of het spel correct is opgelost. - Indien het spel correct is opgelost, voer dan de code
alert("Proficiat!");
uit.
- Zorg ervoor dat de code gebruik maakt van de functie
Om dit te testen willen we ervoor zorgen dat wanneer er op een cel geklikt wordt,
square_click_handler
correct wordt opgeroepen.Maak hiervoor gebruik van het onclick attribuut.
Voeg aan de td-tags onclick toe als volgt.
<td onclick="square_click_handler(this)"></td>
- Zorg ervoor dat het onclick-attribuut correct mee toegevoegd wordt bij het genereren van de HTML-representatie van het bord.
✔️ Als dit correct uitgevoerd wordt, heb je nu een werkende Sliding Puzzle.
- Implementeer deze functie.
- Zorg ervoor dat het spelbord willekeurig gegenereerd wordt. Let erop dat niet alle schuifpuzzels oplosbaar zijn
- Zorg ervoor dat de de grootte van de schuifpuzzel gekozen kan worden door de speler (bijvoorbeeld 4x4 of 5x5)
- Voeg een timer toe die bijhoudt hoe lang je erover doet om een puzzel op te lossen