Oefeningen Jaarproject I Deze oefeningenreeks behandelt de grafische Scheme bibliotheek die jullie mogen gebruiken voor de implementatie van het Pacman spel. De bibliotheek i is een evaluator voor Scheme geschreven in Scheme. Je kan de nodige bestanden alsook uitleg over de grafische bibliotheek vinden point-carré van onder het vak Programmeerproject 1 -- 006348. De oefeningen (en later ook de oplossingen) kan je ook terugvinden via de documenten map op point-carré. Introductie Tijdens deze oefeningenzitting is het de bedoeling om een race spelletje te implementeren aan de hand van de grafische bibliotheek. De implementatie van dit race spel is opgesplitst over vier oefeningen. Een eerste oefening is een herhaling van de grafische bibliotheek. De tweede oefening gaat over de implementatie van de data abstracties zonder grafische weergave. In de derde oefening wordt alles gekoppeld aan een grafische interface. Ten slotte behandelt de laatste oefening de gegevensinvoer. Oefening 1: Tekenscherm basis In deze opgave is het de bedoeling om jullie vertrouwd te laten raken met de grafische bibliotheek. Je zal een scherm aanmaken en een auto op het scherm laten bewegen. Voor je aan deze opgave begint zal je ervoor moeten zorgen dat je de grafische bibliotheek inlaad. In de opgave hieronder zijn alle ADT s van de grafische bibliotheek in het vet gerukt. Je vindt telkens een template met de nodige code voor elke oefening in het rar bestand wpo_code.rar op pointcarré. In dit geval is het een leeg racket bestand in WPO Exercise1 met de naam ex1.rkt. Een voorbeeld is voorzien en de grafische bibliotheek is voorzien. Maak een window aan met breedte 800, hoogte 600 en met de string Jaarproject. Maak een tile aan met de auto1.png en de mask auto1_mask.png. Gebruik je window om een nieuwe layer aan te maken. Teken je tile op de nieuwe layer. Laat je tile bewegen op het scherm door zijn x en y coördinaten te wijzigen. Hint kijk in het opgave document naar sectie 3.1. en kijk naar de voorbeelden die wij meegeleverd hebben met de code. Indien dit moeilijk is, er zijn 6 voorbeelden voorzien met de code van de grafische bibliotheek die gecommentarieerd zijn. Probeer die uit, indien je vragen hebt contacteer ons. Oefening 2: Data Abstracties In deze oefening zal je enkele data abstracties voor het race spel implementeren. We hebben reeds enkele van deze ADT s geïmplementeerd onder de naam race-spel.rkt in de folder WPO Exercise2. Dit is een voorbeeld van een design waar jullie ideeën kunnen uithalen indien je hier moeite mee had met je voorstudie. Ook de manier waarop we dit uitleggen kunnen jullie als voorbeeld gebruiken net als de bijgeleverde
diagrammen, weinig studenten hebben dit goed gedaan in de voorstudie. De functionaliteit van je data abstracties die je moet implementeren voor het race spel zijn weergegeven in figuur 1 en figuur 2. De afhankelijkheden van de data abstracties zijn weergeven in figuur 3. Een snelweg bevat een aantal rijstroken die zelf een aantal vakken bevatten. Deze vakken zijn plaatsen waarop je autootje zich mogelijk kan bevinden. Voor dit spel is het voldoende om drie soorten vakjes te implementeren. Een eerste vakje is een weg waar je auto op kan rijden. Het tweede vakje is een blokkade. Het derde vakje is de finish van de snelweg. Als je auto op een blokkade rijdt gaat hij kapot en heb je het spel verloren. Als je de finish haalt ben je gewonnen. Het spel, de snelweg en het rijstrook ADT zijn reeds geïmplementeerd maar we hebben nog geen vakjes, die zijn aan jullie te implementeren. Als je op run klikt zie je dat er automatisch twee scenarios worden uitgevoerd onderaan het bestand met: ((spel 'test) '(voorwaarts rechts rechts voorwaarts links voorwaarts links voorwaarts)) ((spel 'test) '(voorwaarts rechts voorwaarts voorwaarts links voorwaarts links voorwaarts) Als je dit goed doet dan moet de eerste test printen dat je in de finish bent en de tweede test moet een botsing veroorzaken. Het is dus aan jou om een drie nieuwe objecten aan te maken: Maak het weg ADT aan dat de interface van het Vakje ADT implementeert. Wanneer een auto over je weg rijdt zegt je autootje Vroem. Je mag deze functionaliteit implementeren door simpelweg Vroem te displayen. Maak het blokkade ADT aan dat de interface van het Vakje ADT implementeert. Wanneer een auto je blokkade rijdt is de auto kapot. Dit doe je door het berichtje Kapot naar de auto te sturen. Maak het finish ADT aan dat de interface van het Vakje ADT implementeert. Wanneer een auto op de finish rijdt is het spel gedaan. Dit doe je door het berichtje gewonnen naar spel adt te sturen.
Vakje Auto Snelweg Rijstrook Figuur 1: Grafische weergave van de ADTs. Figuur 2: Grafische weergave van de ADTs. We hebben dit spel gemaakt om jullie een voorbeeld te geven van een goed design waar data en gebruikersinterface (GUI) is gescheiden. Er is ook nagedacht over de structuur van een snelweg en zoals jullie zullen zien over de manier waarop het spel reageert als een auto op een nieuw vakje komt. Dit spel is zeer makkelijk uitbreidbaar en we voorzien de volledige code om jullie een voorbeeld te geven van wat we verwachten.
Snelweg ADT De interface van het snelweg ADT is weergegeven in tabel 1. De constructor van het snelweg ADT verwacht een lijst van rijstrook ADT s. Maak-ADT-snelweg Lijst van lijst van Lijst[Lijst[symbool]] -> () symbolen neem-rijstrook Integer Integer -> Rijstrook aantal-rijstroken / / -> Integer lengte-rijstroken / / -> Integer Tabel 1: Interface van het Snelweg ADT. Rijstrook ADT De interface van het rijstrook ADT is weergegeven in tabel 2. Het rijstrook ADT wordt aangemaakt met een lijst van symbolen die de verschillende vakjes op de rijstrook voorstellen. Deze lijst van symbolen moet beperkt zijn tot de symbolen: blokkade en weg. Deze symbolen worden gebruikt om respectievelijk een blokkade ADT of een weg ADT aan te maken. Maak-ADT-rijstrook Lijst van symbolen Lijst[symbool] -> () neem-vakje Integer Integer -> Vakje Tabel 2: Interface van het Rijstrook ADT. Vakje ADT In de implementatie zal er een groep van ADT s (vakjes) zijn die dezelfde interface ondersteunen. Wegen, blokades en de finish zijn allen een vakje en ondersteunen dus de interface van het Vakje ADT. Aangezien de interface voor elk van deze vakjes hetzelfde is bespreken we ze als één ADT. Deze interface is weergegeven in tabel 3. Er zijn drie verschillende constructors, één voor een weg een finish en een blokkade. maak-adt-weg / / -> Weg maak-adt-finish / / -> Finish maak-adt-blokade / / -> Blokade doeactie Spel en Auto Spel, Auto -> void Tabel 3: Interface van het Vakje ADT.
Auto ADT Het auto ADT stelt een auto voor die zich naar links, recht en voorwaarts kan bewegen. De auto houdt rekening met de snelweg en zal niet van de snelweg rijden. De auto wordt echter niet opgeslagen in een rijstrook zoals de Vakjes maar wordt opgeslagen in het spel ADT wat je kan zien in het afhanklijkheidsdiagram of figuur 3. Een auto weet ook op welke snelweg hij momenteel rijdt en houdt het nummer van de rijstrook en van het vakje bij. De reden dat we auto niet in de snelweg opslaan is dat een mogelijke uitbreiding zou zijn om daarna de auto in een vlotte beweging van een vakje naar een ander vakje te laten bewegen. Dus de auto zou voor 10 percent in vakje 2 zitten en voor 90 percent in vakje 3, hoe zouden jullie dit implementeren? Het feit dat rijstrooknummer en vaknummer een Float teruggeven is een goede hint. Deze interface is weergegeven in tabel 4. maak-adt-auto Spel en Snelweg Spel, Snelweg -> Auto rechts / / -> void links / / -> void voorwaarts / / -> void terug-naar-start / / -> void rijstrooknummer / / -> Float vaknummer / / -> Float Tabel 4: Interface van het Vakje ADT. Spel ADT Het spel ADT zal het spel opstarten indien het start bericht ontvangen wordt. Via test kunnen we zogenaamde unit-tests sturen om te kijken of ons programma werkt. Dit doen we door een lijst van symbolen mee te geven die aan auto worden doorgegeven als berichten. maak-adt-racespel / / -> Spel start / / -> void test / / -> void Tabel 5: Interface van het Spel ADT. Oefening 3: Data-Gui Binding Voor deze oefening is er opnieuw voorbeeld code voorzien in de folder WPO Exercise3-4. Nu we alle data objecten aangemaakt hebben om de spellogica te implementeren kunnen we onze data objecten koppelen aan een grafische interface. Velen onder jullie hadden moeite om hun data structuren te scheiden van de GUI. In deze oefening gaan we een GUI implementatie tonen die de datastructuren gebruikt van oefening 2. De
afhankelijkheden tussen de verschillende ADT s in het race spel is te zien in figuur 2. In dit afhankelijkheden diagram hebben we enkel bij een paar berichten expliciet bijgeschreven welke boodschappen gestuurd worden. De boodschappen voor blokkade en weg ADT zijn soortgelijk aan deze voor het Auto ADT. Merk op dat er een volledige scheiding is tussen de grafische library (Window ADT en Tile ADT) via Teken ADT. Het is dus heel gemakkelijk om een andere Teken ADT te maken die hetzelfde spel anders tekent. Bijvoorbeeld met een andere gui library, met vertikale wegen of in puur tekstueel formaat. Probeer dit ook in jullie Pacman mooi te scheiden. Het teken ADT verstaat berichtjes voor het tekenen van een snelweg en voor het tekenen van een Auto. Om ervoor te zorgen dat de code bijna niet moet aangepast moet worden wanneer er nieuwe ADT s zouden bijkomen is het tekenen opgesplitst in verschillende stappen: 1. Het spel ADT stuurt een berichtje teken naar het Auto ADT. 2. Het Auto ADT reageert hierop door een berichtje te sturen naar het teken ADT. 3. Het teken ADT past een tile aan op het scherm. Teken ADT Het teken ADT vormt de brug tussen de data structuren en de grafische bibliotheek. Indien we een andere manier van teken willen voorzien hoeven we gewoon een nieuw Teken ADT te voorzien met een gelijkaardige interface. maak-adt-teken Snelweg Auto Integer Integer Spel Auto Integer Integer -> Teken teken-auto Auto Auto -> void teken-weg Weg Weg -> void teken-blokade Blokade Blokade -> void teken-finish Finish Finish -> void zet-spel-lus! lambda(float) lambda(float) -> void zet-toets-functie! lambda(symbol) lambda(symbol) -> void schrijf String string -> void schrijf-op-auto String String -> void 4. Tabel 5: Interface van het Spel ADT.
Figuur 3: Afhankelijkhedendiagram. In de code van de opgave is de interactie tussen de finish, de blokkade, de weg en het teken ADT reeds geïmplementeerd. Voor het Auto ADT is dit echter niet het geval. Implementeer de interactie tussen het Auto ADT en het teken ADT. Telkens als je een auto moet tekenen pas je deze Tile aan. Je zal hiervoor eerst een Tile moeten aanmaken in het Teken ADT. Oefening 4: Gegevens Invoer Bijna alle functionaliteit is geïmplementeerd nu. Helaas is er nog geen interactie met de gebruiker. Implementeer de on-key functionaliteit door het autootje links en rechts te laten bewegen telkens als de gebruiker op de up en down toetsen drukt. Implementeer de update functionaliteit door het autootje voorwaarts te laten gaan telkens als er meer dan 1000 ms voorbij gegaan zijn. Extra: Indien je tijd over hebt, probeer eens te kijken hoe je de auto in een vloeiende beweging zou kunnen doen bewegen tussen twee vakjes in plaats van vakje naar vakje te springen. Bij de uitleg van Auto ADT wordt een hint gegeven hoe je dit kan doen.
Besluit: Deze implementatie is een voorbeeld, er zijn een aantal dingen die zeker beter kunnen zoals de manier waarop op toetsen wordt gereageerd. In ieder geval is dit een goed een simpel voorbeeld van een goede scheiding tussen GUI en Data structuren. Wij hopen dan ook dat jullie de code proberen doorgronden en eruit probeer te leren voor jullie design. Verder merken jullie waarschijnlijk dat het niet gemakkelijk is om code uit te leggen, daarom vragen wij jullie om vollediger te zijn in de volgende rapportering zowel op gebied van signaturen als op gebied van afhankelijkheidsdiagrammen. Indien jullie niet alles op één diagram krijgen kan je altijd meerdere diagrammen maken om verschillende soorten afhankelijkheden te beschrijven. Indien er verdere vragen zijn in verband met de code of in verband met het design kunnen jullie steeds terecht op: pacman@soft.vub.ac.be