Cursus ‘Algoritmiek’ [Inleiding programmeren voor Informatiekundigen]; najaar 2005
Opdracht 10
Cursus Algoritmiek - - najaar 2005 Practicumopdracht 10 :
Verkeerslichten-simulator
N.B. Voordat je deze opdracht maakt, moet je eerst het elektronische cursusevaluatieformulier, dat je op de cursus-web-pagina (http://www.cs.ru.nl/~sjakie/pi1) onder het kopje ‘Laatste nieuws’ kunt vinden, invullen en opsturen. Het na versturen getoonde nummer moet je noteren en in de ‘body’ van je emailbericht met je programma-uitwerking mee opsturen!!
Dit is de laatste practicumopdracht van deze cursus die nog ingeleverd moet worden. Ook deze opdracht is voor 2 weken: 1e week (= de week vóór Kerst) t/m deelopdracht 10.4; maak in de 2e week (= de week vanaf 9 januari 2006) de rest. Inleveren vóór vrijdag 13 januari 2006 om 14:00u!
1.
Achtergrond
Tijdens de hoorcolleges van vorige week en deze week heb je kennis gemaakt met een nieuwe manier van probleem analyseren: de aanpak via objectgericht werken. Met deze nieuwe aanpak heb je in de vorige practicumopdracht al geoefend voor een zeer eenvoudige situatie. In deze laatste practicumopdracht ga je voor een wat complexer systeem een ‘objectgerichte’ analyse maken en (in een grafische omgeving) een oplossing ontwerpen en implementeren.
2.
Leerdoelen
Na afloop van deze opdracht ben je in staat om: • de basisprincipes van ‘objectgericht werken’ toe te passen in wat minder triviale situaties; • bestaande ‘class’-sjablonen uit te breiden tot volledig functionele objecttypen.
3.
Instructie
Bestudeer allereerst het op het hoorcollege besproken onderdelen uit het Algoritmiek-dictaat (uit hoofdstuk 11) en de sheets zoals die gebruikt zijn op het college (over OO-werken) en uiteraard je op het hoorcollege gemaakte aanvullende eigen aantekeningen. Hiernaast is in een figuur getoond hoe je uiteindelijke programma er moet uitzien. Naast de vier toegangswegen tot het getekende kruispunt staan verkeerslichten opgesteld, die op de gebruikelijke wijze verspringen. We zien (op papier misschien niet helemaal duidelijk, maar toch ...) dat de lichten rechtsboven en linksonder op ‘rood’ staan en dat de verkeerslichten linksboven en rechtsonder blijkbaar net van groen op oranje (of ‘geel’) zijn gesprongen en binnenkort op rood zullen springen. Even later zullen de nu op ‘rood’ staande verkeerslichten op groen springen, een poosje zo blijven en dan op hun beurt verspringen naar oranje/geel etc. Via de Algoritmiek -Webpagina staat tot je beschikking het bestand ‘verkeerssimulatie.zip’, waarin [naast het ondertussen wel bekende ‘gui_kernel.cpp’ en dito ‘.h’-bestand] ook het bestand ‘kruispunt.cpp’ zit. Als je deze bestanden opneemt in een nieuw project, compileert en ‘linkt’, krijg je het hiernaast getoonde, ietwat uitgeklede kruispunt te zien (zie 2e figuur). Aan jullie de taak om, uitgaande van de 2e situatie de programmacode stap voor stap aan te passen, totdat je de eerste situatie hebt gekregen.
1
Cursus ‘Algoritmiek’ [Inleiding programmeren voor Informatiekundigen]; najaar 2005
Opdracht 10
In het bestand ‘kruispunt.cpp’ zitten o.a. definities (+gedeeltelijke implementaties) van de volgende constanten, objectklassen en (hulp) functies: const GSIZE ScreenSize (450, 450); const GPOINT MidScreen (ScreenSize.cx / 2, ScreenSize.cy / 2); class Kruispunt;
// vóóraankondiging via een ‘proto-type’
class KruispuntSimulatie : public GUI { public: KruispuntSimulatie (Kruispunt&); Window (const RECT& area); Timer (const int dt);
virtual void virtual void private: Kruispunt& } ;
kruispunt;
enum Kleur { Rood, Geel, Groen, Zwart, Wit, AantalKleuren }; const RGBCOLOUR& kleurNaarRGB (Kleur k) ; inline Kleur& operator++ (Kleur& k) ; void tekenCirkel (Canvas& canvas, GPOINT p, int straal, Kleur k, int dim_factor); void tekenRechthoek (Canvas& canvas, GPOINT p, GSIZE s, Kleur k, int dim_factor) ; void tekenKast (Canvas &canvas, GPOINT pos, GSIZE afm); void tekenOmgeving (Canvas& canvas); void tekenWegen (Canvas& canvas); . . . . .
N.B. Let er op, dat alle procedures die direct of indirect gebruik maken van de ‘teken…’-procedures, de ‘canvas’-parameter moeten meekrijgen! De al aangekondigde klasse Kruispunt is vrij kaal gegeven en vooral dit onderdeel moet door jullie uitgewerkt worden teneinde de applicatie de gewenste functionaliteit te geven: class Kruispunt { public: void void private:
Kruispunt (); tekenKruispunt (Canvas& canvas); volgendeToestand (Canvas& canvas);
} ; Kruispunt { }
:: Kruispunt ()
void Kruispunt { }
:: volgendeToestand (Canvas& canvas)
void Kruispunt :: tekenKruispunt (Canvas &canvas) { tekenOmgeving (canvas); tekenWegen (canvas); const
GSIZE
tekenKast
afm_vlicht (40,100); (canvas, GPOINT (100,100), afm_vlicht);
}
Je ziet hierboven dat het aangeleverde ‘kale kruispunt’ blijkbaar getekend wordt door aanroep van de ‘tekenKruispunt’-methode, die behalve de omgeving en de wegen slechts één ‘niet-van-lichtenvoorziene-kast’ tekent. Zie daar het begin van de jullie toebedachte opdracht om dit simulatieprogramma als een ‘echte’ set verkeerslichten te laten functioneren. 2
Cursus ‘Algoritmiek’ [Inleiding programmeren voor Informatiekundigen]; najaar 2005
Opdracht 10
Tot slot vind je in de aangeleverde programmacode, dat de verkeerslichtensimulator wordt gestart via de constructor-aanroep: KruispuntSimulatie :: KruispuntSimulatie (Kruispunt& k) : GUI (ScreenSize, "Kruispunt"), kruispunt (k) {}
Deelopdracht 10.0
Voorbereiding: maak workspace met aangeleverde bestanden
Maak binnen het Visual C++-systeem een nieuwe workspace (/project/een ‘Windows application’) en plaats daarin de bestanden uit het beschikbare bestand ‘verkeerssimulatie.zip’. Zie ook het begin van dit ‘instructiedeel’. Geef het ‘make’-commando en de .h-bestanden zullen [waarschijnlijk..] automatisch opgenomen worden in het project. Overtuig je ervan, dat na linken en opstarten ervan, je Windows applicatie als uitvoer het in figuur 2 getoonde scherm geeft.
Probleemschets (1) bij deze opdracht We zullen er eerst mee aan de slag gaan om binnen die ene (in de 2e figuur) getoonde ‘kast’ van dat ene verkeerslicht ‘lampen’ (of zo je wilt: ‘lichten’) te kunnen plaatsen. Elk verkeerslicht heeft drie lampen, die op hun kleur en positie na volkomen identiek aan elkaar zijn. Om je het leven (althans: bij deze opdracht) te vergemakkelijken, is in het kruispunt.cpp-bestand een functie tekenCirkel opgenomen. Van deze functie gaven we reeds als header: void tekenCirkel (Canvas& canvas, GPOINT p, int straal, Kleur k, int dim_factor);
Een GPOINT is hierin een vóórgedefinieerde Struct met een ‘x’- en een ‘y’-veld. Als je bij aanroep van deze functie aan de ‘dim_factor’ bijvoorbeeld de waarde 3 mee geeft, dan zal de getekende cirkel nog zwak de kleur van die lamp hebben (net zoals je bij een echt verkeerslicht als het groene licht brandt, toch kunnen zien dat er rood glas vóór de bovenste lamp zit).
Deelopdracht 10.1
Ontwerp en implementeer een ‘Lamp’-objectklasse
Analyseer de benodigde opbouw en functionaliteit van een ‘Lamp’-object en ontwerp en implementeer een ‘Lamp’-objectklasse. Gebruik, net zoals dat ook gebeurd is voor reeds (gedeeltelijk) gedefinieerde methodes of gewone functies zoals ‘tekenKast’ en ‘tekenWegen’, een methode met de naam ‘tekenLamp’ (waarbij als eerste parameter het ‘canvas’ mee gegeven wordt en als tweede parameter een boolean waarde ‘is_aan’), om een lamp-object op het scherm af te beelden. Als een lamp ‘aan’ moet worden afgebeeld, gebruik je een andere ‘dimfactor’ dan wanneer hij ‘uit’ is (b.v. dimfactor 1 versus 3). De lichten van de 1e figuur zijn gemaakt met een ‘LampGrootte’ 12 (kortom: neem diezelfde waarde voor de ‘straal’ van je lampen). De plaats waarop die lamp getoond moet worden, kan bepaald worden uit de GPOINT-waarde die eerder bij initialisatie van het object is meegegeven. Test deze Lamp-klasse uit, door zolang even vanuit de meegegeven methode void Kruispunt :: tekenKruispunt (Canvas &canvas); bijvoorbeeld midden op het scherm (neem hiervoor de vóórgedefinieerde constante ‘MidScreen’) een rode lamp te tonen (en als dat correct verloopt, haal die losse lamp daar dan weer weg!).
Deelopdracht 10.2
Ontwerp en implementeer een ‘Verkeerslicht’-objectklasse
Analyseer de benodigde opbouw en functionaliteit van een ‘Verkeerslicht’-object en ontwerp en implementeer zo’n objectklasse. Uiteraard bevat een verkeerslicht (-variabele) drie lampen (rood, geel/oranje, groen) die op onderling gelijke afstanden van elkaar staan en die passen binnen een (getekende) ‘kast’. In de voorbeelden van beide figuren zijn de kastdimensies 40 bij 100 genomen. Als je een verkeerslicht-object zodanig implementeert, dat de GPOINT-coördinaten van het verkeerslicht overeenkomen met het midden van de ‘kast’ (de omtrek) van dat verkeerslicht, dan is daarna de plaats van de gele/oranje lamp gemakkelijk te bepalen. Hou er verder rekening mee dat het ‘x’-veld horizontaal gerekend is en het ‘y’-veld vertikaal, 3
Cursus ‘Algoritmiek’ [Inleiding programmeren voor Informatiekundigen]; najaar 2005
Opdracht 10
dat de ‘oorsprong’ (0,0) van het coördinatenstelsel in de linkerbovenhoek zit en dat de ‘y’-coördinaat groter (positiever) wordt naar beneden toe. Test de werking van deze objectklasse uit door bijvoorbeeld weer midden op de kruising een testverkeerslicht te plaatsen en dat op ‘rood’ te zetten. Het kan nodig zijn, dat je ‘bij nader inzien’ ontwerp en/of implementatie van je Lamp-klasse moet aanpassen.
Deelopdracht 10.3
‘Kruispunt’-klasse: implementeer constructor en teken-methode
In het gegeven bestand ‘kruispunt.cpp’ zit een zwaar onvolledige versie van een ‘Kruispunt’objectklasse. Analyseer de benodigde klasse-velden, voeg die toe aan de ‘Kruispunt’-objectklasse en implementeer en/of verbeter de constructor- en de tekenKruispunt-methodes. Suggestie: plaats de 4 benodigde verkeerslichten in een rij van verkeerslichten; hierdoor kun je ze eenvoudiger ‘aansturen’ (dan vaak via een herhaling van 0 t/m 3 ...). Zet voor het uittesten even 2 verkeerslichten op groen en 2 op rood en test uit of het gehele kruispunt met zijn verkeerslichten goed wordt weergegeven. Het kan nodig zijn, dat je ‘bij nader inzien’ je Verkeerslicht-klasse moet aanpassen.
Probleemschets (2) bij deze opdracht Misschien is het je tijdens het bekijken van de gegeven code opgevallen, dat gelijk in het begin bij de eerste [primitieve] definitie van de: class KruispuntSimulatie : public GUI
de optie ‘public GUI’ staat en dat een van de methoden van deze klasse is: virtual void
Timer
(const int dt);
en dat via menu-keuzes de methoden ‘startTimer’ en ‘stopTimer’ kunnen worden geactiveerd. We willen de verkeerslichten op een regelmatige wijze aansturen, waarbij om de zoveel (milli-) seconden de toestand van de verkeerslichten verandert. Het echte ‘aansturen’ van de verkeerslichten bij dit kruispunt gebeurt met behulp van die meegeleverde ‘Kruispuntsimulatie’-klasse, waar in de ‘Timer’-methode steeds (na elk bij ‘startTimer’ aangegeven tijdsinterval) de Kruispunt-methode ‘volgendeToestand’ wordt aangeroepen. Als voorbeeld geven we, dat na de aanroep ‘startTimer(500);’ vervolgens elke 500 milliseconden de Timer-methode wordt geactiveerd en de daarin geplaatste code uitgevoerd. We beperken ons in deze opdracht tot sets van telkens twee verkeerslichten (bijvoorbeeld linksboven+rechtsonder versus rechtsboven+linksonder) waarbij beide verkeerslichten van zo’n set in dezelfde toestand verkeren. We gaan nu eerst de ‘buiten-werking’-fase (waarbij -zoals vaak ’s nachts gebeurt- alleen de oranje lampen van de beide verkeerslichtensets staan te knipperen) implementeren en daarna de ‘in-werking’fase waarbij de groen-oranje-rood-volgorde correct wordt afgewerkt.
Deelopdracht 10.4
a) Het verkeersregelsysteem in de ‘buiten-werking’-fase
Analyseer de voor een ‘buiten werking’-fase benodigde functionaliteit van de ‘Kruispunt’- en eventueel ook ‘KruispuntSimulatie’-objectklasse en ontwerp en implementeer die. Je mag zelf bepalen of je het knipperen van de geel/oranje-lichten van beide sets afwisselend of gelijktijdig laat gebeuren. Test de werking uit en pas zonodig je code aan. N.B. 1) Je kunt [uiteraard afhankelijk van de rest van je code] eventueel een licht op ‘uit’ zetten, door het de kleur ‘zwart’ te geven. 2) Als je ontdekt dat bij het weer uitschakelen van die knippertoestand de geel/oranje-lampen blijven branden, laat dat probleempje dan voorlopig rusten en denk nog eens rustig na over hoe je dat kunt verhelpen (en doe dat later dan inderdaad een keer).
4
Cursus ‘Algoritmiek’ [Inleiding programmeren voor Informatiekundigen]; najaar 2005
Opdracht 10
Probleemschets (3) bij deze opdracht We gaan nu de uiteindelijke versie ontwikkelen, waarbij de verkeerslichten in een ‘wel-actief’-toestand de groen-geel-rood-fasen doorlopen en daarmee het verkeer regelen. Uiteraard moet bij een kruispunt de verkeersveiligheid gewaarborgd zijn en daarom is een klein tijdsverschil ingebouwd tussen het ‘op rood’ springen van de ene set en het vervolgens ‘op groen ‘ springen van de andere set. Schematisch hebben we dan te maken met [bijvoorbeeld] de volgende fasen, waarin de tijdsintervallen in een of andere eenheid zijn gegeven (voor het gemak: ‘Timer’-eenheden): Set 1 Set 2
<= = = = = = = rood = = = = = = => <= = groen = = > <=oranje=> <= = groen = = > <=oranje=> <= = = = = = = = rood = = = = = = =>
Tijdsintervallen:
1
6
3
1
6
3
We moeten dus ergens (al dan niet in een globale constante) de fase/interval-gegevens opslaan en na elke ‘Timer’-tik laten in die fase/interval-gegevens nazoeken of de Kruispunt.volgendeToestandmethode geactiveerd moet worden. En àls die laatste methode geactiveerd moet worden, moet natuurlijk duidelijk zijn, hoe de verschillende lichten aan- of uitgeschakeld moeten worden.
Deelopdracht 10.5
b) Het verkeersregelsysteem in de ‘in-werking’-fase
Analyseer de voor zo’n ‘in-werking’-fase verder benodigde functionaliteit van de ‘Kruispunt’objectklasse en ontwerp en implementeer die. Denk daarbij dus aan de verschillende fasen die een knipperende verkeerslichtencombinatie bij zo’n kruispunt moet kunnen doorlopen en verzin zelf een geschikte datastructuur en een erbij behorende algoritme om de implementatie op een gemakkelijk mogelijke wijze te laten gebeuren. Test het geheel uit en pas je code zonodig aan. Suggestie: voeg een menu-optie toe om het systeem van de ‘buiten-werking’-toestand in de ‘inwerking’-toestand te laten overgaan en implementeer die. Pas eventuele resterende problemen in je applicatie aan, zodat je een correct werkend verkeersregelsysteem overhoudt.
4.
Producten
Als producten moet je je (uitgeteste!) C++-code inleveren (van deelopdrachten 10.1 t/m 10.5), die ervoor zorgt dat je programma voldoet aan de daar gevraagde specificaties en waarbij je uitwerking voldoet aan de kwaliteitscriteria zoals die gesteld worden (zie bij punt 5. Zelfreflectie). ). Let ook op het aanwezig zijn van de vereiste commentaarregels in elke functie/procedure. Lever indien mogelijk ook schermafdrukken van de uiteindelijke kruispunt/verkeerslichtensituatie in.
5.
Zelfreflectie
Via de Algoritmiek-webpagina (of direct via www.cs.kun.nl/~sjakie/pi-info/algemeen/criteria.html) kom je uit op criteria die we gebruiken voor de kwaliteit van je ingeleverde werk. Die criteria liggen o.a. op het gebied van naamgeving, lay-out, structuur, programmeerstijl, aanpak, realisering, en een juist gebruik van taalprimitieven. Ga voor jezelf na [voor zover van toepassing] in hoeverre je uitwerkingen voldoen aan deze criteria.
=> Inleveren van je producten: vóór vrijdag 13 januari 2006, 14:00 uur, en wel door de uiteindelijke inhoud van je [totale] .cpp-bestand [ruim] op tijd op te sturen naar
[email protected] , als ‘losse’ attached file. Plaats in de email-subjectregel: ‘Algoritmiek opdracht 10’. Plaats duidelijk de namen, studentnummers en studierichting van zowel jezelf als je practicumpartner in alle meegestuurde bestanden, evenals het nummer van deze opdracht. Doe dit plaatsen van namen + studentnrs + ‘Algoritmiek’ + opdrachtnummer óók in het ‘message-deel’ van je email. Nogmaals: in de body van je email moet je het verkregen cursusevaluatie-getal vermelden!
5