Opdrachten
Algemene informatie
Hier vind je de opdrachten voor de permanente evaluatie van SES+EES. De opdrachten voor deel 1 worden gemaakt door alle studenten (SES+EES). De opdrachten voor deel 2 worden enkel gemaakt door de studenten SES.
GitHub repository linken
Om de permanente evaluatie opdrachten in te dienen voor het vak Software Engineering Skills maken we gebruik van GitHub. In de lessen zal je onder begeleiding een gratis account aanmaken op dit platform. Je maakt de opdrachten in een repository die je aanmaakt via GitHub Classroom. Daarvoor moet je je GitHub gebruikersnaam linken aan je naam, zodat wij weten bij welke student de repository van ‘FluffyBunny’ hoort :). Zie de instructies bij de eerste opdracht voor meer details.
Naamgeving bij indienen (tags)
Om de verschillende (sub)opdrachten te identificeren wordt er gebruik gemaakt van “tags” bij het committen van je finale resultaat. (In de eerste lessen worden deze onderwerpen klassikaal uitgelegd zodat alle studenten de juiste werkwijze gebruiken).
De naamgeving: voor het committen van je resultaat van “Opdracht 1” gebruik je de tag v1, voor “Opdracht 2” gebruik je de tag v2, enzoverder.
Tags pushen naar github: git push --tags
Tags op github verwijderen: git push --delete origin <tagname>. Dit moet je doen als je bijvoorbeeld lokaal een tag verplaatst hebt.
Lokaal een tag deleten: git tag --delete <tagname>
Pushen van branches en tags naar de remote repository
Standaard worden lokale branches en tags niet altijd gepushed naar een remote repository, gebruik daarom volgende flags bij het push-command: $ git push --all --tags
Deadlines
Er is 1 deadline voor alle opdrachten van het eerste deel (SES+EES): vrijdag 23/03/2026 23u59.
De deadline voor alle opdrachten van het tweede deel (enkel SES) is vrijdag 15/05/2025 23u59.
Opdrachten deel 1 SES/EES
Hier vind je de opdrachten voor de permanente evaluatie van SES+EES. De opdrachten voor deel 1 worden gemaakt door alle studenten (SES+EES).
Github classroom link
Klik hier voor de invite van de assignment “SES en EES Opdrachten deel 1”.
Extra start files van andere start repositories downloaden in je eigen repo
Om jullie het leven makkelijk te maken, hebben we voor veel van de opdrachten al startcode geschreven in de vorm van een github repository. Die nieuwe repositories simpelweg clonen in een subdirectory van je eigen repository zorgt echter voor een aantal problemen. Die nieuwe directories met startcode worden dan namelijk als een submodule toegevoegd aan je main repo. Die repo wordt dus als een soort link beschouwd en aangezien die nieuwe repo niet van jullie zelf is ga je dan ook geen veranderingen aan die code kunnen pushen.
In de plaats moeten we die start-code-repositories als een subtree toevoegen. Dat heeft als voordeel dat je zelf gewoon wijzigingen kan aanbrengen, committen en pushen naar je eigen hoofd repository. Bovendien blijft er ook een zachte link met de originele start-code-repository zodat als hier iets aan wijzigt je die online wijzigingen nog wel kan fetchen. (Bijvoorbeeld als we merken dat er nog een foutje in de startcode stond!).
Zo een subtree aanmaken doe je dan op de volgende manier:
- Voeg de remote-start-code-repository toe aan je eigen repo met volgende commando:
- met
--prefix=geef je aan in welke subdirectory de inhoud van de externe repo moet komen. - je kan een specifieke branch meegeven (meestal
main) - met
--squashcondenseer je de git history van de externe repo tot één enkele commit. (Je kan deze optie weglaten als je toch de hele git history wil bekijken)
- Zodra de files in jouw repo staan, kan je ze bewerken zoals normaal. De changes worden dan onderdeel van de history van JOUW repository, onafhankelijk van de oorspronkelijke externe repository.
- Moesten er later toch wijzigingen aangebracht worden in de remote-start-code-repository die je wil fetchen dan kan je volgend commando gebruiken:
Waarschuwing
Heb je toch al zo een repo gecloned en is dit nu een een submodule waarvan je de changes niet kan committen dan kan je best je wijzigingen even kopieren naar een andere locatie buiten je repo. De subdirectory verwijderen en nu als subtree toevoegen en dan je oplossingen terug erin zetten.
Opdrachten rond Versiebeheer
Opdracht 1:
- Download volgende file
Candy_Crush_spelregels.txtvia rechtermuisklik, ‘opslaan als’ en sla de file op in volgende directory/folderopdracht1-4_Versiebeheer. Behoud de juiste naam! - Doe nu op de correcte manier een commit en tag de commit met
v1.
Opdracht 2:
- Los alle TODO’s in de file
Candy_Crush_spelregels.txtop.- Verander
<voornaam>en<naam>nog NIET, dit doe je in opdracht 3. - Los de
TODOop rond hoofdletters en kleine letters. - Los de
TODOop rond speciale snoepjes, verzin dus zelf vier namen en verwissel<naamSnoepje>steeds met jouw verzonnen naam.
- Verander
- Doe nu op de correcte manier een commit en tag de commit met
v2.
Opdracht 3:
- Maak een branch aan met als naam “
opdracht_branch”. - Switch naar die branch.
- In de file
Candy_Crush_spelregels.txtverander je nu<voornaam>en<achternaam>naar jouw voor- en achternaam. - Commit je aanpassingen in deze
opdracht_branchbranch. - Switch terug naar de
mainbranch en vul daar andere waarden in voor de auteur gegevens (Dit is bijvoorbeeld een bug in je software). - Commit nu je aanpassingen in deze
mainbranch. - Merge de
opdracht_branchnu met demainbranch. Hiervoor zal je dus ook het mergeconflict moeten oplossen. - Doe nu op de correcte manier een commit en tag de commit met
v3.
Laatste belangrijke stap!
Push nu je aanpassingen naar Github met behulp van git push --all --tags
Dankzij --all wordt je branch mee gepushed en dankzij --tags worden je tags mee gepushed.
Opdrachten rond Build Systems
Opdracht 4
In de subfolder
c/binnenin de folderopdracht4_BuildSystems:- Je moet de makefile aanpassen zodat het C-programma kan gecompiled+gelinked worden met
make compile, - dat de binaries en object files gedeletet worden met
make clean - en dat je project gerund kan worden met
make run(je moet hier ook flags kunnen meegeven). - De uiteindelijk binary moet in de root van je c-project (dus subfolder
cin de folderopdracht4_BuildSystems) directory staan met als naamfriendshiptester.bin. Er mag geen andere binary file in staan!
- Je moet de makefile aanpassen zodat het C-programma kan gecompiled+gelinked worden met
In de subfolder
java/binnenin de folderopdracht4_BuildSystems:- Schrijf een simpele makefile dat de volgende dingen kan doen:
compile: Compileert de bronbestanden naar de/build-directoryjar: packaged alle klassen naar een jar genaamd ‘app.jar’ in de ‘build’-directory met entrypoint de ‘App’-klasse.run: Voert de jar file uitclean: Verwijdert de ‘.class’-bestanden en het ‘.jar’-bestand uit de ‘build’-directory
- Schrijf een simpele makefile dat de volgende dingen kan doen:
In de subfolder
python/binnenin de folderopdracht4_BuildSystems:- Schrijf een simpele makefile dat de volgende dingen kan doen:
compile: Compileert de bronbestanden naar de single ‘friendshiptester.bin’ file in de “/dist”-directorytest: Voert de ‘app.py’ uitrun: Voert de ‘friendshiptester.bin’ uitclean: Verwijdert het ‘.bin’-bestand
- Schrijf een simpele makefile dat de volgende dingen kan doen:
Doe nu op de correcte manier een commit en tag de commit met
v4en push naar Github.
Opdrachten rond Dependency Management
Opdracht 5
- In de folder
opdracht5-6_DependencyManagementmaak je een javaproject met gradle aan in een subdirectory genaamd “checkneighbours” met package “be.ses”.- Je kan de package name meegeven met het ‘gradle init’ commando op de volgende manier:
gradle init --package be.ses
- Je kan de package name meegeven met het ‘gradle init’ commando op de volgende manier:
- In je
checkneighboursgradle project, moet je nu een klasse ‘CheckNeighboursInGrid’ maken en onderstaande static method in implementeren, los ook de TODO op:Voorbeeld: voor het volgende grid:
-> getSameNeighboursIds(grid, 4, 4, 5) returns [2,4,10]
Genereer een
checkneighbours.jarfile van deze Javaklasse in debuild/libsdirectory van je gradle project. Kopiëer de jar-file naar de folder “…/opdracht5-6_DependencyManagement/” (dus.../opdracht5-6_DependencyManagement/checkneighbours.jar).Doe nu op de correcte manier een commit en tag de commit met
v5en push naar Github.
Opdracht 6
In het gradle project
.../opdracht5-6_DependencyManagement/checkneighbours_examplemoet je alle TODO’s oplossen. (Je kan met de TODO tree extensie in VSCode gemakkelijk zien of je alle TODO’s gedaan hebt)- kopieer je
checkneighbours.jar(die in de directory.../opdracht5-6_DependencyManagement/zou moeten staan van opdracht 5) naar deapp/libdirectory van het gradle project ‘checkneighbours_example’. - Pas de
build.gradlein dat project ook aan zodat demain-method in deApp.javacorrect gebuild en gerund kan worden.
- kopieer je
Doe nu op de correcte manier een commit en tag de commit met
v6en push naar Github.
Opdrachten rond Test Driven Development
Opdracht 7
Voeg minstens 6 unittesten toe aan je gradle project
checkneighbours(in de directory.../opdracht5-6_DependencyManagement/checkneighbours/) waarbij de unittesten je oplossing voor degetSameNeighboursIds-methode testen van deCheckNeighboursInGrid-klasse. De testen moeten aan volgende vereisten voldoen:- Gebruik de correcte naamgeving voor de testen
- Gebruik het correcte Arrange, Act, Assert principe
- Maak minstens 1 test die een
Exceptiontest - Probeer de randgevallen te testen en elke test moet een ander scenario testen. (bv. 1 test waarbij je een element aan de linker rand test mag maar 1 keer voorkomen. Eentje in een hoek testen kan dan wel al een ander scenario zijn.)
Doe nu op de correcte manier een commit en tag de commit met
v7en push naar Github.
Opdracht 8
Het python project in de subdirectory
.../opdracht7-8_TestDrivenDevelopment/tdd_pythonbevat:- een
checkneighbours.py-bestand met een implementatie van de functieget_same_neighbours_ids() - een file
checkneighbours_test.pymet het geraamte van het unittest framework al ingevuld.
- een
Schrijf nu dezelfde testen als in Opdracht 7 maar dan voor het python programma.
Doe nu op de correcte manier een commit en tag de commit met
v8en push naar Github.
Opdrachten rond Continuous Integration and Continuous Deployment
Opdracht 9
Gebruik Github Actions om een CI-pipeline aan te maken die steeds je testen van je ‘checkneighbours’ uit opdracht 7 uitvoert wanneer je naar de
mainbranch pusht. Voorzie ook een badge in een README.md in de root folder van deze git directory zodat je in één opslag kan zien wanneer de tests falen.Let op! Je wil nu dus de testen runnen van een specifiek gradle project dat in een subdirectory staat. Meer info hier
Doe nu op de correcte manier een commit en tag de commit met
v9en push naar Github.
Opdrachten deel 2
Deze opdrachten worden enkel door de studenten van SES gemaakt en ingediend via Github Classroom.
Gebruik van GenAI en samenwerking
Omdat dit deel van het vak gericht is op het zelf leren programmeren, en de opdrachten gequoteerd worden, is het niet toegestaan om GenAI tools (ChatGPT, Claude Code, Gemini, CoPilot, de assistent in IntelliJ, …) te gebruiken om de opdrachten op te lossen. Met andere woorden, we verwachten dus dat je alle ingediende code zelf geschreven hebt. Ook code delen met mede-studenten, of buitenstaanders om hulp vragen, is om dezelfde reden niet toegestaan.
Je zal je oplossing na de indiening mondeling nog moeten toelichten (moment nog vast te leggen). Bij deze toelichting wordt getoetst of je de code die je ingedien hebt ook zelf begrijpt.
Tenslotte is het absoluut geen probleem om GenAI tools te gebruiken bij het studeren en verwerken van de leerstof. Begrijp je een concept niet goed, en wil je meer uitleg of voorbeelden? Wil je hulp bij het oplossen van een oefening? Krijg je een compiler error niet opgelost? Gebruik deze tools dan gerust (hou er wel rekening mee dat er ook fouten in hun antwoord kunnen zitten)! Maar gebruik ze dus niet voor de opdracht.
Setup
Volg onderstaande stappen nauwgezet om je project juist te configureren.
Maak hier (via GitHub Classroom) je repository aan voor de assignment “SES opdrachten deel 2”. Deze repository is nog leeg.
Clone jouw (lege) repository naar een folder op je eigen machine (bv.
project-candycrush).Voeg vervolgens een tweede remote aan die repository op je machine toe, namelijk
git@github.com:KULeuven-Diepenbeek/ses-startcode-deel2-2526.gitonder de naamstartcode. Dat kan je met volgend commando:Je lokale repository heeft nu dus twee remote repositories (kijk dit na met
git remote -v):- origin: je eigen GitHub repository (hierop heb je schrijfrechten)
- startcode: de GitHub repository met de startcode die door ons aangeleverd wordt (deze kan je alleen lezen)
Haal de laatste versie van de startcode op en merge die in je repository via
git pull startcode main. Doe dit minstens voor elke nieuwe opdracht, en eventueel ook tussendoor (als er wijzigingen/bugfixes aan onze startcode gebeurd zijn).Open de folder als project in IntelliJ.
Als alles goed gegaan is, wordt je project herkend en geïmporteerd als een Gradle-Java-project. Het is normaal dat de code nog fouten geeft bij het compileren, aangezien die code verwachten die je nog moet schrijven als deel van de opdracht.
Startcode
De startcode bevat een JavaFX-applicatie voor het spel CandyCrush. Het is een Gradle-project voor IntelliJ, en maakt gebruik van Java 25. Je kan de folder openen als project in IntelliJ. De applicatie is gestructureerd volgens het Model-View-Controller (MVC) patroon.
Er zijn ook reeds enkele testen voorgedefinieerd met AssertJ, maar de set van testen is niet volledig. De voorgedefinieerde testen dienen voornamelijk om na te gaan of je oplossing automatisch getest kan worden.
Belangrijk!
Omdat je inzendingen (deels) automatisch verbeterd zullen worden, is het noodzakelijk dat alle gegeven testen compileren zonder enige aanpassingen. Je mag uiteraard wel extra testen toevoegen. Ook is het geen groot probleem indien een bepaalde test niet slaagt — zolang hij maar uitgevoerd kan worden.
Opdracht 1: Records
Startcode
Zorg dat je eerst de setup-instructies voor deel 2 hierboven gevolgd hebt.
Merge de laatste versie van de startcode in je repository door git pull startcode main uit te voeren in jouw lokale repository.
Maak, in package
ses.candycrush.boardeen recordBoardSize. Dit stelt de grootte voor van een CandyCrush speelveld. Het heeft als attributen het aantal rijen (rows) en aantal kolommen (columns) van het speelveld.- Het aantal rijen en kolommen moeten beiden groter zijn dan 0, zoniet gooi je een
IllegalArgumentException.
- Het aantal rijen en kolommen moeten beiden groter zijn dan 0, zoniet gooi je een
Maak, in hetzelfde package, ook een tweede record genaamd
Positionmet attributenrowencolumn. Dit stelt een geldige positie van een cel op een CandyCrush-speelveld voor.- Rijen en kolommen worden genummerd vanaf 0.
- Aan de constructor van een Position-object moeten (in deze volgorde) een rij- en kolomnummer alsook een
BoardSizemeegegeven worden. - Indien de positie ongeldig is voor de grootte van het speelveld, moet je een
IllegalArgumentExceptiongooien.
Voeg in
Positionvolgende methodes toe:een methode
int toIndex()die de positie omzet in een index. Voor veld met 2 rijen en 4 kolommen lopen de indices als volgt:een statische methode
Position fromIndex(int index, BoardSize size)die de positie teruggeeft die overeenkomt met de gegeven index. Deze methode moet eenIllegalArgumentExceptiongooien indien de index ongeldig is.methodes
boolean isFirstRow(),boolean isFirstColumm(),boolean isLastRow(), enboolean isLastColumn()die aangeven of de positie zich in de eerste/laatste rij/kolom van het bord bevindt.een methode
Collection<Position> neighbors()die alle posities van (geldige) directe buren (horizontaal en verticaal) in het speelveld teruggeeft. Kies een geschikt collectie-type voor de teruggegeven collectie.een methode
boolean isNeighborOf(Position other)die nagaat of de gegeven positie een directe buur is van de huidige positie. Gooit eenIllegalArgumentExceptionals de gegeven positie bij een andere bordgrootte hoort.
Voeg in
BoardSizede volgende methodes toe:- een methode
Collection<Position> positions()die een collectie (kies zelf het type) met daarin alle posities op het bord teruggeeft.
- een methode
Voeg, in package
ses.candycrush.model, een sealed interfaceCandytoe, met subklassen (telkens een record, die je in deCandy-interface plaatst) voorNoCandy, wat staat voor het ontbreken van een snoepje.NormalCandy, met een attribuutcolor(eenintmet mogelijke waarden 0, 1, 2, of 3); je gooit eenIllegalArgumentExceptionindien een ongeldige kleur opgegeven wordt.- Elk van de volgende speciale soorten snoepjes:
- een
RowSnapper - een
MultiCandy - een
RareCandy - een
TurnMaster
- een
Voeg, in het package
ses.candycrush.model, een recordSwitchtoe. Een Switch-object stelt een mogelijke wissel voor tussen twee Positionsfirstensecond.- Beide posities moeten buren zijn van elkaar; je constructor moet een
IllegalArgumentExceptiongooien indien dat niet het geval is. - Zorg ervoor dat het niet uitmaakt in welke volgorde de twee posities meegegeven worden aan de constructor; maar het veld
firstmoet uiteindelijk de positie bevatten met de kleinste index (zoals gedefinieerd bijtoIndex()).
- Beide posities moeten buren zijn van elkaar; je constructor moet een
Voeg aan dat Switch-record een operatie
other(Position pos)toe die de andere positie teruggeeft dan de gegeven positie (dus als je first meegeeft, krijg je second terug, en omgekeerd).- Indien de gegeven positie geen deel uitmaakt van het Switch-object, gooi je een
IllegalArgumentException.
- Indien de gegeven positie geen deel uitmaakt van het Switch-object, gooi je een
Pas nu je code (
CandyCrushGame,CandyCrushBoardUI, enController) aan zodat die op zoveel mogelijk plaatsen gebruik maakt van bovenstaande records in plaats vanintenint[](Switchmoet je nog niet gebruiken). Dus:- op elke plaats waar voorheen een int voor width en/of height gebruikt of teruggegeven werd, moet nu
BoardSizegebruikt worden - op elke plaats waar voorheen een rij- en/of kolomnummer gebruikt of teruggegeven werd, moet nu een
Positionobject gebruikt worden - op elke plaats waar voorheen een int gebruikt of teruggegeven werd om een snoepje aan te duiden, moet nu een
Candyobject gebruikt worden. - In de klasse CandyCrushBoardUI (methode
makeCandyShape) moet je pattern matching gebruiken om een JavaFX Node aan te maken voor de gegeven candy op de gegeven positie.
Hint: Laat de compiler je helpen met het vinden van de nog aan te passen code, door bv. eerst de type van een veld te veranderen en dan alle compilatie-problemen die daardoor ontstaan aan te pakken.
- op elke plaats waar voorheen een int voor width en/of height gebruikt of teruggegeven werd, moet nu
Implementeer in de model-klasse
CandyCrushGamede methodeCollection<Switch> getPotentialSwitchesOf(Position pos). Deze moet alle mogelijke wissels teruggeven (collectie-type naar keuze) van positiepos. Positieposkan wisselen met een andere positie indien (1) ze buren zijn; (2) geen van beiden een NoCandy zijn; én (3) de snoepjes op beide posities verschillend zijn (qua soort en/of kleur). (Deze methode zullen we in een latere opdracht verfijnen, maar voorlopig volstaat dit).
Als je dit alles correct gedaan hebt, zou alle code moeten compileren en kan je de applicatie uitvoeren (./gradlew run). Ook de testen zouden moeten slagen.
Tag het resultaat als v1 en push dit naar jouw remote repository (origin) op GitHub: git push origin.
Vergeet niet om de tag zelf ook expliciet te pushen:
git push origin v1. Dit gebeurt namelijk niet automatisch bij eengit push. Je kan ook alle tags in 1 keer pushen metgit push --tags. Controleer op je GitHub-repository of je de tags kan zien.
