Deze oefeningen horen bij het handboek Zie Scherp Scherper (meer info op ziescherp.be. Dit boek wordt gebruikt als handboek binnen de opleidingen professionele bachelor toegepaste informatica en bachelor elektronica-ict van de AP Hogeschool, alsook bij tal van andere hogescholen en middelbare scholen.
Concreet is dit het handboek voor de eerste 2 semesters omtrent 'leren programmeren met C#':
Deel 1: Programming Principles, eerste semester
Deel 2: Object Oriented Programming, tweede semester
Indien bepaalde hoofdstukken of onderdelen niet duidelijk zijn of fouten bevatten, aarzel dan niet om me te contacteren. Normaal gezien zijn alle tekst en afbeeldingen de mijne, tenzij ik anders vermeld. Uiteraard maak ik soms fouten, als je dus een niet geattribueerde tekst of afbeelding ontdekt, aarzel dan niet om me te contacteren.
Alle feedback is zéér welkom.
Veel leer-en leesplezier,
Tim Dams
PS: Besef dat goed kunnen programmeren enkel kan geleerd worden indien je ook effectief veel programmeert. Je kan ook niet leren fietsen door enkel een handboek "Fietsen met Merckx" te lezen, je zal op de fiets moeten springen! En vallen...véél vallen.
Attribution : You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. NonCommercial : You may not use the material for commercial purposes.
No additional restrictions : You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
{% hint style="danger" %}
Vergeet IntelliCode niet uit te schakelen (hoe?)!
{% hint style="info" %}
Kijk pas naar de oplossing als je 100% klaar bent. En zelfs dan, wees erg kritisch over jouw oplossing tegenover de modeloplossing. Vraag hulp aan de lector bij de minste twijfel die je hebt wanneer je jouw oplossing vergelijkt me de modeloplossing!
{% hint style="warning" %}
Maak telkens een volledig nieuwe solution aan per oefening (enkel de oefening "Stad kleuren" doe je in de bestaande "Wie ben ik" oplossing). Zo kan je later makkelijk terugkeren naar een specifieke oefening.
Schrijf een programma dat aan de gebruiker de volgende zaken vraagt:
Voornaam
Achternaam
Adres
Hobby
Vervolgens toon je de vragen gevolgd door de antwoorden, met de naam als 1 antwoord (voornaam en achternaam). Je zal hiervoor de Write-methode en WriteLine-methode moeten gebruiken.
Bijvoorbeeld (tekst die start met liggende streepjes is input van de gebruiker):
Wat is je voornaam?
_Tom
Wat is je achternaam?
_Peeters
Waar woon je?
_Parel van de Kempen
Wat is je hobby?
_fietsen
Goed. Hier volgt je visitekaartje"
Naam: Tom Peeters
Adres: Parel van de Kempen
Hobby: fietsen
Schrijf een programma dat de gebruiker om een vraag vraagt en vervolgens een antwoord geeft, namelijk: "Dat is een interessante vraag! Ik zal er eens over nadenken en later op terugkomen."
Het programma doet dus niets en hoeft dus ook niets met de gebruikerinput te doen. Het is letterlijk een lege doos. Voorbeeld output:
Wat is je vraag?
_Wonen er Marsmannetjes op Mercurius?
Dat is een interessante vraag! Ik zal er eens over nadenken en later op terugkomen.
Open terug je "Wie ben ik"-solution. Pas de code aan zodat je stad in rode letters met witte achtergrond wordt getoond. Vergeet niet je kleur terug te resetten naar de standaardkleuren na het tonen van de stad.
Voorbeeld van de output (gebruik je eigen gegevens uiteraard):
Schrijf een applicatie met behulp van ReadLine() en WriteLine()-methoden waarbij de computer aan de gebruiker om zijn of haar favoriete kleur, eten, auto en boek vraagt. Het programma gaat echter de gebruiker plagen en de ingelezen informatie op de verkeerde manier aan de gebruiker tonen. Het programma zal de antwoorden namelijk door elkaar halen waardoor de computer vervolgens toont:
Je favoriete kleur is [eten]. Je eet graag [auto]. Je lievelingsfilm is [boek] en je favoriete boek is [kleur].
Waarbij tussen de rechte haakjes steeds de invoer komt die de gebruiker eerder opgaf voor de bijhorende vraag.
Voorbeeld (tekst die start met liggende streepjes is input van de gebruiker):
Geef je favoriete kleur:
_rood
Geef je favoriete eten:
_lasagne
Geef je favoriete auto:
_mazda
Geef je favoriete boek:
_Het oneindige verhaal
Je favoriete kleur is lasagne. Je eet graag mazda. Je lievelingsfilm is Het oneindige verhaal en je favoriete boek is rood.
Kan je volgende afbeeldingen namaken in de console?
Volgende tekening toont een schematische weergave:
{% hint style="info" %}
Je kan een gekleurd vakje 'tekenen' door de BackGroundColor van de console in te stellen en dan een spatie naar het scherm te sturen.
{% hint style="info" %}
Extra'tjes oefeningen gebruiken zaken die niet bij de leerstof horen, maar die eenvoudig genoeg zijn om eens te bekijken. Meestal zijn ze ook nog eens leuk om te maken, wat mooi is meegenomen.
Met de Console.Beep() methode kan je muziek maken. Volgende voorbeeld toont bijvoorbeeld hoe je do-re-mi-fa-sol-la-si-do afspeelt:
De frequentie van de toon die moet afgespeeld worden. Bijvoorbeeld 264 (in Hertz, hz).
De duur dat de toon moet afgespeeld worden in milliseconden. Als je dus 1000 meegeeft zal de toon gedurende 1000 ms, oftewel 1 seconde, afgespeeld worden.
Open 1 van de eerder gemaakte oefeningen en zorg ervoor dat bij het opstarten ervan er een kort, door jezelf gecomponeerd, introliedje wordt afgespeeld.
{% hint style="info" %}
Het is aanbevolen dat je vanaf nu per hoofdstuk een nieuwe solution aanmaakt op je computer. Per oefening maak je dan best een nieuw project aan dat je in de solution zet. Geef ieder project een duidelijke naam (bv EuroNaarDollar) zodat je later vlot je oefeningen kan terugvinden. Denk er aan dat je je projecten best enkel met cijfers en letters benoemd (dus beter EuroNaarDollar dan Euro-Dollar).
Meer uitleg over Projecten en Solutions en hoe je bovenstaande doet kan je hier terugvinden.
{% hint style="warning" %}
Het is een goede gewoonte om ogenblikkelijk de juiste coding guidelines te volgen. Deze staan in het handboek hier opgelijst.
{% hint style="info" %}
We vragen in deze oefeningen nog geen input aan de gebruiker. Alle getallen worden hard gecodeerd in de variabelen. In een volgend hoofdstuk gaan we leren hoe we input van de gebruiker kunnen vragen.
Maak 3 variabelen aan van het type int genaamd september, oktober en november. Plaats in elke variabele de hoeveelheid uren slaap je die in die maand verwacht te doen. Bereken nu het gemiddelde van 3 maanden en toon het resultaat op het scherm (kies uiteraard 3 verschillende hoeveelheden slaap).
Opgelet: het resultaat moet als een kommagetal worden getoond!
Ontwerp een toepassing waarmee je een bedrag (dat je hardcode in een variabele), inclusief komma-getallen in euro kan omrekenen naar dollar. Gebruik hierbij de huidige wisselkoers. Je hoeft niet af te ronden. Het resultaat op het scherm wordt als volgt weergegeven: [x] EUR is gelijk aan [y] USD.
Dit is de startcode van je applicatie:
double bedragInEuro = 78.65;
Uitvoer:
78,65 EUR is gelijk aan 81,0095 USD.
{% hint style="info" %}
Begrijp je dat al deze oefeningen eigenlijk altijd dezelfde 3 fases hebben?
Data invoer: variabelen aanmaken en waarden geven.
Data verwerken: berekeningen doen met de ingevoerde data.
Data uitvoer: resultaten op het scherm tonen
Als je je applicaties zo opbouwt dan zal je snel ontdekken dat al deze oefeningen eigenlijk in essentie hetzelfde zijn.
{% hint style="info" %}
De k/d ratio is de verhouding tussen het aantal kills dat je in een spel hebt gehaald ten opzichte van het aantal keer dat je zelf bent gestorven, deads. Wanneer deze verhouding dus groter is dan 1 heb je vaker iemand gedood dan dat je zelf gestorven bent. Onder de 1 is dit net omgekeerd...en ben je dus niet zo goed in het spel dat je aan het spelen bent.
Maak twee variabelen double kills en double deaths aan. Wijs er jouw typische gamescores aan toe die je haalt in een spel naar keuze. Bereken en toon vervolgens je kill/death-ratio.
Uitvoer (indien kill=44 is en deaths=9)
Je k/d-ratio is 4,888888888888889
{% hint style="warning" %}
Begrijp je waarom we best een van beide variabelen in double zetten? Lees de waarschuwing van de voorman bij Expressies zeker nog eens na... Of test eens wat er gebeurt indien je met int zou werken.
Merk op dat het vreemd is dat je een niet-geheel aantal kills of deaths kunt halen als je met double werkt. Dat kan natuurlijk niet. Je kunt niet 2,5 keer dood zijn gegaan in een spel. In hoofdstuk 4 gaan we dit oplossen (en er dus voor zorgen dat kills en deaths wel als int kan blijven staan, maar we toch een double als resultaat voor de kdratio krijgen)
Schrijf een programma waarin je het BTW-percentage 21% als een constante definieert door het keyword const voor de variabele te zetten. Vervolgens toon je een prijs naar keuze, met en zonder btw op het scherm.
Dit is je startcode:
double prijs = 20;
const double BTW = 21.0;
Bereken nu de prijs met BTW en toon het resultaat op het scherm.
Voorbeeld output:
Prijs 20 euro zonder btw. Met BTW: 24.2 euro.
{% hint style="info" %}
Je kan de BTW op verschillende manieren berekenen. Kies zelf hoe je dit doet? Je mag dus gerust ook werken met const double BTW = 1.21; of const double BTW = 0.21; , afhankelijk van welke berekenwijze je prefereert.
Je massa is overal dezelfde. Je gewicht daarentegen is afhankelijk van de zwaartekracht van de plek waar je bent. Zo is je gewicht veel groter op Jupiter dan op Mars (uitgedrukt in Newton).
Maak een variabele double gewichtOpAarde aan. Wijs een gewicht toe (bv. het jouwe). Schrijf nu een programma dat onder elkaar jouw gewicht op verschillende planeten toont.
Hier de omzettingstabel (je gewicht op Mercurius is dus je gewicht op aarde x 0.38):
Mercurius: 0.38
Venus: 0.91
Aarde: 1.00
Mars: 0.38
Jupiter: 2.34
Saturnus: 1.06
Uranus: 0.92
Neptunus: 1.19
Pluto: 0.06 (we laten de discussie achterwege of pluto wel of niet een planeet is)
De output zijn verschillende lijnen onder elkaar in de vorm van:
Je weegt op [planeet] [gewichtopdieplaneet] N.
Plaats de zin met Jupiter in het rood, daar je daar het zwaarst weegt en die van pluto in het groen.
Voorbeeld output:
Je weegt op Mercurius 30,627999999999997 N.
Je weegt op Venus 73,346 N.
en zo verder...
Met het statement Console.Clear(); kan je de console - je raadt het nooit - leegmaken. Test deze code in het volgende programma:
Schrijf een programma dat de tafels van vermenigvuldigen geeft van 411 (dus 1x411= 411, 2x411= 822 tot en met 10x411= 4110). Toon telkens 1 zin en wacht dan tot de gebruiker op enter duwt om de volgende vermenigvuldiging op een nieuw scherm te tonen. De output ziet er dus als volgt uit:
1 x 411 = 411
Druk op enter voor de volgende lijn.
[Scherm leeg gemaakt]
2 x 411 = 822
Druk op enter voor de volgende lijn.
[Scherm leeg gemaakt]
...
{% hint style="warning" %}
Plaats 411 en de teller (die van 1 tot en met 10 gaat) elk in een variabele aan de start van het programma en gebruik deze in je berekeningen verderop. Toon dat je code ook werkt door de inhoud van de variabele in een ander getal te veranderen zodat je van dat nieuwe getal nu de tafels van vermenigvuldiging krijgt. Door de waarde 411 bovenaan in een variabele te steken kan je heel snel je programma een andere tafel laten berekenen, je hoeft dan gewoon de waarde van die variabele aan te passen.
Gebruik teller++ om de teller-variabele telkens te verhogen.
Je kan wachten tot de gebruiker op enter duwt door gewoon een lege Console.ReadLine te doen, zoals volgende voorbeeld toont:
Console.WriteLine("Eerste beeld");
Console.WriteLine("Druk enter om voort te gaan.");
Console.ReadLine();
Console.Clear();
Console.WriteLine("Tweede beeld");
{% hint style="info" %}
Merk op dat Console.Clear() niet werkt zoals verwacht op Mac.
Bewaar het resultaat van iedere opgave in een aparte variabele. Reken op papier of met je calculator na wat het resultaat moet zijn. Toon vervolgens de uitkomst (m.b.v. WriteLine) telkens op het scherm en vergelijk die met je eigen berekening. Begrijp je waar de verschillen zitten (als die er zijn)?! Waarom moet je bij de derde en vierde expressie met double werken en niet bij de eerste 2?.
{% hint style="warning" %}
De % hier is de modulo-operator.
{% hint style="info" %}
PRO oefeningen bevatten leerstof die mogelijk niet in deze cursus wordt behandeld, of die in een later hoofdstuk pas aan bod zal komen.
Met de methode System.IO.File.WriteAllText(); kan je een string naar een bestand wegschrijven.
Je geeft hierbij 2 variabelen mee: de bestandsnaam, en de inhoud van het bestand.
Volgende voorbeeld schrijft bijvoorbeeld de zin "Ik ben tim" weg naar een bestand dat zal aangemaakt worden genaamd "me.txt":
System.IO.File.WriteAllText("me.txt", "Ik ben tim");
Schrijf een programma dat aan de gebruiker de naam van het bestand vraagt, gevolgd door wat er in het bestand moet geschreven worden. Vervolgens maak je dit bestand aan en plaats je die inhoud er in.
{% hint style="info" %}
Als je enkel een bestandsnaam meegeeft (en geen volledige folderpath) dan wordt het bestand geplaatst op de plek waar het programma wordt uitgevoerd.
Standaard staat je gecompileerde programma in de bin\debug folder van je project.
Als je dus een solution hebt aangemaakt genaamd "Oefening" in de folder "C:\Temp" dan zal het bestand zich in de volgende folder bevinden "C:\Temp\Oefening\Oefening\bin\debug".
Je kan ook snel naar deze folder gaan door in de solution explorer aan de rechterzijde in VS te rechterklikken op je project en dan te kiezen voor: Open folder in file explorer.
{% hint style="warning" %}
Vanaf dit hoofdstuk wordt verwacht dat je steeds string interpolatie gebruikt om strings samen te voegen, en dus niet meer met + werkt!
MadLibs is een populair woordspelletje waarbij de gebruiker een aantal verschillende woorden moet opgeven. Vervolgens worden deze woorden in een verhaal geplaatst dat zo plots erg grappig kan worden.
In deze oefening vraag je aan de gebruiker volgende zaken:
Een naam (bv. Jos)
Een zelfstandig naamwoord (bv. bal)
Een adjectief (bv. groene)
Een werkwoord (bv. springen)
Vervolgens worden deze woorden in volgende zin geplaatst en aan de gebruiker getoond (gebruik hier string interpolation voor).
Op een dag ging [naam] naar de AP Hogeschool. Hij zag daar een [adjectief] [zelfstandig naamwoord] en vond dat zo grappig dat hij begon te [werkwoord].
Voorbeeld werking:
Geef een naam:
_Jos
Geef een zelfstandig naamwoord:
_bal
Geef een adjectief:
_groene
Geef een werkwoord:
_springen
Hier komt het!
Op een dag ging Jos naar de AP Hogeschool. Hij zag daar een groene bal en vond dat zo grappig dat hij begon te springen.
Schrijf een applicatie die berekent hoeveel dozen van 8 eieren je volledig kan vullen en hoeveel eieren je dan nog zal over hebben. Gebruik ook nu string interpolation in de finale uitvoer.
Bovenaan je programma schrijf je:
const int doosGrootte = 8;
int aantalEieren = 124;
Met deze startinvoer (test ook met andere getallen!) moet je volgende uitvoer krijgen.
124 eieren passen in 15 dozen van doosgrootte:8. Daarbij zal je nog 4 eieren over hebben.
Test of je applicatie ook werkt met andere aantal eieren én doosgrootte.
{% hint style="info" %}
In deze oefening moet je gebruik maken van je kennis van het vorige hoofdstuk, waaronder:
De modulo operator.
Datatypes en wat de impact ervan is op onder andere de deling (twee integers delen geeft...een integer!).
Zorg ervoor dat volgende dialoog op het scherm, met juiste formatering getoond wordt. Je mag enkel de tekst tussen de aanhalingstekens (in de plaats van X) van de variabele dialoog gebruiken (en zal dus escape characters nodig hebben.):
Alice: "Hoe gaat het met je?"
Bob: "Goed, dank je! Hoe gaat het met jou?"
Alice: "Ook goed, bedankt dat je het vraagt."
Gebruik om de tekst van Bob te doen inspringen. Merk op dat de tabgrootte verschillend kan zijn (wat geen probleem is) dan wat je hier als voorbeeld ziet.
Maak een applicatie die de belangrijkste computer-informatie (geheugen, etc) aan de gebruiker toont m.b.v. de Environment. Zoals je ziet wordt het geheugen in bytes teruggegeven. Zorg ervoor dat het geheugen steeds in mega of gigabytes op het scherm wordt getoond. Toon minstens volgende zaken:
ProcessorCount
WorkingSet (in MB en GB)
MachineName
UserName
is64OperatingSystem
Voorbeeld uitvoer:
Systeeminformatie voor admin op damsPowahPC:
---------------------------------------------------
Aantal processors: 8
64-bit besturingssysteem: True
Huidige geheugengebruik: 23.00 MB (0.02 GB)
---------------------------------------------------
Gebruik string formatering (m.b.v. met F2) om de output tot 2 cijfers na de komma op het scherm te tonen.
Genereer je naam in Unicode Art met een van de vele online generators. Toon deze art (m.b.v. WriteLine of Write) aan de start van een van je bestaande programma's, zodat nu je naam wordt getoond wanneer het programma start, gevolgd door de rest.
Ook informatie over de harde schijven kan je verkrijgen (in bits). Dit vereist wel dat je bovenaan je programma volgende lijn bijschrijft: using System.IO.
Vervolgens kan je in je programma schrijven:
long cdriveinbytes = DriveInfo.GetDrives()[0].AvailableFreeSpace;
long totalsize = DriveInfo.GetDrives()[0].TotalSize;
De lijn met using is om aan te geven dat we iets uit de System.IO bibliotheek nodig hebben, namelijk DriveInfo. Schrijven we dat niet dan moeten we in onze code DriveInfo aanroepen met z'n volledige path: System.IO.DriveInfo....
De 0 tussen rechte haakjes is de index van welke schijf je informatie wenst. 0 is de eerste harde schijf, 1 de tweede, enzovoort.
Vraag aan de gebruiker het nummer van de harde schijf waar meer informatie over moet getoond worden.
{% hint style="warning" %}
Opgelet: sta toe dat de gebruiker 1 voor de eerste harde schijf mag gebruiken, 2 voor de tweede, enzovoort. Je zal dus in code nog manueel 1 moeten aftrekken van de invoer van de gebruiken. Bv:
int invoer=int.Parse(Console.ReadLine()) - 1;
long totalsize = DriveInfo.GetDrives()[invoer].TotalSize;
Je kan de output van een Process.Start() programma naar je console scherm sturen. Dit vereist wat meer code. Volgend voorbeeld zal de output van het commando ipconfig /all op het scherm tonen:
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "ipconfig";
process.StartInfo.Arguments = "/all";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); //start process
// Read the output (or the error)
string output = process.StandardOutput.ReadToEnd(); //normal output
Console.WriteLine(output);
string err = process.StandardError.ReadToEnd(); //error output (if any)
Console.WriteLine(err);
//Continue
Console.WriteLine("Klaar");
{% hint style="info" %}
Let er op dat dit voorbeeld niet perfect werkt met een shell-commando dat even duurt. Denk bijvoorbeeld aan ping. De output komt namelijk pas op het scherm als het commando is afgelopen. Test zelf maar eens!
Maak enkele kleine C# programma's die bepaalde shell-commando's zullen uitvoeren, eventueel na input van de gebruiker. Enkele nuttige shell-commando's in de netwerk-sfeer zijn bijvoorbeeld:
hostname
arp -a
getmac
nslookup google.com
netstat
Andere toffe commando's kunnen zijn:
chrome.exe ap.be
notepad mytest.txt
Of de naam van een bestand dat je wilt openen, maar dan met het hele path:
Gebruik je kennis van het verschil tussen Console.Write en Console.WriteLine, alsook de werking van kleuren in console-applicaties, om je Unicode-art naam van de eerdere oefening nu van kleur te voorzien. Zorg ervoor dat minstens 1 letter in een andere kleur is.
{% hint style="info" %}
Dit is een redelijke lange oefening, doe deze best op het einde.
Deze oefening kan je op 2 manieren oplossen:
Je gebruikt een combinatie van Write en Console.SetCursorPosition
Je knipt je tekening op in stukken die je met verschillende Write en WriteLines op het scherm zet. Volgend voorbeeld toont bijvoorbeeld hoe je een vierkantje van sterretjes tekent waarbij het midden van het vierkant rood is:
{% hint style="warning" %}
Gebruik je kennis van debuggen om vanaf dit hoofstuk problemen op te lossen. Gebruik niet Console.WriteLine() om de waarde van een variabele te controleren at-runtime, maar gebruik daarentegen breakpoints!
{% hint style="info" %}
Vanaf dit punt zullen de meeste oefeningen iets "vragen" aan de gebruiker. Hiermee wordt bedoeld dat je de gebruikersinput via ReadLine moet inlezen en indien nodig moet converteren naar het gewenste type.
Vraag aan de gebruiker 3 kommagetallen. Bereken het gemiddelde van deze 3 getallen en toon dit als een kommagetal op het scherm
{% hint style="info" %}
Gebruikersinvoer in de voorbeelden zullen met een liggend streepje voorafgegaan worden. Zo zie je duidelijk wat het verschil is tussen ReadLine en WriteLine in de voorbeelduitvoer.
Voorbeeld:
Geef getal 1:
_23,4
Geef getal 2:
_34,6
Geef getal 3:
_27,7
Het gemiddelde hiervan is: 28,566666666666666
Bereken de oppervlakte en de inhoud van een balk . De gegevens (hoogte, breedte, lengte) worden ingelezen als gehele getallen. Zorg ervoor dat de uitvoer er als volgt uitziet:
Lengte?
_3
Breedte?
_5
Hoogte?
_4
Oppervlakte is 94
Inhoud is 60
Maak een programma dat aan de gebruiker z'n lengte (in cm) en gewicht (in kg) vraagt en vervolgens de berekende BMI (Body Mass Index) toont. Zoek zelf op hoe je het BMI berekent.
Gebruik Math.Round om de uitkomst tot maximum 2 cijfers na de komma te tonen.
Reken na met je rekenmachine of je uitkomst wel degelijk klopt!
Uitvoer:
Wat is uw lengte in cm?
[lengteInCm]
Wat is uw gewicht in kg?
[gewicht]
Een persoon met een lengte van [lengteInMeter] m en een gewicht van [gewicht] kg heeft een BMI van [bmi].
Een vaste klant in je café bestelt altijd "op-de-poef". Dat wil zeggen dat hij niet onmiddellijk betaalt en dat z'n rekeningen worden neergeschreven. Ooit zal de klant dan gevraagd worden de hele som te betalen.
Schrijf een programma dat 5 keer na elkaar aan de barman vraagt om een bedrag in te voeren. Het ingevoerde bedrag wordt opgeteld bij wat er reeds op de rekening staat. Na 5 keer wordt de totale som getoond alsook hoeveel weken het duurt indien de klant wekelijks 10 euro afbetaalt.
Voorbeeldwerking:
Voer bedrag in?
_12
De poef staat op 12 euro.
Voer bedrag in?
_14
De poef staat op 26 euro.
Voer bedrag in?
_3
De poef staat op 29 euro.
Voer bedrag in?
_8
De poef staat op 37 euro.
Voer bedrag in?
_2
De poef staat op 39 euro.
*************************
Het totaal van de poef is 39 en zal 4 weken duren om volledig afbetaald te worden.
{% hint style="warning" %}
Voor deze oefening heb je Math.Ceiling() nodig. Deze methode zal een getal altijd naar boven afronden.
De plaatselijke voetbalclub organiseert een mosselfestijn. Naast mosselen met frietjes (20 EUR) bieden ze voor de kinderen de mogelijkheid om een koninginnenhapje (10 EUR) te kiezen. Verder is er een ijsje als nagerecht voorzien (3 EUR). Om het gemakkelijk te maken kosten alle dranken 2 EUR.
Ontwerp een applicatie zodat de vrijwilliger aan de kassa alleen maar de juiste aantallen moet ingeven, lijn per lijn. (frietjes, koninginnenhapje, ijsje, drank) om de totaal te betalen prijs te berekenen.
Het resultaat wordt als volgt weergegeven: Het totaal te betalen bedrag is x EURO.
Voorbeeld:
Frietjes?
_3
Tussenprijs= 60 euro
koninginnenhapje?
_5
Tussenprijs= 60 euro + 50 euro
Ijsjes?
_2
Tussenprijs= 60 euro + 50 euro + 6 euro
Dranken?
_5
Tussenprijs= 60 euro + 50 euro + 6 euro + 10 euro
Het totaal te betalen bedrag is 126 EURO.
Gebruik een random generator om een orakel (een duur woord voor waarzegger) te maken, namelijk de kleine broer of zus van het Orakel van Delphi. Het programma zal aan de gebruiker vertellen hoe lang deze nog zal leven. Bijvoorbeeld: "Je zal nog 15 jaar leven.".
Het orakel zal enkel realistische getallen geven. M.a.w., getallen van 5 tot en met 125 jaar.
{% hint style="info" %}
We gaan geregeld een oefening in een later hoofdstuk verder uitbreiden. Het orakeltje van Delphi is er zo eentje. Bewaar je oefeningen dus goed!
Vraag aan de gebruiker een hoek in graden. Zet deze om naar radialen , gebruik Math.PI voor Pi. Gebruik vervolgens de verschillende geometrische functies in de Math. bibliotheek om de sinus (.Sin), cosinus (.Cos) en tangens (.Tan) van de hoek aan de gebruiker te tonen
{% hint style="info" %}
Denk eraan: de methoden die met hoeken werken, werken in radialen, daarom moeten we deze eerst omzetten. 1 rad = 180°/PI = 57.295779513°.
{% hint style="info" %}
Je zal merken dat voor bepaalde hoeken (bijvoorbeeld 90 graden) je erg kleine of erg grote waarden krijgt, dat is normaal. De geometrische functie in de Math-bibliotheek berekenen de resultaten (en werken dus niet met een tabel) wat met eindige kommagetallen ervoor zorgt dat je soms in plaats van 1 of 0 (of plus of min oneindig) iets erg kleins of groot krijgt.
Uitvoer:
Geef de hoek in graden:
[hoekInGraden]
Sinus van deze hoek is: [sinus]
Cosinus van deze hoek is: [cosinus]
Tangens van deze hoek is: [tangens]
Sinds 2022 en de sappige verhalen rond Magnus en Niemann is schaken erg populair aan het worden bij "de massa". Tijd om hier dus een oefening rond te maken.
"Een Elo-rating is een getalsmatige aanduiding van de sterkte van een speler. Het wordt het meest gebruikt in schaken, dammen en go, maar kan in principe gebruikt worden bij elke sport waarbij spelers 1 tegen 1 spelen." (bron Wikipedia). We gaan een applicatie schrijven (zie verderop voor de effectieve werking van de applicatie) die:
1° De verwachte score (Ea en Eb) berekend indien 2 spelers tegen elkaar gaan spelen, gebaseerd op hun ELO-rating (Ra en Rb) die je applicatie aan de gebruiker vraagt. 2° Berekenen van hun nieuwe Elo score (R'a en R'b) gebaseerd op de effectieve uitslag (Sa en Sb).
{% hint style="warning" %}
Oefeningen worden sinds vorig hoofdstuk al eens wat langer. Het is belangrijk dat eerste de volledige opgave doorneemt voor je begint te programmeren. Deze gewoonte is essentieel indien je over enkele weken grote 2uur-durende projecten tot een goed einde wenst te brengen.
Pas je BMI-programma uit het vorige hoofdstuk aan zodat je programma feedback geeft aan de gebruiker naargelang het berekende BMI.
De kleur tussen haakjes geeft aan in welke kleur je deze tekst zet:
Onder de 18,5 (rood): ondergewicht.
Van 18,5 tot 25, met 25 niet inbegrepen (groen): normaal gewicht.
Van 25 tot 30, met 30 niet inbegrepen (donkergeel): overgewicht. Je loopt niet echt een risico, maar je mag niet dikker worden.
Van 30 tot 40, met 40 niet inbegrepen (rood): Zwaarlijvigheid (obesitas). Verhoogde kans op allerlei aandoeningen zoals diabetes, hartaandoeningen en rugklachten. Je zou 5 tot 10 kg moeten vermageren.
40 of meer (magenta): ernstige zwaarlijvigheid. Je moet dringend vermageren want je gezondheid is in gevaar (of je hebt je lengte of gewicht in verkeerde eenheid ingevoerd).
a) Maak een oefening die aan de gebruiker vraagt hoeveel paar schoenen hij wenst te kopen. Ieder paar schoenen kost steeds 20 euro. Indien de gebruiker 10 paar of meer koopt kosten de eerste 9 paar nog steeds 20 euro, de overige kosten echter maar 10 euro. Toon aan de gebruiker de totale prijs.
Voorbeeld:
8 schoenen kost 8x20 = 160 euro
12 schoenen kost 9x20 + 3x10 = 210 euro
b) Voeg nu toe dat het programma eerst aan de kassier vraagt tot hoeveel schoenen de korting niet geldt.
Voorbeeld:
De kassierster voert 6 in. Dan kosten 8 schoenen: 6x20 + 2x10 = 140 euro.
{% hint style="info" %}
Je hebt niet noodzakelijk een if voor deze oefening nodig. Indien je deze oefening zonder if kunt oplossen, dan krijg je als extra opgave bij:
c) Zorg ervoor dat de kassier enkel een getal van 3 tot en met 10 kan invoeren bij de vraag tot hoeveel schoenen de korting niet geldt. Indien de kassier een getal buiten deze range invoert wordt de gewone korting toegekend, namelijk vanaf 10 of meer schoenen.
Vraag aan de gebruiker wat hij wenst te berekenen: spanning, weerstand of stroomsterkte. Vraag vervolgens de 2 andere waarden (als dus de gebruiker "Spanning" kiest vraag je aan de gebruiker de stroomsterkte en de weerstand) en bereken m.b.v. de wet van Ohm de gewenste waarde tot 2 cijfers na de komma.
Voorbeeld output:
Wat wil je berekenen? spanning, weerstand of stroomsterkte?
stroomsterkte
Geef me dan de spanning:
_34,4
Geef me dan de weerstandswaarde:
_3,4
De stroomsterkte bedraagt dan 10,12 Ampere
Schrijf een programma om het vroegere nationale bankrekeningnummer te controleren of het al dan niet een geldig nummer is (dus niet het IBAN nummer).
Het bankrekeningnummer wordt ingelezen als 3 gehele getallen van 3, 7 en 2 die de gebruiker apart invoert en die je in 3 aparte variabelen bewaard.
{% hint style="info" %}
Een bankrekeningnummer is geldig als de rest van de deling van het getal, dat bestaat uit de eerste 10 cijfers, door 97, gelijk is aan het getal bestaande uit de laatste 2 cijfers.
Dit is een voorbeeld van een geldige rekening: 000 1459325 57 , want 000 1459325 gedeeld door 97 geeft als rest 57.
Dit een ongeldige: 000 1359325 77, want 1359325 gedeeld door 97 geeft als rest 64 en niet 77
We gaan het Orakeltje verbeteren. Voor het orakel je vertelt hoe lang je te leven hebt zal het eerste vragen of je een vrouw (v) of een man (m) bent. Dan vraagt ze je leeftijd. Mannen leven maximum tot hun 120 jaar. Vrouwen echter tot 150 jaar. Laat het orakel een duur voorspellen die kan. Als een vrouw van 50 de vraag stelt dan zal het orakel dus een getal van 5 tot en met 100 (150-50) genereren. Een man van 35 zal van 5 tot en met 85 (120-35) jaren langer kunnen leven.
Genereer een random getal van 1 t.e.m. 6 maar toon dit niet aan de gebruiker. Vraag aan de gebruiker welk getal hij denkt dat de computer heeft "geworpen". Indien de gebruiker juist raadt verschijnt er "proficiat" op het scherm. Anders: "You lose. Ik wierp [getal]".
Voorbeeld:
Welk getal heb ik geworpen?
_3
You lose. Ik wierp 1.
Vul de voorgaande oefening aan, maar laat de gebruiker 3x na mekaar raden. Enkel als hij juist raadt mag hij nog eens raden. Als hij ook de derde juist raadt wint hij. In alle andere gevallen niet.
Voorbeeld output:
Welk getal heb ik geworpen?
4
Welk getal heb ik nu geworpen?
1
You lose!
en
Welk getal heb ik geworpen?
4
Welk getal heb ik nu geworpen?
1
Welk getal heb ik nu geworpen?
5
Proficat!
Definieer de verschillende schaakstukken in een enum-type (Pion, Loper, Koning, etc.). Maak 2 variabelen aan van dit nieuwe datatype en vraag aan de gebruiker welke waarde elke moet krijgen (bv variabele 1 een pion , variabele 2 een koningin).
Toon aan de gebruiker hoe elke variabele kan bewegen (Pion: "Rechtdoor, 1 of 2 vakjes", Loper: "Schuin", etc.), gebruik hiervoor een switch (die je 3x zal nodig hebben)
Indien beide variabelen hetzelfde stuk zijn dan toont de applicatie de tekst "Beide zijn hetzelfde." gevolgd door hoe ze kunnen bewegen.
Voorbeeld werking:
Welk stuk is stuk1?
_Toren
Welk stuk is stuk2?
_Koningin
Stuk1 kan enkel horizontaal of verticaal bewegen.
Stuk2 kan in alle richtingen bewegen
Ander voorbeeld:
Welk stuk is stuk1?
_Loper_
Welk stuk is stuk2?
_Loper
Beide zijn het zelfde en kunnen enkel schuin bewegen.
Maak een quiz. Maak gebruik van het switch-statement om de input van de gebruiker (a, b, c of d) te verwerken en bij iedere vraag aan te geven of dit juist of fout is. Voorzie 3 multiple choice vragen. Houd bij hoe vaak de speler juist antwoordde en geef op het einde de eindscore (Juist is +2, fout is -1).
Zoek op hoe je de kleur van de letters en de achtergrond in een console-applicatie kunt aanpassen en pas dit toe op je quiz om deze er iets boeiender uit te laten zien. Toon iedere vraag op een nieuw scherm.
De gebruiker voert een jaartal in en jouw programma toont of het wel of geen schrikkeljaar is. Een schrikkeljaar is deelbaar door 4, behalve als het ook deelbaar is door 100, tenzij het wél deelbaar is door 400. Bijvoorbeeld:
1997: geen schrikkeljaar
1996: wél schrikkeljaar
1900: geen schrikkeljaar
2000: wél schrikkeljaar
Kan je dit oplossen met 1 if-statement (met gecombineerde logische expressie?)
Vraag aan de gebruiker om de ringkleuren van de eerste 3 ringen in te voeren als tekst (bv groen). Toon vervolgens de waarde van deze weerstand (kleuren van de ringen kan je in deze tabel vinden) Als dus de gebruiker na elkaar invoert:
rood
paars
rood
Dan zal het programma tonen:
Deze weerstand heeft een waarde van 2700 Ohm
Waarom? Ring 1 is rood en heeft waarde 2. Ring 2 is paars en heeft waarde 7. Samen dus 27. Ring 3 heeft waarde rood, wat wil zeggen dat de vermenigvuldigingsfactor 100 is.
Los deze oefening op met meerdere switchstatements.
Kan jij volgende ludieke stemwijzer van GuntherD in een eenvoudig programma gieten dat door een reeks j/n vragen aan de gebruiker uiteindelijk zijn "stemprofiel" toont?
Maak een enum die de seizoenen van het jaar bevat. Vraag aan de gebruiker om een maandnummer in te voeren. Gebruik vervolgens een switch om te bepalen in welk seizoen deze maand (grotendeels) ligt. Wijs deze enum toe aan een variabele in de switch. Vervolgens gebruik je een if om, gebaseerd op deze enum-variabele, te tonen of het om een koud seizoen (winter en herfst) of een warm seizoen (zomer en lente) gaat.
Je gaat een programma schrijven dat het gedrag van een verkeerslicht simuleert met behulp van een enum. De gebruiker moet het verkeerslicht (een enum variabele) een status geven (groen, oranje of rood), en op basis daarvan moet het programma een bericht weergeven over wat een bestuurder moet doen.
Gebruik een switch-statement om het gedrag van de bestuurder te bepalen op basis van de invoer.
Als het licht groen is: Toon het bericht "Je mag doorrijden."
Als het licht oranje is: Toon het bericht "Maak je klaar om te stoppen."
Als het licht rood is: Toon het bericht "Stop! Wacht tot het licht groen wordt."
Voorbeeld werking:
Voer de status van het verkeerslicht in (Groen, Oranje, Rood):
_Groen
Je mag doorrijden.
Maak een enum die de verschillende soorten gewichten voorstelt (Obees, Zwaarlijvig, NormaalGewicht, etc.) Pas de bestaande "BMI met if" oefening aan zodat je deze enum gebruikt om je code leesbaarder te maken.
In plaats van de 3 mogelijke scenarios (win,loss, draw) vraag je nu aan de gebruiker wie van beide spelers heeft gewonnen ("A", "B" of "D" van Draw/gelijk) en toont enkel de nieuwe ratings gebaseerd op de ingevoerde uitslag.
Pas je applicatie ook aan als volgt: indien de gebruiker een negatieve rating voor een van de beide spelers opgeeft dan gebeuren er 2 zaken:
Er verschijnt een foutboodschap ("Negatieve rating mag niet. Ik genereer een random rating.")
Je genereert een random rating tussen 500 en 3000, toont dit getal aan de gebruiker, en gebruikt dit vervolgens verder in de applicatie.
FIFA berekent de score per nationaal voetbal team met een eigen formule bron waarvan de belangrijkste informatie hier samengevat wordt:
Schrijf een applicatie die de nieuwe P berekent nadat de gebruiker alle nodige informatie heeft ingevoert. Bij de invoer van I krijgt de gebruiker een keuze menu te zien dat de verschillende zinnetjes toont zonder de I-waarde. De gebruiker kiest uit het menu de juiste importance (bijvoorbeeld door a, b, c, etc. in te voeren) en jouw programma zet dit dan om naar een getal. De gebruiker moet voor W invoeren: gewonnen, verloren, gelijk. Jouw programma zal dit omzetten naar het juiste getal (1, 0.5 of 0).
{% hint style="info" %}
Dit zijn goede oefeningen om te testen of je alle leerstof van de voorbije hoofdstukken goed beheerst. De volgende opgaven waren ook soms effectieve (tussentijdse) vaardigheidsproeven voor dit vak.
Maak een multitool-applicatie die wanneer deze opstart aan de gebruiker een menu toont. Afhankelijk van de input van de gebruiker zal er vervolgens een ander stuk uitgevoerd worden. De verschillende keuzes zijn (de gebruiker voert een cijfer in!):
Menuitem 1 - Rekenmachine. Indien dit gekozen wordt zal het programma eerst 2 getallen aan de gebruiker vragen, gevolgd door een keuzemenu waarop de gebruiker een operator kan kiezen (+,-,*,/,%). Het programma toont dan het resultaat indien de operator op de twee ingevoerde getallen wordt uitgevoerd. Wanneer de uitkomst negatief is dan zal de uitkomst in het rood worden getoond.
Menuitem 2 - Password tester: Vraag aan de gebruiker z'n paswoord. Indien dit gelijk is aan "TrumpSux" zal er een groene tekst "Toegelaten" verschijnen. Zoniet een rode "Verboden" tekst.
Menuitem 3 - Recyclage: Kies eender welk programma dat je in dit of vorig hoofdstuk hebt gemaakt waarin je input aan de gebruiker ook verwerkt. Plaats dit programma achter dit menuitem
Menuitem 4 - Computersolver : Implementeer volgende flowchart . Een ruit geeft aan dat je een ja/nee vraag aan de gebruiker stelt (gebruik de tekst dus in de ruit). Een rechthoek (ook die met ronde hoeken) is tekst die je aan de gebruiker toont.
De gebruiker dient steeds met "ja" of "nee" te antwoorden bij de vragen.
De applicatie begint met "Zet de computer aan." En stelt dan de eerste vraag ("Gaat de computer aan").
Na ieder antwoord wordt het scherm leeggemaakt. Finaal bereikt de gebruiker dan een van de onderstaande fasen A,B of C, die verderop in de opgave worden uitgelegd.
De gebruiker dient de foutcode als geheel getal in te voeren. Dit moet een getal van 0 tot en met 9 zijn. Bij alle andere getallen (bijvoorbeeld -1 of 14) verschijnt er "Los het dan zelf op he!" en sluit het programma zich af.
Wanneer een correct getal werd ingevoerd verschijnt er in RODE LETTERS de boodschap "Gelieve je computer gedurende X minuten af te zetten."
X is een getal dat berekend wordt als volgt: vierkantswortel van (foutcode * 3)
X verschijnt op het scherm met 1 cijfer na de komma.
In fase B verschijnt er op het scherm op het "Mooi zo, alles werkt."
Om de gebruiker aan te moedigen een werkende computer te hebben is er ook 25% kans dat hij een extra bonus krijgt.
In 25% van de gevallen dat fase B wordt bereikt verschijnt er namelijk een tweede zin: “En u wint ook nog eens 1 jaar gratis IT support!” De overige 75% keren dat fase B wordt bereikt verschijnt er enkel "Mooi zo, alles werkt." op het scherm.
In deze fase wordt eerst wat meer informatie over de huidige computer getoond (merk op dat deze fase bij de klant op de computer eigenlijk moet uitgevoerd worden, maar doe maar alsof)
Verkrijg via de Environment-bibliotheek het aantal processoren van de huidige computer ( ProcessorCount) en gebruik deze waarden om
Indien er 1 processor in de computer zit komt er in witte letters op rode achtergrond op het scherm “1 processor”
Indien er 2 of meer in zitten toon je het aantal processoren als getal met een groene achtergrond en blauwe letters,
Vervolgens berekent het programma de kostprijs voor de reparatie. Deze is 50€ per processor. Een computer met 5 of meer processoren zal altijd 200 euro kosten. Bereken de kost door het aantal processoren uit de vorige stap te gebruiken en toon dit op het scherm.
Voorbeeld 1 fase C:
Voorbeeld 2 fase C:
De gebruiker krijgt een bon voor een gratis reparatie indien hij een 64 bit computer gebruikt. Bevraag dit via de Environment-bibliotheek en toon "Hier een bon!" indien een 64 bit processor aanwezig is.
IPP – Intergalactic PizzaPhone - is de populairste pizza-delivery service van het heelal. Ze hebben jouw hulp ingeschakeld om een nieuwe bestel-module te maken. Jouw module moet ervoor zorgen dat de telefoonoperators veel sneller de bestellingen kunnen invoeren en doorgeven aan de keuken.
yIghoSDo' chenmoHwI'! (Klingon voor: Veel succes maker!)
Deel 1- Bestelmodule (15 punten) De bestelmodule uit een aantal onderdelen (Alle prijzen worden uitgedrukt in Intergalactic Credits (IC))
Bevraging: er wordt aan de klant een aantal vragen gesteld (bv type pizza, etc)
Visualisatie: de bestelling wordt getoond op het scherm
Berekening: de totaalprijs wordt berekend
Ticket: de totaalprijs wordt getoond
Deel 2 – Uitbreidingen (5 punten) Deze zullen achteraan de opgave uitgelegd worden. Het is aangeraden om eerst deel 1 af te werken voor je aan de uitbreidingen begint.
Indien "Martian meal" wordt besteld moet de operator ook vertellen dat dit niet geschikt is voor kinderen onder de 54 jaar. De operator zal daarom nu de leeftijd vragen en enkel verder gaan indien deze groter of gelijk is aan 54. Indien jonger stopt programma en verschijnt er “ERROR” in rode letters op het scherm.
De gebruiker kan kiezen uit 2 soorten toppings, hij mag ook verkiezen om zonder topping verder te gaan. De kost van een topping kan afhankelijk zijn van de gekozen pizzabodem:
Als finale vraag dient de gebruiker door te geven hoe ver het afleveradres is in lichtjaren. Dit zal steeds een geheel getal van 1 tot en met 100 moeten zijn.
Indien de gebruiker een getal buiten deze grenzen ingeeft dan sluit het programma door in rode letters “ERROR” op het scherm te zetten
De prijsberekening van de pizza gebruikt de prijzen hierboven vermeld en is gewoon de optelsom van de aparte delen.
Na de pizza-prijs berekening wordt berekend hoeveel de transportkosten zullen zijn. Deze zijn gebaseerd op de afstand tot de aarde in lichtjaren als volgt:
Transportkosten:
Afstand kleiner dan 10 : 25 IC
Afstand groter of gelijk aan 10: $\sqrt(s/p)+p$ (met p gelijk aan de pizzaprijs en s de afstand)
De transportprijs wordt naar beneden afgerond tot het eerste gehele getal.
Indien de chef’s extra werd gekozen dan zal er een 10% korting op de totale transportkosten gegeven worden
Gebruik string interpolatie voor dit deel. Een ticket wordt getoond dat de volledige bestelling in tekst toont met erachter, via tab, steeds de prijs. Onderaan volgt de totaalprijs. Voorbeeld van een ticket:
Martian meal 2.8 IC
Italian Cheese 5.5 IC
- - - - - - - - -
Totaal pizza 8.3 IC
Afstand 12 Lichtjaren
Transportkosten: 9 IC
- - - - - - - - -
TOTAAL 17.3 IC
De standaard korting voor de chef’s extra op de transportkosten is 10%. In deze uitbreiding zou het bedrijf graag hebben dat een willekeurige korting wordt toegekend. Deze zal steeds een willekeurige bedrag van 0 tot en met 50% korting zijn.
Deze module zal berekenen hoeveel tonnen benzine er nodig zijn om de pizza bij de klant te krijgen. Er is 1 ton benzine nodig per 5 lichtjaar. Indien de klant dus 12 lichtjaren ver woont dan zijn 3 tonnen nodig, waarbij de derde ton maar voor 2/5 (40%) zal opgebruikt worden.
De module zal dus steeds het geheel aantal tonnen benzine tonen , gevolgd door hoeveel % van de laatste ton nodig zal zijn (indien deze volledig opgebruikt zal worden dan toon je 100% uiteraard; bv wanneer de klant op 10 lichtjaar woont)
De benzine module toont deze informatie onderaan het ticket:
Martian meal 2.8 IC
Italian Cheese 5.5 IC
- - - - - - -
Totaal pizza 8.3 IC
Afstand 12 Lichtjaren
Transportkosten: 9 IC
- - - - - - -
TOTAAL 17.3 IC
*********************************
Informatie voor de piloot:
Benzine tonnen in te laden 2
Benzine over in laatste ton: 60%
We maken een applicatie die leerlingen kunnen gebruiken om beter te weten wat ze moeten doen in tijden van corona. De applicatie bestaat uit 2 delen:
Een “Covidbeslissingshelper”: deze zal enkele vragen aan de leerling vragen om te beslissen of de leerling naar school mag blijven gaan of in quarantaine moet
Een “Covidquiz”: de leerling zal een vraag over Covid moeten oplossen om te zien of de leerling de regels goed genoeg kent.
3 punten staan op naamgeving, layout en algemene oplossingsmethode
Maak een applicatie volgens volgende flowchart en de uitleg verderop:
Gebruik een switch om afhankelijk van de invoer van de gebruiker een ander deel (Covidquiz of Covidbeslissingshelper) uit te voeren:
Indien de gebruiker iets anders dan ‘c’ of ‘q’ invoert dient de applicatie af te sluiten nadat het de boodschap “Verkeerde invoer” op het scherm heeft getoond.
Een reeks vragen wordt gesteld, afhankelijk van het vorige antwoord wordt er mogelijk een andere vraag gesteld.
Toon finaal wat de leerling moet doen. Toon dit met tekst wiens achtergrondkleur overeenkomt met die in de flowchart (groen indien naar school mag gegaan worden, rood indien quarantaine)
Deze quiz gaat testen of de leerling weet wanneer hij/zij getest moet worden na een risico-contact te hebben gehad. De regel is eenvoudig: bij een contact moet je je na 5 dagen laten testen.
De quiz zal dit testen als volgt:
• De quiz genereert een getal tussen 1 en 5 dagen, inclusief 5 zelf. Dit stelt het aantal dagen voor dat de leerling reeds in quarantaine is.
Dit wordt aan de gebruiker getoond.
Vervolgens wordt gevraagd hoeveel dagen de leerling nog moet wachten voor deze zich moet laten testen.
De gebruiker voert dit getal is. Indien dit juist is toon je in groene letters “correct”. Bij fout toon je in rode letters “Fout” gevolgd door het juiste antwoord
Voorbeeld: Als de computer 3 toont, dan is het juiste antwoord 2. De student moet namelijk op dag 3 nog 2 dagen wachten om op dag 5 getest te worden.
Zorg ervoor dat ieder deel (ruiten en vierkanten) uit de covidbeslissingshelper maar 1x in code moet beschreven staan. Je kan de covidbeslissingshelper in 40 of minder lijnen code oplossen.
Een bekende streamingdienst twim.tv heeft jou gevraagd om een softwarepakket te ontwikkelen dat hun klanten kunnen gebruiken terwijl ze video’s streamen. De applicatie zal de streamers helpen om viewers bij te kopen en te zien hoe goed hun stream het doet.
De applicatie bestaat uit 3 duidelijke delen die alle 3 steeds zullen uitgevoerd worden:
Belangrijke afspraken
Strings worden altijd m.b.v. string interpolatie naar het scherm gestuurd.
Wanneer de applicatie opstart, groet deze de gebruiker. Hierbij wordt de gebruikersnaam uit het systeem (m.b.v. de correcte Environment-eigenschap) uitgelezen.
Voorts worden volgende willekeurige getallen (uiteraard automatisch gegenereerd) aangemaakt:
Het aantal viewers dat naar de stream kijkt: dit kan 1000, 2000, 3000 , 4000 of 5000 zijn. Dit wordt willekeurig bepaald.
Het huidige budget uitgedrukt in credits van de gebruiker: dit is een willekeurig geheel getal gelegen tussen 100 (100 inbegrepen) tot en met 600.
Deze optie kost 200 credits. Indien de gebruiker niet genoeg credits heeft dan verschijnt er in rode letters “Niet genoeg credits” en wordt er naar deel 3 van het programma gegaan. Indien de gebruiker 200 of meer credits heeft dan:
Wordt het budget met 200 verlaagd.
Wordt het aantal viewers met 1000 verhoogd
Voorzie ook de mogelijkheid om te onthouden of je viewers gekocht hebt. Vervolgens verschijnt er het nieuwe budget en aantal viewers op het scherm en wordt het laatste deel van de applicatie gegaan (“Bepalen van de categorie”)
Deze optie kost 300 credits. Indien de gebruiker niet genoeg credits heeft dan verschijnt er in rode letters “Niet genoeg credits” en wordt er naar deel 3 van het programma gegaan.
Indien de gebruiker 300 of meer credits heeft dan:
Wordt het budget met 300 verlaagd.
Wordt het aantal viewers als volgt verhoogd:
Indien het huidig aantal viewers een veelvoud van 2000 is komen er 1000 viewers bij
Zo niet komen er 500 viewers bij
Voorzie ook de mogelijkheid om te onthouden of je adspace gekocht hebt.
Vervolgens verschijnt er het nieuwe budget en aantal viewers op het scherm en wordt er naar het laatste deel van de applicatie gegaan (“Bepalen van de categorie”)
Indien de gebruiker een ander getal dan 1, 2 of 3 invoert dan verschijnt er op het scherm dat dit geen geldige keuze is. Voorts gebeuren er volgende zaken:
Er wordt 10% van het budget afgetrokken (tot 2 cijfers na de komma). Het resultaat wordt naar beneden afgerond.
Het aantal viewers wordt met een vierde (naar boven afgerond) verminderd.
Er verschijnt op het scherm: “Je verliest 1 op 4 viewers.”
In dit finale gedeelte wordt de “gezondheid” van de streamer bepaald. Het aantal viewers, budget en aankopen in deel 2 bepalen hoe gezond een streamer is. Er zijn 4 soorten streamers:
Beginner
Gevorderde
Faker
Onbekend
De applicatie toont tot welke categorie de streamer zich bevind waarbij deze categorie als een enum intern wordt voorgesteld.
Beginner: je hebt 200 of minder credits en je hebt 4000 of minder viewers
Gevorderde: je hebt 5000 of meer viewers en je hebt 1 aankoop gedaan in deel 2
Faker: je hebt 4000 of minder viewers en je hebt in deel 2 adspace viewers gekocht
Onbekend: je voldoet niet aan 1 van voorgaande categorieën Indien 2 of meer categorieën gelden voor een gebruiker, dan wordt de bovenste uit deze lijst toegewezen.
Indien de gebruiker als “Faker” wordt bestempeld krijg je de vraag of je voor 100 credits het profiel wil omgezet zien worden naar “Gevorderde”. Indien de gebruiker met “nee” antwoordt sluit het programma af. Indien de gebruiker “ja” antwoordt komt er op het scherm “Word beter!” en dan sluit het programma af.
Vanaf dit hoofdstuk zul je véél meer oefeningen voorgeschoteld krijgen dan je kan afwerken in 1 labo tijd (I dare you ;) ). Selecteer zelf de oefeningen die je wenst te doen en sla die over waarvan je overtuigd bent ze al te kunnen.
De oefeningen zijn, in de mate van het mogelijke, gerangschikt op relatieve moeilijkheidsgraad.
Indien niet expliciet vermeld mag je kiezen met wat voor loop (for, while, do while) je het probleem zal oplossen. Denk echter steeds goed na wat voor loop de beste keuze is. Indien je van te voren weet hoe vaak de loop moet uitgevoerd worden, dan is een for de beste keuze. Weet je dat niet dan kies je voor while of do while (weet je nog het verschil tussen beiden?).
Oefeningen waar n wordt gebruikt geven aan dat dit een getal is dat je aan de gebruiker vraagt aan de start.
Met afsluitwaarde bedoelen we een waarde die de gebruiker moet invoeren om het programma te stoppen. Dus zolang de gebruiker NIET die afsluitwaarde invoert zal het programma om nieuwe waarden blijven vragen.
Lees een willekeurig aantal getallen van de gebruiker (de gebruiker kiest zelf de getallen) met als afsluitwaarde 0. Bereken de som en druk die af. Je blijft dus de getallen van de gebruiker optellen tot deze 0 invoert, dan stopt het programma.
Lees een willekeurig aantal getallen in met als afsluitwaarde 0. Druk het aantal strikt positieve en het aantal strikt negatieve getallen af.
Lees een willekeurig aantal getallen in met als afsluitwaarde -32768. Bepaal het aantal strikt positieve getallen, het aantal strikt negatieve getallen en het aantal getallen gelijk aan nul. Druk deze aantallen af.
Lees een willekeurig aantal getallen in met als afsluitwaarde 0. Bereken het product en druk dit af.
(PRO) Lees een getal in en druk de som van zijn cijfers af.
Lees een willekeurig aantal positieve getallen in en bereken het (afgekapt) gemiddelde ervan. De afsluitwaarde is een willekeurig negatief getal.
Lees een willekeurig aantal getallen in met afsluitwaarde -32768. Druk het kleinste getal af en het aantal keer dat het voorkomt. Als de gebruiker volgende reeks invoerde: "3,2,1,2,3,1,4,5,1,2,-32768'. Dan komt er 1 als kleinste getal op het scherm en 3 (omdat 1 drie maal werd ingetypt)
Een reeks in stijgende volgorde gesorteerde getallen wordt ingelezen. De invoer moet stoppen indien er een fout in de sorteervolgorde voorkomt.
Een reeks getallen wordt ingelezen. De invoer moet stoppen indien er twee maal achter elkaar een nul wordt ingelezen. Het gemiddelde van de reeks getallen wordt afgedrukt. De laatste twee nullen tellen uiteraard niet mee voor de bepaling van het gemiddelde.
Bepaal de som van de kwadraten van de even natuurlijke getallen van 50 tot 100 (inbegrepen). De som wordt afgedrukt.
Een reeks van 100 getallen wordt ingelezen. Van de positieve getallen moet er afgedrukt worden hoeveel deelbaar waren door 2, hoeveel deelbaar waren door 3 en hoeveel door 6.
Druk de som af van de eerste 30 termen van de volgende reeksen:
6 + 12 + 18 + 24 + 30 + ...
4 + 12 + 20 + 28 + 36 + ...
1 + 2 + 4 + 8 + 16 + ...
1 + 1/2 + 1/4 + 1/8 + 1/16 + ...
1 + 1/3 + 1/5 + 1/7 + 1/9 + ...
1/2 + 1/3 + 1/5 + 1/9 + 1/17 + ...
Druk de som af van de eerste 20 termen van de volgende reeksen:
Gebruik de kracht van loops om pijlsnel de tafels van vermenigvuldigen op het scherm te tonen van een getal naar keuze(dus bijvoorbeeld 2x1, 2x2, tot 2x10 en alles daartussen).
Gebruik de kracht van geneste loops om pijlsnel alle tafels van vermenigvuldigen op het scherm te tonen van de getallen 1 tot en met n(dus 1x1, 1x2,... 1xn, 2x1, 2x2,...,2xn tot en met n x n).
DNA heeft steeds een RNA-complement (DNA is het gevolg van RNA transscriptie). Schrijf een programma dat een ingevoerde DNA-string omzet naar een RNA-string. De gebruiker voert steeds 1 DNA-nucleotide in per keer en duwt op enter, de RNA string wordt steeds groter. Na 12 karakters stopt het programma.
De omzetting is als volgt:
G wordt C
C wordt G
T wordt A
A wordt U
Als de gebruiker dus ACGTGGTCTTAA heeft ingevoerd moet het resultaat: UGCACCAGAAUU zijn.
Ga er van uit dat de gebruiker letter per letter invoert (telkens dus enter na een letter) en je de omgezette string doet groeien (m.b.v. +=).
Schrijf een programma dat aan de gebruiker een getal vraagt en vervolgens toont of het ingevoerde getal een Armstrong-nummer is of niet.
Je zou deze oefening kunnen oplossen door het ingevoerde getal als string op te splitsen in individuele char's. Maar we raden je aan om de "wiskunde" weg te volgen zodat je terdege leert met loops en wiskunde te werken.
Stel dat je het getal 4563 hebt:
Eerst deel je 4563 door 1000. Dit geeft 4.
We trekken 4x1000 van 4563 af. Dit geeft 563.
Deel 563 door 100. Dit geeft 5.
We trekken 5x100 van 563 af. Dit geeft 63.
Deel 63 door 10. Dit geeft 6.
We trekken 6 x 10 van 63 af. Dit geeft 3
Je kan van een string weten hoe groot deze is als volgt:
//veronderstellend dat myInputGetal van het type string is
int lengte= myInputGetal.Length;
Je kan dan nu met Math.Pow(10,lengte-1) berekenen vanaf welke exponent van 10 we moeten beginnen werken.
Zorg ervoor dat je Schaak-elo programma "blijft werken" als volgt:
1° De gebruiker geeft z'n begin Elo-rating op
2° Een loop start en vraagt nu telkens de Elo-rating van de huidige tegenstander, gevolgd door de uitslag. Telkens wordt de nieuwe Elo-rating van de gebruiker getoond. Wanneer de gebruiker een negatieve rating voor z'n volgende tegenstander opgeeft stopt de loop.
Maak volgende opdracht van projecteuler.net:
>Indien we alle natuurlijke getallen van 0 tot en met 10 oplijsten die een meervoud van 3 of 5 zijn, dan krijgen we de getallen 3,5,6,9 en 10. De som van deze 4 getallen is 33.
Maak nu een programma dat de som van alle veelvouden van 3 of 5 weergeeft van 0 tot en met 1000 (dit zou 234168 moeten geven).
De modulo-operator (%) is je grote held hier. Een getal is een veelvoud van x indien getal % x 0 als resultaat geeft.
Schrijf een programma dat de volgende output geeft, gegeven dat de gebruiker een maximum waarde invoert, dus als hij 4 ingeeft dan zal de driehoek maximum 4 breed worden. Gebruik enkel 2 geneste for-loops!
Een extra grote hoop oefeningen om je loops te oefenen (originele bron). De oefeningen zijn gerangschikt naar moeilijkheid, je moet deze allemaal met loops oplossen! Hoe ver geraak je?
Probeer niet alle oefeningen met hetzelfde type loop te doen, wissel tussen while, do-while en for.
Indien er sprake is van n in de opgave dan is dit een getal dat je eerst aan de gebruiker moet vragen.
Opgelet: de oplossing van dit soort oefeningen vind je overal. Weersta hier aan, en probeer ZELF de oplossing te vinden. Dat is de enige manier om dit te leren.
Niet zeker van je oplossing? Test of je met minimale aanpassing de grenzen van je programma kunt aanpassen. Als je bijvoorbeeld de getallen van 1 tot 100 moet tonen dan zou je met 2 wijzigingen maximum dit moeten kunnen aanpassen naar de getallen van -1000 tot 21234.
Schrijf een programma dat alle Unicode karakters en hun waarde toont van 10 tot n (tip: char c = Convert.ToChar(65); zal hoofdletter A tonen). Merk op dat sommige unicode karakters (zeker die vooraan) "onzichtbaar" zijn en dus niets op het scherm zullen geven.
Toon het alfabet van a tot z.
Schrijf een programma dat de macht van een getal toont. De gebruiker voert eerst het getal in, gevolgd door de macht (bv. 2 en 4 zal als resultaat 16 geven (2 tot de 4e macht)). Merk op dat je geen gebruik mag maken van Math.Pow. Je dient zelf de vermenigvuldiging helemaal (m.b.v. loops) uit te voeren.
Schrijf een programma een getal n ontbindt in factoren. Factoren zijn de getallen waardoor je n kan delen zonder rest (van bijvoorbeeld het getal 100 zijn de factoren 1, 2, 4, 5, 10, 20, 25, 50 en 100).
Schrijf een programma dat controleert of een getal priem is of niet.
Schrijf een programma dat het aantal digits in een getal telt (het getal 12348 heeft bijvoorbeeld 5 digits).
(PRO) Schrijf een programma dat een ingevoerd getal als tekst uitschrijft. Als de gebruiker dus 123 invoert zal de uitvoer zijn: honderd drie en twintig.
Schrijf een programma om de eerste n termen van een harmonische reeks te tonen en bereken vervolgens de som van deze termen. Als de gebruiker bijvoorbeeld 5 invoert verschijnt er (de laatste plus mag je tonen om geen onnodige ingewikkelde code te moeten schrijven):
1/1 + 1/2 + 1/3 + 1/4 + 1/5 +
Som = 2.283334
Schrijf een programma dat de som van de serie 9+99+999+9999+99999+999999 berekent (mét loop uiteraard).
Vraag aan de gebruiker getallen tot hij -1 invoert. Toon het gemiddelde van de ingevoerde getallen.
{% hint style="info" %}
Begin pas aan deze oefeningen wanneer je voldoende geoefend hebt door de vorige 2 delen oefeningen op te lossen.
Deze oefeningen zijn oefeningen die je moet kunnen indien je hoofdstuk 6 goed en wel beheerst. Ze zijn dus een goede maat om te weten of je het hoofdstuk al voldoende in de vingers hebt.
Maak een 'boekhoud-programma': de gebruiker kan continu positieve en negatieve getallen invoeren. Telkens hij op enter duwt wordt de huidige invoer aan de balans bijgevoegd. Het programma stopt met getallen vragen wanneer de gebruiker 'q' invoert. Finaal worden dan de volgende zaken op het scherm getoond:
De balans van alle ingevoerde getallen: dit is gewoon de som van de getallen. Als de gebruiker dus de getallen 4, -10 en 8 invoerde dan zal de balans op +2 staan (4 -10 + 8).
De som van alle negatieve invoeren. Als de gebruiker dus 4, -10, 8 en -6 invoerde dan zal dit getal op -16 staan (= -10 -6).
De som van alle positieve invoeren. Als de gebruiker dus 4, -10, 8 en -6 invoerde dan zal dit getal op +12 staan (= 4 + 8).
Het gemiddelde van alle ingevoerde getallen.
Deze 4 getallen worden ook steeds geüpdatet en getoond wanneer de gebruiker een nieuw getal invoert en op enter duwt.
Simulatie van het "hoger-lager" spel. Het programma kiest een random-getal van 1 tot en met 100 (telkens inbegrepen). Vervolgens wordt de gebruiker gevraagd om een gok te doen en toont het programma of de gok juist was, te laag was ("hoger") of te hoog ("lager"). Het programma blijft gokken van de gebruiker accepteren tot de gok juist is of de gebruiker besluit te stoppen (door een negatief getal in te voeren). Het aantal beurten wordt op het einde van het spel getoond en de mogelijkheid om opnieuw te spelen.
Maak een applicatie die je kan gebruiken om je tafels van vermenigvuldigen te oefenen. De applicatie vraagt steeds een willekeurige vermenigvuldiging (enkel getallen tussen 1 tot en met 10) en de gebruiker moet de oplossing invoeren. Indien correct gaat de gebruiker verder. Bij fout stopt het programma en wordt getoond hoeveel keer je juist hebt ingevoerd.
Bouw levels in de voorgaande wiskundequiz. Per 5 juiste antwoorden, stijg je 1 level. Het level bepaalt het bereik van getallen die gegenereerd worden bij de oefening. Bijvoorbeeld level 1 enkel getallen van 1 tot en met 5, level 2 tot en met 10, level 3 tot en met 20 etc.
PRO: Kan je ervoor zorgen dat het bereik van de getalgeneratie met een formule afhankelijk is van het level? Zodat je de grenzen per level niet moet hardcoden?
Integreer voorgaande quiz met een menu dat je bijvoorbeeld in codemenu hebt gemaakt. Het menu wordt aan de start getoond en geeft de gebruiker de optie om te kiezen wat hij wenst te doen:
Gewoon spelen
Starten op een bepaald level (de gebruiker moet vervolgens het level invoeren)
Studeren: de oplossing wordt steeds getoond. De gebruiker hoeft niets in te voeren, elke 5 seconden verschijnt de volgende opgave met oplossing. Gebruik System.Threading.Thread.Sleep(5000) om je programma 5 seconden (5000 ms) te pauzeren.
Twee getallen van 2 tot en met 20 worden ingelezen (invoercontrole!). Er moet een open rechthoek afgedrukt worden bestaande uit *en waarbij de ingelezen getallen respectievelijk de breedte en de hoogte van de rechthoek voorstellen. Als bijvoorbeeld 10 en 4 werden ingelezen, wordt de volgende rechthoek getoond:
Maak een applicatie waarbij de gebruiker steen-schaar-papier met de computer kan spelen. De gebruiker kiest telkens steen, schaar of papier en drukt op enter. Vervolgens kiest de computer willekeurig steen, schaar of papier (gebruik de Random.Next() methode, waarbij je deze van 1 tot en met 3 laat varieren). Vervolgens krijgt de winnaar 1 punt:
Steen wint van schaar, verliest van papier.
Papier wint van steen, verliest van schaar.
Schaar wint van papier, verliest van steen.
Indien beide hetzelfde hebben wint niemand een punt.
Op het scherm wordt telkens getoond wie de huidige ronde heeft gewonnen en hoeveel de tussenscore is. De eerste (pc of gebruiker) die 10 punten haalt wint.
Teken een flowchart van je applicatie.
{% hint style="info" %}
Los dit op met enum : je code zal een pak leesbaarder worden
Maak een applicatie die bij het opstarten een keuze menu toont. Het menu toont 5 verschillende oefeningen naar keuze. Telkens de gebruiker in het menu een oefening kiest (door a, b, c, d of e in te voeren) wordt de code van die oefening getoond. Vervolgens kan de gebruiker op enter duwen zodat terug het menu verschijnt, zodat de gebruiker een nieuwe oefening kan kiezen
Extra: maak je menu visueel interessanter (m.b.v. kaders en kleuren)
Schrijf een BeerSong-generator zoals onderstaande output. Merk op dat de laatste 5 zinnen anders zijn:
99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.
98 bottles of beer on the wall, 98 bottles of beer.
Take one down and pass it around, 97 bottles of beer on the wall.
97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 bottles of beer on the wall.
96 bottles of beer on the wall, 96 bottles of beer.
Take one down and pass it around, 95 bottles of beer on the wall.
95 bottles of beer on the wall, 95 bottles of beer.
Take one down and pass it around, 94 bottles of beer on the wall.
...
4 bottles of beer on the wall, 4 bottles of beer.
Take one down and pass it around, 3 bottles of beer on the wall.
3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Take it down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.
Ook dit hoofdstuk bevat meer oefeningen dan je lief zijn. Zoek zelf de oefeningen uit die je aanspreken en focus je op het leren werken met methoden en deze te integreren in een grotere applicatie.
Tip van een lector: meestal als een boek veel oefeningen van een bepaald onderwerp bevat is de kans bestaande dat dit onderwerp misschien wel eens belangrijk kan zijn ;)
OPGELET: de naam van de methode geeft meestal aan wat er juist moet gebeuren. ReadLine en WriteLine mag je bijna NOOIT in methoden gebruiken. Enkel als de methode bijvoorbeeld ToonGetal heet dan zal je iets met WriteLine IN de methode moeten doen. Heet de methode VraagGetal dan zal je inderdaad ReadLine mogen gebruiken. In bijna alle andere gevallen mag dat niet en is het dus de bedoeling dat je de vereiste informatie als parameters aan de methode meegeeft (i.p.v ReadLine), en het resultaat als return teruggeeft (i.p.v. WriteLine).
Sommige oefeningen zijn van de vorm "Maak een methode die...". Het is steeds de bedoeling dat je de werking van je methode ook test in je main door deze aan te roepen.
Maak een methode die jezelf voorstelt op het scherm in de vorm van "Ik ben Tim Dams, ik ben 18 jaar oud en woon in de Lambrisseringsstraat 666".
Deze informatie mag hardcoded in je methode staan. Bedoeling is dat je de methode kan aanroepen als volgt:
MyIntro();
Deze methode toont enkel zaken op het scherm en heeft dus als returntype void.
Maak minimaal de methoden genaamd TelOp, TrekAf, Vermenigvuldig en Deel. Je kan aan deze methoden steeds twee doubles meegeven en het resultaat dat terugkomt is uiteraard de bewerking van die twee parameters.
Maak een eenvoudig programma waarin je die methoden test.
Dit is geen oefening, maar wel een manier om voor je zelf extra oefeningen te maken.
Gebruik volgende prompt om één of meerdere goede Methoden-oefeningen te genereren. Vervang "XXXX" door een onderwerp of genre waar je interesse in hebt (bijvoorbeeld "counterstrike", "F1 racing", etc.).
"
Je bent een lector van een hogeschool die studenten helpt met programmeren. Je bent heel goed in interessante opgaves in C# te ontwikkelen die studenten motiveert om te blijven programmeren.
Verzin een C# oefening voor mij die me doet oefenen op methoden. Methoden geven maximum 1 element terug. Gebruik dus geen tuples of sets van returntypes bij methoden.
Volgende zaken mogen in de oefening aanwezig zijn:variabelen, if else, switch, expressies, de math bibliotheek en loops. De nadruk ligt op het oefenen op methoden.
Volgende zaken mogen niet in de oefening aan bod komen: arrays, lists, linq en object georiënteerd programmeren.
Laat de oefening gaan over XXXX.
Toon geen voorbeeldcode of oplossing.
Toon wel voorbeelduitvoer.
Leg ook expliciet uit welke methoden ik moet schrijven en hoe ze werken
Stel ook 3 mogelijke uitbreidingen voor.
"
OPGELET: zoals je weet bestaat de kans dat ChatGpt toch oefeningen maakt die je nog niet kan, ondanks de prompt. Het kan bijvoorbeeld gebeuren dat de oefening toch vereist dat je al weet wat arrays zijn. In dat geval kan je zelf de oefening voor je zelf vereenvoudigen, of vragen aan ChatGPT om het stuk dat je niet begrijpt er uit te halen (of uit te leggen wat hij juist bedoelt).
Gebruik volgende prompt om je code te verbeteren en evalueren, waarbij je "XXXX" vervang door je volledige code. OPGELET: doe dit in dezelfde chat als waarin je de opdracht prompt genereert:
"
Hierna volgt mijn oplossing. Kan je deze evalueren op correctheid, naamgeving, mate van overbodige code, etc., Let op: we mogen geen gebruik maken van van arrays, linq, lambdas, goto, break mag enkel in switch, events, delegates en objectgeoriënteerd programmeren. Geef vooral aandacht aan het gebruik van methoden, wat het hoofddoel van de opdracht was. Hier mijn code:
XXXX
"
ChatGPT kan wispelturig zijn. Als test moet je eens onderstaande prompt gebruiken om een voorbeeldoplossing te genereren. Vervolgens voer je zijn oplossing terug in via de voorgaande prompt om je code te evalueren. Ook z'n eigen code zal ChatGPT kritisch bekijken en soms met terechte verbeteringen afkomen.
Gebruik volgende prompt, in dezelfde chat om een voorbeeldoplossing te krijgen:
"
Los deze oefening voor me op in c#. Zonder gebruik te maken van arrays, linq, goto, break op een andere plaats dan een switch, lambdas, events, delegates en object georiënteerdprogrammeren. Plaats bij de code de nodige commentaar. De nadruk ligt op leren werken met methoden. Geef dus aandacht in je commentaar in de uitleg van hoe deze methoden geschreven werden.
"
Maak een paswoord generator die paswoorden van bepaalde lengte genereert en bestaat uit willekeurige letters, hoofdletters en cijfers. Plaats deze code in een methode die 1 parameter aanvaardt namelijk de lengte van het paswoord dat gemaakt moet worden. De methode geeft het gegenereerde paswoord terug als resultaat. (tip gebruik een random number generator(s) om getallen te genereren die je ook kan casten naar chars dankzij de Unicode waarde van chars).
Maak een methode FilmRuntime() die 3 parameters accepteert:
Een string die de naam van de film bevat
Een integer die duur in minuten van de film bevat
Een enum-type die het genre van de film bevat (Drama, Actie, etc.)
Indien de duur van de film niet wordt meegeven wordt een standaard lengte van 90 minuten ingesteld. Indien het genre niet wordt meegeven dan wordt deze default op Onbekend ingesteld.
De methode geeft niets terug maar toont eenvoudigweg de film op het scherm, gevolgd door z’n duur en genre in volgende formaat. Voorbeelduitvoer=
The Matrix (120 minuten, Actie)
Toon aan in je main dat de methode werkt met zowel 1, 2 als 3 parameters. Toon ook aan dat je met named arguments de methode kan aanroepen.
Maak een methode Roulette. De methode aanvaart een double en een int als parameter en geeft een double terug. De int parameter is een optionele parameter die standaard op 10 staat.
De methode zal een casino-simuleren en geeft op het einde de winst (of verlies) van de speler terug. De double die wordt meegegeven is het startkapitaal. De int is het aantal simulaties n. De methode zal n roulette-rondes simuleren en telkens de winst of verlies bijhouden.
Iedere van de n simulaties gebeurt het volgende:
De computer kiest een willekeurig getal tussen 0 en 60. Dit is zogezegd de keuze van de speler bij roulette.
De computer kiest een willekeurig getal tussen 0 en 60. Dit is zogezegd het getal waar de roulette-balletje op belandt.
Indien beide getallen overeenkomen zal het startkapitaal van de speler met 1 verhogen. Indien het getal niet gelijk was wordt er 0.1 van het kapitaal afgehouden.
Finaal geeft de methode terug hoeveel geld er nog overblijft na n simulaties.
Maak een applicatie die aan de gebruiker een startkapitaal vraagt. Vervolgens gebruik je de Roulette methode om aan de speler te tonen hoeveel er van zijn kapitaal zou overblijven als hij:
10 keer het roulette-spel speelt
100 keer
1000 keer
10000 keer
Toon telkens ook hoeveel verlies (of winst) dit is ten opzichte van het startkapitaal. Bij winst wordt dit verschil in groene letters getoond, bij verlies in rode letters.
Tekst die start met ">" is invoer van de gebruiker.
Wat is je startkapitaal?
>1000
Gegeven deze informatie krijg ik volgende resultaten
Als je 10 keer roulette speelt zou je eindkapitaal 999,2 zijn, dat is een verschil van -0,8.
Als je 100 keer roulette speelt zou je eindkapitaal 993,4 zijn, dat is een verschil van -6,6.
Als je 1000 keer roulette speelt zou je eindkapitaal 923,8 zijn, dat is een verschil van -86,2.
Als je 10000 keer roulette speelt zou je eindkapitaal 880,0 zijn, dat is een verschil van -120.
Je bent met doubles aan het werken...Is het je opgevallen dat je soms heel vreemde afrondingen krijgt, of dat 10,0 plots 10,00000003 wordt? Dit komt doordat doubles (net als alle datatypes) maar een bendaring kunnen bewaren , vanwege het aantal bytes dat ze innemen. Dit kan soms leiden tot onverwachte afrondingsfouten. Afhankelijk van de oefening is er in dergelijke gevallen niets mis mee om waar nodig dan manueel af te ronden met Math.Round().
We gaan de prompt uit de vorige week-oefeningen om methode-oefeningen te genereren uitbreiden met de specifieke zaken waar vooral deze week op geoefend moet worden, namelijk: optionele parameters, named parameters en method overloaden. Vergeet XXXX niet te vervangen door je eigen context (of laat het staan als je geen inspiratie hebt)
"
Je bent een lector van een hogeschool die studenten helpt met programmeren. Je bent heel goed in interessante opgaven in C# te ontwikkelen die studenten motiveert om te blijven programmeren.
Verzin een C# oefening voor mij die me doet oefenen op methoden.
Volgende zaken mogen in de oefening aanwezig zijn:variabelen, if else, switch, expressies, de math bibliotheek en loops. De nadruk ligt op het oefenen op methoden. Specifiek wil ik oefenen op optionele parameters, named parameters en method overloaden. Methoden geven maximum 1 element terug. Gebruik dus geen tuples of sets van returntypes bij methoden.
Volgende zaken mogen niet in de oefening aan bod komen: arrays, lists, linq en object georiënteerd programmeren.
Laat de oefening gaan over XXXX.
Toon geen voorbeeldcode of oplossing.
Toon wel voorbeelduitvoer.
Leg ook expliciet uit welke methoden ik moet schrijven en hoe ze werken
Stel ook 3 mogelijke uitbreidingen voor.
"
Je oplossing kan je met deze prompt evalueren:
"Hierna volgt mijn oplossing. Kan je deze evalueren op correctheid, naamgeving, mate van overbodige code, etc., Let op: we mogen geen gebruik maken van van arrays, linq, lambdas, goto, break mag enkel in switch, events, delegates en objectgeoriënteerd programmeren. Geef vooral aandacht aan het gebruik van methoden, specifiek named parameters, method overloading en optionele parameters wat het hoofddoel van de opdracht was. Hier mijn code:
XXXX
"
En zo genereer je een modeloplossing:
"
Los deze oefening voor me op in c#. Zonder gebruik te maken van arrays, linq, goto, break op een andere plaats dan een switch, lambdas, events, delegates en object georiënteerd programmeren. Plaats bij de code de nodige commentaar. De nadruk ligt op leren werken met methoden, specifiek named parameters, method overloading en optionele parameters . Geef dus aandacht in je commentaar in de uitleg van hoe deze methoden geschreven werden.
"
Vul een array van ints met alle getallen van 1 tot 100. Druk de array af.
Vul een array van ints met alle even getallen tot en met 100. Druk de array af.
Vraag aan de gebruiker 3 keer een getal, stop deze in een array, druk deze array af.
Maak een array aan en plaats daarin de 4 namen van je beste vrienden in volgorde van "beste vriend" tot "minst beste vriend". Toon nu de namen op het scherm, onder elkaar, met telkens ervoor "Beste vriend", "Tweede beste vriend", "Derde beste vriend", "Minst beste vriend".
Maak een array van 20 booleans en zorg dat alle oneven indexen False en de even True zijn. Druk vervolgens de array af.
Maak een array van 20 bool-waarden. Deze waarden zijn willekeurig. Print de array. Toon hoeveel keer true en hoeveel keer false er in de array zit. Opgelet, je doet de visualisatie in aparte loop nadat je deze hebt aangemaakt. Voorts tel je de true en false variabelen in nog eens een aparte loop.
Vul een array met 10 random doubles tussen 0 en 10. Toon het gemiddelde ervan.
Maak een enum Schooltype met mogelijke waarden TSO, BSO, ASO, KSO. Maak een array van 20 Schooltype-waarden. Vul deze met willekeurige schooltypes. Toon de array. Toon hoe vaak ieder schooltype in de array voorkomt.
Maak een array die 6 strings kan bevatten. Ieder element van de array bevat een vraag (naar keuze te verzinnen) als string waar de gebruiker met een getal op moet antwoorden. Maak een array aan die tot 6 ints kan bevatten. Lees 1 voor 1 de vraag uit de string-array uit en toon deze op het scherm. Lees vervolgens het antwoord uit dat de gebruiker intypt en bewaar dit als int in de 2e array.
Na de 6 vragen toon je vervolgens de vragen opnieuw met achter iedere vraag het antwoord van de gebruiker.
Maak een programma voor een koeriersbedrijf. Maak een array die 10 postcodes bevat (zelf te kiezen) van gemeenten waar het bedrijf naar levert. Maak een tweede array die de prijs bevat per kg voor iedere respectievelijke gemeente. Het eerste element van deze array bevat dus de prijs/kg om naar de gemeente te leveren die als eerste in de array met postcodes staat.
Vraag aan de gebruiker een postcode en het gewicht van het pakket. Vervolgens wordt de prijs/kg opgezocht voor die gemeente en wordt de prijs berekend, gegeven het ingegeven gewicht.
Indien het bedrijf niet levert aan de ingetypte postcode dan wordt een foutmelding weergegeven.
Geef gewicht pakket
_45
Naar welke postcode wenst u dit pakket te versturen?
_2020
Dit zal 9630 euro kosten.
Bob is a lackadaisical teenager. In conversation, his responses are very limited. Bob answers 'Sure.' if you ask him a question. He answers 'Whoa, chill out!' if you yell at him. He answers 'Calm down, I know what I'm doing!' if you yell a question at him. He says 'Fine. Be that way!' if you address him without actually saying anything. He answers 'Whatever.' to anything else."
Bekijk steeds de laatste 2 tekens die de gebruiker invoert om de response van Bob te bepalen.
Kan je een gesofisticeerdere bot maken?
{% hint style="info" %}
myInputstring.Contains(somestring) geeft een bool terug indien somestring voorkomt in de variabele myInputstring van het type string.
Maak een programma dat eerst aan de gebruiker 10 waarden vraagt die in een array worden gezet.
Vervolgens vraagt het programma welke waarde verwijderd moet worden. Wanneer de gebruiker hierop antwoordt met een nieuwe waarde dan zal deze nieuw ingevoerde waarde in de array gezocht worden. Indien deze gevonden wordt dan wordt deze waarde uit de array verwijderd en worden alle waarden die erachter komen met een plaatsje naar links opgeschoven, zodat achteraan de array terug een lege plek komt.
Deze laatste plek krijgt de waarde -1.
Toon vervolgens alle waarden van de array.
Indien de te zoeken waarde meer dan 1 keer voorkomt, wordt enkel de eerst gevonden waarde verwijderd.
De hamming distance is het aantal tekens dat twee reeksen verschillen indien we ieder element vergelijken op dezelfde plaats in de andere reeks.
Maak een programma dat aan de gebruiker vraagt om twee DNA strings in te voeren (een reeks bestaande uit de letters G, A, C & T). Beide reeksen moeten even lang zijn.
Bereken de hamming distance tussen beide reeksen.
De hamming distance van volgende twee DNA strings is 7, omdat er 7 elementen in beide strings staan die niet gelijk zijn aan mekaar op dezelfde plek (aangeduid met ^).
Ontwerp een consoletoepassing waarmee je een wachtwoord genereert voor een gebruiker. Het wachtwoord is opgebouwd uit:
de 2 eerste letters van de familienaam: de 1ste letter is een hoofdletter, de 2de letter is een kleine letter. Daarna worden de 2 letters gewisseld; het zonenummer van het telefoonnummer zonder de 0; het eerste cijfer van de postcode in het kwadraat.
Gebruik de ToCharArray() methode die je op een string kunt toepassen, zoals hier getoond: char[] chars = myEpicName.ToCharArray();
{% hint style="warning" %}
Schrijf nooit een paswoord manager die je paswoorden gortdroog als string bewaart. Secure code schrijven is een hele discipline op zich en laat je best nog even links liggen tot je C# goed in de vingers hebt.
Sommige oefeningen zijn op randje van PRO. U weze gewaarschuwd.
{% hint style="info" %}
Je mag in deze oefeningen NIET gebruik maken van .Reverse(), .BinarySearch() etc. Alles moet je manueel kunnen. Enkel sorteren mag je automatisch doen met .Sort().
Als er dus staat "lees 20 getallen in", dan moet je die in volgorde bewaren in je array. Vervolgens begin je die array te manipuleren.
Er worden 20 getallen ingelezen. De getallen worden in omgekeerde volgorde afgedrukt.
Er worden 20 getallen ingelezen. De getallen worden 1 plaats naar voor verschoven afgedrukt, d.w.z. eerst het tweede ingelezen getal, dan het derde ingelezen getal, dan het vierde ingelezen getal , ... , dan het laatste ingelezen getal en tenslotte het eerste ingelezen getal.
Er worden 20 getallen ingelezen. De getallen worden 3 plaatsen naar achter verschoven afgedrukt, d.w.z. eerst het derde laatste ingelezen getal, dan het voorlaatste ingelezen getal, dan het laatste ingelezen getal, dan het eerste ingelezen getal, dan het tweede ingelezen getal en tenslotte het vierde laatste ingelezen getal.
Er worden 20 getallen ingelezen. De getallen worden geroteerd (verschoven) afgedrukt over een aantal elementen x zoals in de vorige opgave. Maak dus de vorige oefening maar nu is 3 een variabele die je op voorhand kan instellen.
[Pro] Een rij van 100 getallen wordt ingelezen. Druk de inhoud van de rij af in 3 kolommen. De getallen worden gerangschikt rij per rij. Als je input bijvoorbeeld volgende reeks getallen is: 4 5 8 7 5 2 6 8 7 1 3 2, dan wordt dit je output:
4 5 8
2 5 7
6 7 8
1 2 3
[Pro] Een rij van 100 getallen wordt ingelezen. Druk de inhoud van de rij af in 3 kolommen. De getallen worden gerangschikt kolom per kolom (hier mag je Sort gebruiken).
{% hint style="info" %}
Voor de volgende oefeningen dien je telkens zelf te bepalen welke methoden (met bijhorende parameters en return types) nodig zijn om tot een gestructureerde oplossing te komen.
Ontwikkel een applicatie die parkeerkosten berekent. De applicatie moet eerst vragen hoeveel auto's er verwerkt moeten worden, en vervolgens per auto de parkeerduur opvragen.
Tarieven: Het basistarief bedraagt € 2,00 voor een parkeerduur tot en met 3 uur. Indien er langer geparkeerd wordt, wordt er na deze 3 uur een supplement aangerekend van € 0,50 per begonnen uur. De maximale dagprijs is begrensd op € 10,00. Je mag ervan uitgaan dat een auto nooit langer dan 24 uur parkeert.
Technische vereisten:
Zorg voor een indeling in logische methodes. Denk bijvoorbeeld aan een methode die de kosten berekent voor één specifieke parkeerbeurt.
Het eindresultaat moet een overzichtstabel zijn die per auto de duur en de kostprijs toont, gevolgd door een totaalbedrag.
Implementeer het Caesar-algoritme om tekst te versleutelen en te ontcijferen.
Algoritme: Bij dit systeem wordt elke letter in de tekst vervangen door een letter die een vast aantal plaatsen verderop in het alfabet staat. Wanneer het einde van het alfabet bereikt wordt, telt men verder vanaf 'A' (cyclische verschuiving). Bijvoorbeeld: bij een verschuiving van 3 wordt 'A' een 'D', 'B' een 'E', enzovoort. 'Z' wordt in dit geval 'C'.
Formule: Gebruik de formule: nieuweIndex = (oudeIndex + sleutel) % 26 (waarbij A=0, B=1, ...).
Opdracht: Schrijf een programma dat de gebruiker om een tekst en een sleutel (verschuiving) vraagt. Het programma moet in staat zijn om de tekst te versleutelen en nadien de versleutelde tekst weer correct te ontsleutelen. Je oplossing moet gebruik maken van arrays van karakters (char[]) voor de interne verwerking.
Schrijf een validatie-methode voor Belgische ondernemingsnummers.
Een ondernemingsnummer (formaat: BE 0xxx.xxx.xxx) is geldig als het voldoet aan volgende controle: Wanneer men de eerste 7 cijfers (na de '0') als één getal beschouwt, en men berekent de rest bij deling door 97, dan moet 97 min deze rest gelijk zijn aan de laatste 2 cijfers van het nummer.
Vereiste: De methode accepteert het nummer als string (inclusief "BE", spaties en punten) en geeft aan of dit geldig is of niet.
Analyseer onderstaande problemen en implementeer de oplossingen. Let goed op het onderscheid tussen het aanmaken van een nieuwe array en het aanpassen van een bestaande array.
Omkeren (Nieuw): Lees getallen in en produceer een nieuwe array met de elementen in omgekeerde volgorde.
Omkeren (Mutatie): Keer de volgorde van de elementen om in de array zelf (in-place).
Verschuiven (Mutatie): Roteer de inhoud van de array 1 positie naar links. Het eerste element verhuist naar de laatste positie.
Verschuiven (Nieuw): Idem als bovenstaande, maar het resultaat komt in een nieuwe array; de originele blijft ongewijzigd.
Verschuiven met X (Nieuw): Roteer de elementen 3 posities naar links in een nieuwe array.
Verschuiven met X (Mutatie): Roteer de elementen 3 posities naar links in de array zelf.
Uniek (Nieuw): Filter een array zodat alle dubbele waarden verwijderd zijn.
Uniek en Gesorteerd (Nieuw): Filter een array die reeds gesorteerd is, zodat dubbels verwijderd zijn. Omdat de lijst gesorteerd is, staan gelijke waarden naast elkaar. Je hoeft dus enkel elk element met het vorige element te vergelijken.
Analyse Max: Bepaal het maximum van een reeks getallen, hoe vaak dit voorkomt, en de index van de eerste keer dat dit maximum voorkomt.
Analyse Min: Bepaal het minimum, hoe vaak dit voorkomt, en de index van de laatste keer dat dit minimum voorkomt.
Aantal Verschillende: Tel hoeveel unieke getallen er voorkomen in een reeks.
[PRO] Zeef van Eratosthenes: Genereer alle priemgetallen kleiner dan 100.000.
Maak een lijst van alle getallen van 2 tot 100.000 (initieel allemaal "mogelijk priem").
Begin bij 2: streep alle veelvouden van 2 weg (behalve 2 zelf).
Ga naar het volgende niet-weggestreepte getal (3) en streep alle veelvouden weg.
Programmeer een module om de determinant van een matrix te berekenen.
Opdracht: Begin met ondersteuning voor een 2x2 matrix. De determinant van een matrix [[a, b], [c, d]] bereken je als (a * d) - (b * c) (kruisproduct). Zorg ervoor dat je oplossing gebruik maakt van meerdimensionale arrays ([,]).
Uitbreidbaarheid: Denk na over hoe je de code zou structureren om later ook 3x3 matrices te ondersteunen.
Test data: Voor matrix $\begin{pmatrix} 2 & 4 \ 3 & 5 \end{pmatrix}$ is het resultaat -2.
Implementeer het matrixproduct van twee matrices $A$ en $B$. Zorg voor een correcte controle op de dimensies (aantal kolommen van A moet gelijk zijn aan aantal rijen van B).
Een team wenst statistische analyse uit te voeren op de prestaties van hun spelers (rugnummers 1 t.e.m. 12). Er moeten twee types acties bijgehouden worden: positieve en negatieve. Opdracht: Schrijf een programma dat interactief data kan invoeren. De gebruiker geeft een rugnummer en het type actie in (gebruik 'P' voor positief, 'N' voor negatief), gevolgd door het aantal keer dat deze actie voorkwam. De gebruiker bepaalt zelf wanneer de invoer stopt.
Na afloop toont het programma een rapport met:
Per speler: aantal positieve acties, negatieve acties en het netto resultaat (positief - negatief).
Een aanduiding van de meest en minst performante speler(s).
Een typische invoer kan dus zijn:
2
P
6
De coach kiest dus de speler met rugnummer 2, kiest voor een positieve actie ('P'), en voert 6 in als aantal.
In de array op index 1 (rugnummer -1) zal in de 0'de kolom (0 = positieve, 1 = negatieve) het getal 6 geplaatst worden.
Vervolgens kan de coach een ander rugnummer (of hetzelfde) invoeren en zo verder.
Wanneer de coach 99 invoert stopt het programma en worden de finale statistieken getoond
Schrijf een methode die de som berekent van een willekeurige hoeveelheid integers. De methode moet zo ontworpen zijn dat ze kan aangeroepen worden met eender welk aantal argumenten (bv. Som(1, 2) maar ook Som(1, 2, 3, 4, 5)).
Onderzoek welke C# language feature hiervoor gebruikt kan worden.
De discotheek "Damsing Van Camp" heeft jouw diensten ingehuurd om een Covidsafe tracker te ontwikkelen. Ze willen op deze manier potentiële uitbraken in de wachtrij detecteren voor de contactracers.
De tool wordt gebruikt door het personeel van het onthaal aan de kassa die het volgende zal doen:
Ze zal met een andere app het covid safe ticket scannen.
Fase 1: Vervolgens start ze jouw tool en voert in:
De naam van de gescande persoon.
Of deze persoon wel of niet werd toegelaten.
Fase 2: De volgende dag kan de manager van de discotheek (de wereldberoemde Vinny Timzo) de resultaten van de app raadplegen en de nodige statistieken genereren die hij dan aan de contacttracers kan doorgeven.
Fase 3: Beslissen of het programma nog eens moet uitgevoerd worden of niet.
2 arrays worden aangemaakt van lengte 100. Vul de namenarray met de string leeg in ieder element, zo kan je verderop makkelijker tellen.
Het programma start met een loop die zich blijft herhalen tot de gebruiker "stop" invoert als naam. In de loop gebeurt het volgende:
Een zinnetje toont Voer de naam in van persoon x waarbij de x vervangen door een getal dat aangeeft de hoeveelste persoon nu komt (begint bij 1 en wordt telkens met 1 verhoogd).
De gebruiker voert de naam in (indien hier stop wordt ingevoerd stopt de verdere werking van de loop).
Deze naam wordt bewaard in een array (type string).
Een zinnetje toont Werd deze persoon toegelaten (j/n)?.
De gebruiker moet j of n (ja of nee) invoeren. Enkel dan wordt er naar de volgende stap gegaan, anders wordt naar stap 4 gegaan.
Het antwoord (j of n) wordt in een array van het type bool bewaard.
Een zinnetje toont De persoon met naam X werd ingevoerd. Hij werd Y. waarbij X de ingevoerde naam is en Y ofwel toegelaten of niet toegelaten afhankelijk van de invoer bij stap 5.
Na de loop worden de statistieken getoond zoals uitgelegd in de volgende sectie (Fase 2)
Voorbeelduitvoer fase 1a (de namen en j of n werden door gebruiker ingevoerd):
Voer de naam in van persoon 1
tim
Werd deze persoon toegelaten (j/n)?
n
De persoon met naam tim werd ingevoerd. Hij werd niet toegelaten.
Voer de naam in van persoon 2
jos
Werd deze persoon toegelaten (j/n)?
j
De persoon met naam jos werd ingevoerd. Hij werd toegelaten.
Voer de naam in van persoon 3
anna
Werd deze persoon toegelaten (j/n)?
Wat?
Werd deze persoon toegelaten (j/n)?
j
De persoon met naam anna werd ingevoerd. Hij werd toegelaten.
Voer de naam in van persoon 4
stop
Er wordt een methode ToonTracerRapport aangeroepen. Aan deze methode geef je de 2 arrays mee.
Gebaseerd op het percentage niet toegelaten personen wordt een risico berekend: onder de 35% is Laag, tussen de 35% en 75% Verhoogd en boven 75% Kritiek. Het risico is gebaseerd op de verhouding tussen het aantal ingevoerde personen en degene die daarvan niet zijn toegelaten. Als er dus 10 personen in totaal werden ingevoerd en daarvan waren er 4 niet toegelaten, dan is het risico 40% (4 van de 10).
Deze grenswaarden kunnen na initialisatie niet meer aangepast worden.
Gebruik een enum type om het risico te bewaren.
Deze methode zal vervolgens een samenvatting van de ingevoerde data uitvoeren, als volgt (fictieve data):
Aantal ingevoerde personen = 24
Daarvan werden 3 personen niet toegelaten, dat is 12,5%.
Risico: laag
Volgende personen werden niet toegelaten:
- Franky Vermeulen
- Raphael Palinsky
- Freya Versavel
Vervolgens vraagt het programma aan de gebruiker of de gebruikersnamen anoniem moeten gemaakt worden. De gebruiker antwoordt met j of n. Bij neen wordt deze fase overgeslagen en wordt er naar fase 2c gegaan. Bij j gebeurt het volgende:
Een methode MaakAnoniem wordt aangeroepen. Aan deze methode geef je de 2 arrays mee.
Kopieer de naam-array naar een nieuwe array van string. Vervang de naam van ieder persoon in deze nieuwe array door ***** indien deze persoon niet werd toegelaten (het aantal sterretjes is altijd even lang). De methode geeft een nieuwe array terug waarin de aangepaste namen staan.
De plekken in de array waar geen namen stonden worden niet door sterretjes vervangen én ook niet getoond.
Wanneer de methode terugkeert bewaar je het resultaat van deze methode (de naam array) in een nieuwe variabele.
Roep nu terug het ToonTracerRapport aan met deze nieuwe array. Het resultaat zou moeten zijn:
Aantal ingevoerde personen = 24
Daarvan werden 3 personen niet toegelaten, dat is 12,5%.
Risico: laag
Volgende personen werden niet toegelaten:
- *****
- *****
- *****
Het programma vraagt of er moet afgesloten worden of niet (j/n). Bij neen worden alle arrays leegemaakt en wordt er terug naar fase 1 gegaan en begint alles van voor af aan.
Volgende opgave was de vaardigheidsproefopdracht voor examen van dit vak (Programming Principles) in januari 2018
Oh jeetje, de wereld draait nu helemaal door. Jouw firma werd zonet gevraagd om een online casino te ontwerpen met als doelgroep babies. Voor ze je de effectieve site laten maken willen ze eerst een simulatie zien in console. Aan jou de eer om deze om deze dubieuze opdracht tot een goed einde te brengen.
De speler wordt telkens gevraagd welk van de 3 spellen hij wenst te spelen. Hij kan ten allen tijde stoppen en krijgt dan te zien hoeveel het verlies of de winst is.
De applicatie is modulair opgebouwd door middel van methoden.
Opgelet, bekijk zeker de puntenverdeling om te bepalen wat je eerst doet:
Je kan deze opgave in willekeurige volgorde oplossen, daar alle delen modulair en onafhankelijk van mekaar zijn:
Roep de methode aan vanuit de main met een naam, lengte en breedte naar keuze.
Enkel indien de methode true geeft zal het programma verder gaan, anders sluit het programma zich hier af.
Deze 3 methoden bevatten telkens 1 spel. Als het spel gedaan is geeft de methode telkens terug hoeveel winst (of negatieve winst) de speler heeft gemaakt.
De speler moet raden welk getal van 0 tot en met 10 de computer in gedachte heeft. Voor hij dit doet moet hij eerst ingeven hoe vaak hij denkt te moeten raden.
Indien de gebruiker exact wist hoevaak hij moest raden voor hij het getal zou vinden, dan krijgt hij +50.
Indien het aantal keer raden maximum 2 verwijderd is van hoe vaak hij dacht nodig te hebben, dan krijgt hij +5.
Stel dat hij aan de start 5 ingaf als aantal pogingen, dan zal hij 5 euro krijgen indien hij het uiteindelijk effectief in 3,4,6 of 7 pogingen het heeft geraden (en uiteraard 50 indien hij het in 5 keer raadde)
Welkom bij raad het getal!
Je moet een getal van 1 tot 10 raden. Hoe veel keer denk je nodig te hebben?
4 <= ingevoerd door gebruiker
Hier gaan we dan.
Welk getal is het (aantalpogingen is 0)?
1 <= ingevoerd door gebruiker
Neen, dat is het niet. Probeer opnieuw
Welk getal is het (aantalpogingen is 1)?
2 <= ingevoerd door gebruiker
Neen, dat is het niet. Probeer opnieuw
Welk getal is het (aantalpogingen is 2)?
3 <= ingevoerd door gebruiker
Jeuj. Je hebt het geraden!
Je zat er minder dan 3 af van het aantal keer dat je ging raden. Je verdient 5 euro.
Je krijgt nu 5 reken oefeningen. Per juiste krijg je 5 euro. Per foute verlies je 5 euro.
Hoeveel is 4x9?
36 <= ingevoerd door gebruiker
Mooi zo! Je winst verhoogt.
Hoeveel is 6x4?
20 <= ingevoerd door gebruiker
Dat is fout. Je winst verlaagt
Hoeveel is 7x7?
49 <= ingevoerd door gebruiker
Mooi zo! Je winst verhoogt.
Hoeveel is 8x1?
8 <= ingevoerd door gebruiker
Mooi zo! Je winst verhoogt.
Hoeveel is 9x1?
10 <= ingevoerd door gebruiker
Dat is fout. Je winst verlaagt
Je totale winst dit spel is 5
Druk toets om verder te gaan
Bij de start van deze methode wordt een array van bool, met lengte 10, gevuld met willekeurige true en false waarden.
De gebruiker moet proberen zo ver mogelijk door de array te geraken door te raden of de volgende waarde in de array true of false is. Van zodra de speler fout gokt stopt dit spel.
Hoe verder de speler geraakt, hoe meer winst (er kan geen verlies gemaakt worden).
Er wordt op het einde ook getoond wat de volledige sequentie was
Hoe lang kan jij de sequentie raden?Geef 0 (false) of 1 (true) in.
Komt er juist of fout? (1 of 0)
1 <= ingevoerd door gebruiker
Goed zo!
Komt er juist of fout? (1 of 0)
1 <= ingevoerd door gebruiker
Goed zo!
Komt er juist of fout? (1 of 0)
0 <= ingevoerd door gebruiker
Fout
Je behaalde een sequentie van 2 juiste gokken. Dat is 10 euro waard.
De correcte sequentie was:
True,True,True,True,True,True,True,False,True,False,
De verkiezingen komen er aan in Nederland. Jouw bedrijf werd ingeroepen om een applicatie te maken die de burger kan gebruiken om te ontdekken op welke partij hij het best kan stemmen. Je gaat dus een zogenaamde stemwijzer maken.
Het programma bestaat uit een loop die telkens uit volgende stappen bestaat:
Fase 1: Identificatie: vragen wie de gebruiker is en op welke partij hij vorig jaar stemde mbv VraagDetails-methode.
Fase 2: Stemwijzer starten: de gebruiker doorloopt enkele vragen om te zien op welke partij hij. Met behulp van de StemWijzer-methode.
Fase 3: Statistieken tonen: gebaseerd op de stemwijzer resultaten van de vorige fase wordt getoond hoe het resultaat zich verhoud tegenover de resultaten van iedereen die de test reeds heeft afgelegd. Met behulp van de ToonStatistieken-methode.
Iedere fase (1,2&3) bestaat uit een methode die vanuit deze fase 0 wordt opgeroepen. De fase 0 loop stopt nooit.
Twee arrays houden volgende informatie bij en worden aangevuld naarmate de informatie beschikbaar is:
Naamarray: 1 array houdt de naam van iedere persoon die de tool heeft gebruikt
Resultaatarray: 1 array houdt het stemresultaat uit fase 2 van de persoon bij
Beide array werken dus synchroon: op dezelfde index staat steeds de naam en stemresultaat van 1 persoon.[kies zelf of je arrays of lists gebruikt]
Maak een methode “VraagDetails”. Deze methode vereist 2 parameters:
namelijk de array met de namen uit fase 0 (naamarray).
De kleur (ConsoleColor) waarin de boodschap in de methode moet getoond worden op het scherm. De standaardkleur is Red.
De methode vraagt de naam van de gebruiker (in de kleur die werd meegegeven) en voegt die aan de array toe op de eerste lege plek.
Indien de naam reeds voorkomt in de array verschijnt er een foutboodschap en wordt de naam opnieuw gevraagd. Dit blijft gevraagd worden tot de gebruiker een geldige naam (of "admin") invoert
De methode geeft een bool terug als volgt:
True indien de gebruiker de naam "admin" heeft ingegeven
Maak een methode “Stemwijzer”, deze methode vereist 2 parameters van het type bool en ConsoleColor. De Methode geeft een string terug als resultaat.
De eerste parameter die je moet meegeven is een bool die aangeeft of het om een admin gaat of niet. De standaard waarde van deze parameter is false (zie fase 2.3 ivm het gebruik van deze parameter).
De tweede parameter is wederom de kleur waarmee de tekst in de methode zal getoond worden.
Wanneer de methode opstart wordt er een reeks vragen gesteld. Afhankelijk van het vorige antwoord krijg je andere vragen. Je dient volgende beslissingsboom in te voeren, startende aan de linkerkant:
De eerste vraag zal dus zijn “Vrije sluitingstijden in de horeca”. De volgende vraag zal zijn Extra evenementen?” als bij de vorige vraag “neen” werd geantwoord, anders is de volgende vraag “Politie moet harder optreden”
De gebruiker mag enkel “ja” of “nee” antwoorden.
Je houdt bij hoe vaak de gebruiker ja heeft geantwoord, en hoe vaak er nee werd geantwoord. [x] en [y]
Indien de gebruiker een niet geldige invoer geeft dan zal de vraag opnieuw gesteld worden tot hij correct (ja,nee) invoert.
Het scherm wordt na de vragen leeggemaakt en in het midden van het consolescherm komt de tekst: De partij waar je best op stemt is [uitgekomen partij] je hebt hiervoor [x] keer ja geantwoord en [y] keer nee
De methode geeft vervolgens de partij als string terug waar de stemwijzer is op uitgekomen.
Enkel indien de gebruiker géén admin is (wat je hebt teruggekregen via de bool in van VraagDetails() methode wordt vervolgens z’n stemresultaat bewaard in de array 2: Dit resultaat wordt in de 2e array van fase 0 bewaard op de respectievelijke index waar ook de naam van de huidige gebruiker in de andere array staat.
Als laatste fase wordt een methode ToonStatistieken aangeroepen. Deze methode verwacht twee arrays. De eerste array bevat namen (string), de andere de stemresultaten (string of enum als je de volgende fase ook maakt).
De methode gebruikt de 2 arrays om enkele interessante statistieken te tonen:
Het toont het percentage dat partijen vertegenwoordigd zijn. Als dus de array bestaat uit vvd,d66,vvd. Dan zal vvd 66% vertegenwoordigen, d66 33%
Je toont ook het aantal keer dat iedere partij voorkwam aan de hand van een lijn bestaande uit zoveel sterren. Als vvd 5 stemmen kreeg, d66 3 en bas 6 dan toont de methode dit als volgt:
vvd ******
d66 ***
bas *****
Het toont de gemiddelde lengte van de gebruiker. Als de namen bestaan uit Tim,Jos,Frederik, Frans dan is dit gemiddelde 4,75 letters
Het geeft een overzicht van alle stemresultaten maar toont enkel de eerste letter van iedere naam. Als bijvoorbeeld Tom op d66 uitkwam, Gerolf op vvd en Frans op bas dan verschijnt er:
Gebruik een enum type om de partijen voor te stellen in je code en vervang ook de array door een array die die enums kan bevatten in plaats van strings voor de partijen.
Een firma die huisverkopers opleidt heeft je gevraagd om een trainingspakket te maken. Het pakket moet de trainees in staat stellen om te oefenen op het zo goed mogelijk kopen van huizen die op de markt verschijnen.
Er zijn twee gebruikers:
De trainer: degene die het programma instelt aan de start
De trainee: de persoon die de opleiding volgt en dus de training doet.
Er hoeft geen rekening gehouden te worden met foute invoer van de gebruiker. De gebruiker voert enkel zaken in die toegestaan zijn.
Fase 1 (4punten): De trainer stelt de moeilijkheidsgraad in van het programma zodat het startbudget kan berekend worden
Fase 2 (8 punten): De trainee krijgt huizen aangeboden (willekeurig) waar hij op kan bieden. Van zodra het budget op is wordt naar de volgende fase doorgegaan.
Fase 3 (4 punten): De trainer én trainee krijgen te zien hoe goed de trainee het heeft gedaan
Achteraan is ook een aanvullende-opgave (2 punten waard) waar je eventueel al van bij de start rekening mee kunt houden.
De moeilijkheidsgraad wordt gevraagd (een getal van 1 tot en met 9, hierop moet géén foutcontrole gebeuren).
Er wordt gevraagd of de trainee een bonus krijgt (j of n) en dit wordt als bool bewaard.
Een methode “BudgetGenerator” wordt aangeroepen. Deze zal een budget teruggeven dat je bewaard in het hoofdprogramma en nodig hebt in de volgende fasen.
Voorbeeld output
Geef moeilijkheidsgraad in (een getal van 1 tot en met 9)
5 <-input user
Krijg de trainee een startbonus? [j/n]
j <-input user
Je startbudget is 4500
Een loop wordt gestart, zolang de trainee budget heeft krijgt hij steeds een nieuw huis te zien dat hij kan kopen. Wanneer er 20 huizen getoond stopt de loop ook, ongeacht of de gebruiker nog budget over had of niet.
De loop:
Het huidige budget wordt steeds opnieuw getoond
De prijs van een nieuw huis wordt gegenereerd in een methode “HuisPrijs”, de methode toont ook wat het huis heeft (qua kamers en terras)
De te betalen prijs wordt getoond.
De trainer kan beslissen om het huis te kopen of niet
Wanneer de trainee een huis koopt zal zijn budget verminderd worden met de prijs van het huidige huis.
De gebruiker moet hiervoor j of n antwoorden op de vraag of hij dit huis wenst te kopen
Er wordt bijgehouden welke huizen de trainee wel én niet kocht alsook de prijs van ieder huis. Dit wordt in 2 arrays bewaard:
1 array (double) zal de prijzen van ieder gegenereerd huis bijhouden
1 array (bool) zal bijhouden of de gebruiker het huis wel of niet kocht
*****
Huis met 2 slaapkamers en geen terras: 1240 euro
Je budget is nu 4500
-----------------
Wil je dit huis kopen? Het kost 1240 euro. [j/n]
n <-input user
*****
Huis met 3 slaapkamers en met terras: 1810 euro
Je budget is nu 4500
-----------------
Wil je dit huis kopen? Het kost 1810 euro. [j/n]
j <-input user
*****
Huis met 2 slaapkamers en geen terras: 1240 euro
Je budget is nu 2690
-----------------
Wil je dit huis kopen? Het kost 1240 euro. [j/n]
j <-input user
*****
Huis met 1 slaapkamers en geen terras: 1120 euro
Je budget is nu 1450
-----------------
Wil je dit huis kopen? Het kost 1120 euro. [j/n]
In deze fase wordt een overzicht getoond van de gekochte én niet gekochte huizen. Gebruik hiervoor de twee arrays waarin je die informatie bijhield. Je toont telkens de prijs van het huis alsook of deze wel of niet werd gekocht.
Na het overzicht wordt de gemiddelde prijs van de aangekochte huizen getoond m.b.v. een methode BerekenGemiddelde. Deze methode zal het gemiddelde berekenen en in het hoofdprogramma wordt deze dan in een zin getoond (zie voorbeeld output)
Voorbeeld output
Huis met prijs 1240 euro heb je gekocht
Huis met prijs 1690 euro heb je niet gekocht
Huis met prijs 1120 euro heb je gekocht
Huis met prijs 1810 euro heb je niet gekocht
Huis met prijs 1810 euro heb je niet gekocht
Huis met prijs 1810 euro heb je gekocht
Huis met prijs 1120 euro heb je gekocht
Je spendeerde gemiddelde 1322,5 euro aan een huis
Iedere fase (3 in totaal) wordt in een aparte methode geplaatst. In de main-methode mogen enkel deze 3 methode-fasen staan alsook eventuele variabelen die je nodig hebt om data tussen de methoden uit te wisselen.
Dit nooit meer. Tijdens een examen Java ging plots het brandalarm af. Alhoewel dit terecht was, heeft de PAP Hogeschool ons gevraagd om een verbeterde alarminstallatie te maken. De nieuwe installatie moet een beter logbook tonen en bijhouden van de echte en valse alarmen.
Het programma zal gedurende maximum 10 jaren steeds de 52 weken van een jaar doorlopen. Het programma zal iedere 10e week een testalarm starten. Doorheen het jaar zullen ook echte alarmen plaatsvinden. Aan het einde van ieder jaar wordt het jaar gevisualiseerd (in welke weken een test, niets of echt alarm plaatsvond) Al deze zaken worden in een log bijgehouden zodat op het einde van het programma kan gekeken worden hoeveel percentage echte alarmen hebben plaatsgevonden. Dit blijft zich herhalen tot er 10 jaar zijn gepasseerd of wanneer de gebruiker op n heeft gedrukt.
Deze zal maximum 10x doorlopen worden. Deze kan onderbroken worden wanneer de gebruiker na 1x jaar “n” antwoord op de vraag of er nog een jaar moet gestart worden.
Indien de gebruiker “n” heeft geantwoord sluit deze loop af en wordt het eindverslag getoond (zie verder)
Binnenin de hoofdloop wordt telkens een weekloop gestart. Deze zal steeds 52 keren herhalen (1 jaar bestaat uit 52 weken):
In de weken 1,11,21,31,41 en 51 wordt steeds een testalarm gestart. In deze weken wordt de methode “TestAlarm” aangeroepen (zie verder).
In de andere weken is er 25% kans dat er alarm afgaat. In die weken wordt een methode “StartAlarmGebouw” (zie verder) aangeroepen.
Het alarm gaat in een van de 3 willekeurige gebouwen door (=eerste parameter). De kans is per gebouw even groot.
Via de tweede parameter wordt aangegeven dat het niét om een test gaat
Een array die 52 elementen kan bevatten (type int, of enum (zie verder) ) houdt bij per week of er geen (=0), een testalarm (=1) of een echt alarm (=2) is afgegaan. Deze array is het weeklogbook
In de hoofdloop nadat 1 jaar werd doorgelopen (dus 52 weken in de weekloop):
wordt het weeklogbook getoond via de “ToonLogbook” methode (zie verder), het weeklogbook wordt als parameter meegegeven.
Voorts wordt het jaarlijks gemiddelde echte alarmen berekend via de methode “BerekenSommen” (zie verder) ,het jaarlogbook wordt als parameter meegegeven.Het resultaat van dit jaarlijkse gemiddelde wordt in een array (type double) bijgehouden), de jaarlogbook.
een jaaroverzicht, bestaande uit weeklogboek en berekening jaarlijks gemiddelde dat aan de array van alle jaren wordt toegevoegd,. Wanneer de hoofdloop afsluit wordt een vervolgens een overzicht van de voorbije jaren getoond (het eindverslag)
Indien je besluit om de weeklogbook met een enumtype ipv int voor te stellen kan je 2 extra punten verdienen. Uiteraard dien je hiervoor ook sommige methode en en code aan te passen om dit werkende te krijgen.
Deze methode geeft niets terug en heeft geen parameters nodig. De methode zal het alarm in een willekeurig gebouw laten afgaan als volgt.
De methode roept de StartAlarmGebouw methode aan, waarbij via de bool wordt aangegeven dat het om een test gaat. Voorts wordt er een willekeurig gebouw meegegeven:
Deze methode zal de meegeven array (het logbook) visualiseren door telkens een weekgetal te tonen en de juist kleur, als volgt:
De weken zijn genummerd van 1 tot en met 9 en herhalen zich dan
De weken zonder alarm zijn blauw, de testalarmen zijn groen, de echte alarmen zijn rood
Enkele voorbeelden:
Daar de testen altijd op zelfde momenten plaatsvinden (week 1,11,21, etc.) zullen de groene blokjes steeds op zelfde plek staan (namelijk 1,2,3,4,5 en 6).
De bewaarde gemiddelde in de jaarlogbook array worden in deze fase getoond tot 2 cijfers na de komma. Wanneer een gemiddelde lager dan 10% was zal deze in een groene kleur getoond worden.
Voor ieder gemiddelde verschijnt het jaarnummer, vanaf 1 te tellen.
Volgende opgave was de vaardigheidsproefopdracht voor examen van dit vak (Programming Principles) in januari 2020
De geheime diensten hebben je hulp ingeroepen. De laatste weken onderscheppen ze vreemde signalen uit de lucht en ze hebben software nodig om deze signalen te analyseren. Jouw opdracht bestaat er uit een tool te ontwikkelen die de geheime diensten zal vertellen wanneer een signaal verdacht is of niet.
De signalen die onderschept worden bestaan steeds uit een willekeurige reeks hoofdletters van A tot en met Z. Ze zijn steeds 100 karakters lang.
Een voorbeeld van zo’n signaal:
BAMKHVSSJDUHCDGDQWQXYSXPVHOMRALPNNAKIRHVBEQWQOFDMQFKQLAIDXPAHGBJSEUPCWUYOVVTBBZGCKZBVBYCNSHLCHNUDHDL
Maak een methode (genaamd MaakSignaal) die geen parameters aanvaardt en een array van chars teruggeeft:
De methode genereert een random array met lengte 100 die de eigenschappen heeft van het signaal hierboven in de kader beschreven.
(Denk eraan: “Een methode mag enkel datgene doen, wat de identifier van de methode laat vermoeden. Dus een signaal maken en NIET afdrukken”)
Roep deze methode aan bij de start van je applicatie. De array (we zullen deze code noemen) die je terugkrijgt zal je vervolgens gebruiken in de volgende delen
NeedsColor: deze methode geeft een bool terug en aanvaardt 1 parameter van het type char. De methode geeft enkel true terug indien de parameter een X,Y,Z of Q karakter is.
WriteCharInRed: deze methode geeft niets terug en aanvaardt 1 parameter van het type char. De methode zal de meegegeven parameter in het rood op het scherm tonen (m.b.v Write) op de huidige plaats van de cursor, en vervolgens de kleur terug resetten.
Het aantal keer dat de speciale tekens X,Y,Z en Q voorkomen bepaalt hoe verdacht het signaal juist is. Enkel indien de verdachte tekens in totaal een veelvoud van 3 zijn is het signaal interessant om op te volgen. Een bericht zonder verdachte tekens is niet verdacht.
Maak een methode (genaamd AnalyseerCode) die 1 parameter van het type char-array aanvaardt en niets teruggeeft:
De methode zal de methode CountSpecials aanroepen (zie verder) om te weten hoeveel verdachte tekens er voorkomen. Vervolgens zal de methode een zin tonen die zegt hoeveel speciale tekens er gevonden werden.
Vervolgens wordt een methode IsVerdacht aangeroepen (zie verder) waar het resultaat van CountSpecials als parameter aan wordt meegegeven. Indien het resultaat van IsVerdacht true is dan zal er op het scherm verschijnen “Dit is een verdacht signaal” , anders verschijnt er “Dit is geen verdacht signaal”.
CountSpecials: deze methode aanvaardt een array van chars en geeft een int terug als resultaat. De methode zal teruggeven hoe vaak de speciale letters X,Y,Z en Q voorkomen in de meegegeven array.
De methode zal de eerder geschreven methode NeedsColor gebruiken om te weten of een char speciaal is of niet
IsVerdacht: deze methode aanvaardt een int als parameter en geeft een bool terug als resultaat. Het resultaat van deze methode is true indien de meegegeven parameter een veelvoud van 3 is (3 zelf dus ook) .
Finaal verschijnt de vraag of de gebruiker opnieuw deel 1 tot 3 wil doorlopen. We starten terug bij deel 1 indien de gebruiker ‘j’ (als karakter) invoert. In alle andere gevallen sluit het programma zich af.
Volgende opgave was de vaardigheidsproefopdracht voor inhaalexamen van dit vak (Programming Principles) in januari 2022
De applicatie bestaat uit 2 verschillende rondes waarin de leerling de namen, symbolen en atoomnummers van de chemische elementen moet raden.
Ronde 1: 10 willekeurige vragen om de kennis van de naam, symbool of atoomnummer te testen.
Ronde 2: sudden death ronde die enkel test naar de kennis van de symbolen en die eindigt van zodra de student 1 fout maakt.
De eerste array bevat de naam van het element, de tweede bevat het symbool. Beide arrays zijn synchroon uiteraard: het symbool van het element met de naam Helium is "He".
Het atoomnummer van een element/symbool is de "index+1" van het element/symbool in de array. Het atoomnummer van Lithium is dus 3.
Eerst wordt aan de gebruiker gevraagd hoeveel vragen er in ronde 1 moeten gesteld worden (ga ervan uit dat de gebruiker altijd een positief getal invoert. Geen invoercontrole nodig met andere woorden).
Een loop wordt gestart die even vaak wordt uitgevoerd als dat er vragen dienen gesteld te worden (dit is ronde 1 die start).
In de loop wordt telkens de StelVraag-methode (zie verder) aangeroepen. Het resultaat van deze methode, de score, wordt bijgeteld bij de totaalscore. 1 punt per juist anwoord. Er wordt een willekeurige vraagsoort als derde parameter meegeven.
De score van ronde 1 wordt getoond.
Ronde 2 wordt gestart door de SuddenDeathRonde-methode aan te roepen. Het resultaat van deze methode is de score voor ronde 2.
De totaalscore van ronde 1 en ronde 2 opgeteld wordt getoond.
Een namenarray van strings, die de namen van de elementen zal bevatten.
Een even lange andere symbolenarray van strings, die de respectievelijke symbolen zal bevatten
Een enumtype genaamd VraagSoort waarmee kan aangegeven worden wat voor vraag in de methode moet gesteld worden (mogelijheden zijn: ZoekSymbool, ZoekAtoomNummer, ZoekNaam)
De methode stuurt een int terug, die de score voorstelt (0 indien fout, 1 indien juist) (let op: we hanteren een int, ook al zijn er maar 2 mogelijke uitkomsten, we willen echter dat de applicatie in de toekomst ook met andere scores kan werken)
Afhankelijk van de vraagtype zal de applicatie nu een vraag stellen. De vraag zal telkens een willekeurig element kiezen. De gebruiker moet (nog steeds in de methode) het juiste antwoord intypen dat dan zal gecontroleerd worden:
ZoekSymbool: de applicatie toont een willekeurig element uit de namen array en vraagt het symbool (het toont ook het atoomnummer bij de vraagstelling). Indien de gebruiker het juiste symbool geeft geeft de methode 1 terug, anders 0. Via de symbolenarray kan de applicatie controleren of dit klopt. Voorbeeld van de vraag: "Wat is het symbool van Helium (atoomnummer 1)?" Antwoord = H.
ZoekAtoomNummer: de methode toont een element naam (uit de namen array) en wil weten wat het atoomnummer is (zijnde de index+1 van het element). Ook hier is de score het zelfde. Voorbeeld: "Wat is het atoomnummer van Helium?" Antwoord= 2.
ZoekNaam: in deze vraag wordt een willekeurig symbool gekozen uit de symbolenarray en gevraagd wat de element naam is. Voorbeeld: "Wat is het element H, met atoomnummer 2?" Antwoord: He. Ook hier zelfde score.
Indien de gebruiker fout antwoord dan wordt eerst het juist antwoord getoond en dan wordt een score van 0 teruggegeven.
Tip: je kan overwegen om voor de 3 vraagtypes 3 aparte methodes aan te maken die je dan aanroept vanuit deze methode (hoort niet bij opgave, maar zal je code wel leesbaarder maken)
Een namenarray van strings, die de namen van de elementen zal bevatten.
Een even lange andere symbolenarray van strings, die de respectievelijke symbolen zal bevatten
De methode stuurt een int terug, die de totale score voorstelt.
Deze methode start een loop waarin telkens een vraag van het type ZoekSymbool wordt gesteld gebruikmaken van de StelVraagmethode.
Zolang de gebruiker juist antwoordt blijft deze loop doorgaan. De loop zal de totale score bijhouden (het telt het resultaat van StelVraag op bij een totale score).
De methode stopt wanneer de gebruiker een fout heeft gemaakt. Het geeft dan de totaalscore terug.
Een liggend streepje aan het begin van een lijn geeft aan dat dit door de gebruiker werd ingevoerd:
Hoeveel vragen moeten er in ronde 1 gesteld worden?
_3
Ronde 1 start! Hier volgen 3 vragen
Wat is element Cl, met atoomnummer 17?
_Chloor
Fout. Het was Chlorine. Geen punt!
Wat is element Zn, met atoomnummer 30?
_Zinc
Juist! 1 punt bij
Wat is het atoomnummer van Radon?
_120
Fout. Het was 86. Geen punt!
Je score voor ronde 1 is 1
De sudden death ronde start nu!
Wat is het symbool van Chromium, met atoomnummer 24?
_Cr
Juist! 1 punt bij
Wat is het symbool van Astatine, met atoomnummer 85?
_As
Fout. Het was At.Sudden death gedaan!
Je score voor ronde 2 is 1
Je totale score is 2
Helaas, de Mac-DamsCamp slaagt niet aan. Toch heeft APDonalds™ je gevraagd om hun kassa-software grondig te vernieuwen. Aan jou de taak om de bestelling van een hamburger, met optioneel drank en frietjes, te stroomlijnen. Go get’m!
Hier de algemene flow van de applicatie (merk op dat de methoden BestelFrietjes,BestelDrinken en BerekenTotaal allemaal vanuit BestelHamburger worden aangeroepen, wat later wordt uitgelegd)
De applicatie loopt oneindig door en kan dus niet afgesloten worden).
In de hoofdapplicatie bewaar je in een array (met grootte 100) van doubles telkens het resultaat van de BestelHamburger-methode. (met deze array doe je voor de rest niets).
Deze methode toont het menu( zie onderaan) en heeft een double als resultaat. De methode vraagt eerst welke hamburger de gebruiker wenst. De gebruiker voert een string in voor z’n keuze (“gewoon”, “fish”, “veggie”). Zolang de gebruiker geen juist antwoord geeft wordt de vraag opnieuw gesteld en de input uitgelezen.
Vervolgens dient de gebruiker met “j” of “n” te antwoorden of deze frietjes wilt .Indien ja dan wordt de methode “BestelFrietjes” aangeroepen.
Vervolgens dient de gebruiker met “j” of “n” te antwoorden of deze frisdrank wenst. Indien ja dan wordt de methode “BestelDrinken” aangeroepen.
Finaal roept deze methode de BerekenTotaalMethode aan en zal alle verzamelde informatie aan deze methode meegeven (zie verder). Het resultaat van de BerekenTotaalMethode (een double) wordt teruggegeven als resultaat van deze methode.
Deze methode vraagt hoeveel frietjes de gebruiker wenst en zal het resultaat (een getal) teruggeven als resultaat. De gebruiker voert een getal in tussen 1 en 10 (geen controle nodig) en dit getal geeft deze methode terug.
De methode vraagt welke frisdrank de gebruiker wenst (zie menu), wederom voert de gebruiker een getal in. Dit getal wordt omgezet naar een enum van het type Frisdranken (met als waarden Water, Fanta, Cola) dat zal teruggeven als resultaat van de methode.
Deze methode geeft de prijs als double tot 2 cijfers na de komma op het scherm weer en zal deze waarde ook als return teruggeven. De methode aanvaardt volgende parameters:
hamburger, string, verplicht
aantalfrietjes, int, optioneel (standaard: 1)
drank, enum type Frisdranken, optioneel (standaard: "geen")
Volgende menukaart wordt gebruikt om met voorgaande informatie de totaalprijs te bereken.
Hoera. Je nieuw opgerichte bedrijf “Tornado” heeft z’n eerste contract binnen. Om de capaciteiten van je bedrijf aan te tonen heeft je klant gevraagd een spel, Underlook 2, te programmeren. Laat je niet afschrikken door de opgave van de klant: het gaat om een eenvoudig spelletje. Doel Het spel bestaat uit meerdere delen die je dient te maken, te weten:
Deel 1: Een hero-generator (2punten)
Deel 2: De hero-visualisatie (2 punten)
Deel 3: Een trainingsmissie om het spel aan de speler duidelijk te maken (3 punten)
Deel 4: Het spel zelf dat uit drie rondes bestaat (5 punten)
PROTIP: lees eerst de gehele opgave tot het einde. Kijk goed na dat je alles hebt gelezen en niet als een ‘kieke zonder kop’ begint te programmeren. PROTIP2: Het spel is eenvoudig, maar je klant heeft een nogal onduidelijke manier van opgave opgesteld. LEES DAAROM ZEKER DE APPENDIX ACHTERAAN WAAR HET SPEL EENVOUDIGER WORDT TOEGELICHT
Maak een hero-generator die 3 zaken zal generen, namelijk een naam, aantal aanval en aantal verdediging. Hoe?
Vraag aan de gebruiker "Wil je een random held genereren?(ja/nee)"
Indien de gebruiker “nee” antwoordt dan heeft je held volgende standaard eigenschappen:
Aanval= 5
Verdediging= 5
Naam= “Default”
Indien de gebruiker “ja” antwoordt dan zal een willekeurige held aangemaakt worden, als volgt:
Aanval = willekeurig getal van 1 tot en met 9
Verdediging = 10 – aanval [als dus bij aanval 3 werd gegenereerd dan zal de verdediging 7 zijn]
Naam= resultaat van de methode NaamGen.
NaamGen-methode
De Methode NaamGen heeft volgende eigenschappen:
Aanvaardt geen parameters
Geeft een string terug, namelijk de gegenereerde naam.
Deze naam wordt willekeurige gekozen uit een array die vooraf gevuld werd met volgende 10 namen: TorBro, Vuilhard, Merci, Junkpoes, Genki, Ono, April, Yingyatta, Ombra en Lookup.
Dit deel roept 1 methode aan genaamd “DoeTraining”. Deze methode zal de speler een test-spel (Opgelet: het appendix achteraan dit document beschrijft de spelregels van het spel, zoals ze ook hieronder verwerkt werden) laten uitvoeren zodat de speler begrijpt hoe het spel werkt.
DoeTraning-Methode
Deze methode heeft volgende eigenschappen:
Retourneert niets. Toont enkel output in de console.
Aanvaardt 3 parameters, namelijk een string voor de naam, en twee ints voor de aanval en verdediging
Deze drie parameters zijn de resultaten die je in Deel 1 hebt gemaakt en die je nu meegeeft aan deze methode.
De werking van de methode is als volgt:
Een oefenmonster wordt gemaakt dat aanval = 4 en verdediging = 6 heeft.
Er wordt aan de speler gevraagd hoeveel hij wenst te schieten. Dit getal mag niet groter zijn dan de aanvalskracht van de speler (wat je in deel 1 hebt gemaakt) en minimum 1.
De vraag toont ook tussen welk bereik van getallen de speler mag kiezen. [1 tot en met ‘aanvalskracht’)
Als dus de speler aanval 5 heeft dan worden enkel de getallen 1,2,3,4 en 5 aanvaardt.
Indien de speler een foutief getal invoert dan zal de vraag herhaald worden tot de speler een correct getal ingeeft.
Er wordt nu gecontroleerd of de speler het monster raakt: enkel indien het gekozen getal maximum 1 afwijkt van de verdediging van het monster is dit raak.
Het monster in de training heeft standaard 6, dus enkel de getallen 5,6 en 7 worden aanvaardt.
Indien de speler raakt dan wordt de verdediging van het monster met 1 verlaagt.
Bij mis gebeurt er niets. (een held met lage aanval zal dit startmonster dus niet kunnen raken)
Nu mag het monster aanvallen: het monster (de computer) kiest een willekeurig getal tussen 1 en de aanvalskracht van het monster (in de training dus tussen 1,2,3 en 4)
Indien het monster raakt dan wordt de verdediging van de speler met 1 verlaagd.
Toon aan de speler de uitkomst van de training:
De speler wint indien de som van de speleraanval en spelerverdediging groter of gelijk is aan de som van de aanval en verdediging van het monster.
Voorbeeld output (na creatie van random held met aanval 2 en verdediging 8):
---De training---
Hoeveel wil je schieten? (min=1, max=2)
2
Oei, gemist. Het monster heeft verdediging 6. Je had een getal tussen 5 en 7 moeten kiezen (als dat kon met je huidige aanvalskracht).
Door te missen wordt je aanval met 1 verlaagt.
Nu valt het monster aan.
Het valt aan met 4.
Oef, gemist. De aanvalskracht van het monster zakt.
Eens kijken wie wint. Diegene met de hoogste som van aantal en verdediging wint. Bij gelijke stand wint de held.
Het monster wint de training.
De mogelijk verloren verdediging uit de training wordt bij aanvang van deze fase teniet gedaan. De speler heeft dus terug de aanval en verdediging zoals deze in deel 1 werd aangemaakt. In dit deel zal de speler het spel effectief kunnen spelen. In dit deel wordt een nieuwe methode “DoeGame” aangemaakt.
DoeGame-methode
Deze methode heeft volgende eigenschappen:
Retourneert niets. Toont enkel output in de console.
Aanvaardt 3 parameters, namelijk een string voor de naam, en twee ints voor de aanval en verdediging
Deze drie parameters zijn de resultaten die je in Deel 1 hebt gemaakt en die je nu meegeeft aan deze methode.
De werking is iets complexer: * Eerst verschijnt de boodschap “Het spel gaat beginnen. Druk op enter om door te gaan.” * Nadat de speler op enter heeft geduwd wordt het console-scherm leeggemaakt. * Er wordt nu 3 keer een methode “DoeGevecht” aangeroepen (zie verder). * Deze methode zal telkens een bool terug geven om aan te geven of de speler wel of niet dit gevecht wint. * Na ieder gevecht krijgt de speler terug al z’n aanval en verdediging. * Na 3 gevechten wordt de score getoond aan de speler: de score is gewoon de som van het aantal van de 3 gewonnen gevechten. Als de speler 2 van de 3 wedstrijd won dan geeft de methode 2 terug.
DoeGevecht-methode
Deze methode heeft volgende eigenschappen:
Retourneert een bool. Deze is true indien de speler het gevecht heeft gewonnen.
Aanvaardt 2 parameters, twee ints voor de aanval en verdediging
Deze twee parameters zijn de resultaten die je in Deel 1 hebt gemaakt en die je nu meegeeft aan deze methode.
De werking is als volgt:
Een gevecht is bijna identiek aan de training. Er zijn enkele verschillen:
Bij ieder gevecht wordt een nieuw, willekeurig monster wordt aangemaakt aan de start.
Het monster wordt als volgt aangemaakt: eerst wordt een willekeurig getal tussen 1 tot en 9 gekozen voor de aanval van het monster. De verdediging van het monster is 10 minus net gekozen aanval van het monster.
Indien de speler mist wordt zijn aanval met 1 verlaagt. Indien de speler raakt wordt de verdediging van het monster met 1 verlaagt [beiden mogen negatief worden]
Indien het monster mist wordt de aanval van het monster met 1 verlaagt. Indien het monster raakt wordt de verdediging van de speler met 1 verlaagt [beide mogen negatief worden]
Wanneer het gevecht voorbij is (speler en monster hebben ieder 1 keer proberen te schieten) zal de methode een bool teruggeven. Deze zal true zijn indien de speler wint (omdat z’n aanval+ verdediging groter of gelijk is aan die van het monster), zoniet wordt false teruggegeven.
Voorbeeld-output:
Volgende scherm verschijnt 3 keer:
Nieuw monster staat klaar!
Hoeveel wil je schieten? (min=1, max=6)
4
Oei, gemist. Het monster heeft verdediging 9. Je had een getal tussen 8 en 10 moeten kiezen (als dat kon met je huidige aanvalskracht).
Door te missen wordt je aanval met 1 verlaagt.
Nu valt het monster aan.
Het valt aan met 1.
Oef, gemist. De aanvalskracht van het monster zakt.
Het monster wint dit rondje.
Gevolgd dan door:
Mooi zo April. Je behaalde een score van 1. Tot volgende keer!
In dit spel komt de held steeds een ander monster tegen. Ieder gevecht tegen een monster is dus anders. Beide spelers (monster en held) worden gedefinieerd door twee parameters:
Aanvalskracht
Verdedigingskracht Deze parameters zijn bij aanmaken steeds samen 10 (verdediging+aanval) van zowel speler als monster Deze parameters worden bij de monsters willekeurig gegenereerd bij de start van ieder nieuw monster. Bij de held zijn deze 5 en 5, tenzij de speler deze ook random wil gegenereerd krijgen.
spelverloop
Om de beurt mag een van beide spelers “schieten”. Ze gebruiken hierbij hun aanvalskracht als maximum-kracht dat ze kunnen schieten. * Enkel indien met een kracht die maximum 1 verschilt van de verdediging van het doel zal er geraakt worden. Als dus het monster een verdediging van 5 heeft dan moet de held met een kracht van 4,5 of 6 schieten om te raken.
Wanneer gemist wordt zal de aanvalskracht van de schietende speler met 1 verlaagt worden. Indien raak dan zal de verdediging van het doelwit met 1 verlaagt worden.
De speler wiens totale som van verdediging en aanvalskracht na het gevecht het hoogste is wint het gevecht.
Opgelet: de kans bestaat dus dat de speler of het monster al van bij de start onmogelijk kan winnen omdat de aanvalskracht te laag is tegenover de verdedigingskracht van de tegenspeler. Dat is de pech die je kan hebben.
Volgende opgave was de vaardigheidsproefopdracht voor het examen van dit vak (Programming Principles) in januari 2024
Tekst die start met ">" is invoer van de gebruiker.
Geef n:
>5
Geef nu 5 getallen in:
>3
>2
>2
>-1
>2
Hier volgt de informatie over je invoer:
Kleinste ingevoerde getal: -1
Grootste ingevoerde getal: 3
Het meest ingevoerde getal: 2
dit getal werd 3 keer ingevoerd
Gemiddelde: 1,60
Schrijf een methode GenereerRandom. Deze methode geeft een double terug en aanvaardt 2 int parameters, genaamd onderGrens en bovenGrens. De methode zal een random double getal teruggeven dat zich tussen de ondergrens en bovengrenswaarden bevindt. De bovengrens is exclusief en zal dus zelf nooit gegenereerd worden.
Als de methode met de waarden 6 en 12 wordt aangeroepen zal er dus een kommagetal tussen 6 en 12 worden teruggegeven worden.
Indien de ondergrens en bovengrens parameters even groot zijn dan wordt het dubbele van de bovengrens gebruikt.Indien de ondergrens groter is dan de bovengrens dan worden de grenzen omgekeerd gebruikt.
Schrijf een methode ToonArrayKleuren die een array van double aanvaardt:
De methode berekent het gemiddelde van alle waarden in de array.
Twee int variabelen boven en onder krijgen volgende inhoud: boven krijgt de waarde van het gemiddelde naar boven afgerond (naar het dichtsbijzijnde gehele getal). onder krijgt de waarde van het gemiddelde naar onder afgerond. (als het gemiddelde 13.6 was dan krijgt boven de waarde 14, en onder onder de waarde 13).
Deze methode zal vervolgens de inhoud van de meegeven array naar het scherm visualiseren als volgt. Het toont de getallen uit de array naast elkaar in een rij (telkens 1 cijfer na de komma), telkens met een tab tussen. Ieder getal dat zich tussen de waarden onder en boven bevindt zal vierkante haakjes rond zich hebben (bv [17,0] )
Schrijf een programma dat aan de gebruiker de onder en bovengrens waarden vraagt (int) en vervolgens 100 keer de GenereerRandommethode met deze informatie aanroept. De 100 gegenereerde getallen worden in een array bewaard. Deze array wordt aan de methode ToonArrayKleuren meegegeven die vervolgens het nodige werk zal doen.
Een lokale cinema heeft je hulp nodig. Ze wensen een kassasysteem. Gebruikers krijgen een menukeuze en kunnen zo aangeven hoeveel tickets van elke soort er besteld moeten worden. De applicatie zal bij foute invoer een foutboodschap tonen en de invoer negeren en wachten op correcte invoer (door het menu opnieuw te tonen).
Wanneer het menu opstart worden volgende opties getoond:
Normaal ticket (10 euro)
Reductie ticket (8 euro)
Groepsticket (30 euro voor 5 personen)
Opnieuw
De gebruiker kiest 1 van deze 4 opties. Bij een andere optie dan 1,2,3 of 4 zal een fout getoond worden en wordt het menu opnieuw getoond.
Bij optie 1, 2 en 3: vervolgens vraagt het programma hoeveel tickets van deze optie nodig zijn (indien de gebruiker dus 2 tickets van optie 3 kiest dan gaat het dus om 90 euro voor 15 personen). Vervolgens wordt terug het begin menu getoond.
Onderaan het menu wordt de hele tijd de huidige kost én aantal personen getoond. Enkel wanneer de gebruiker optie 4 kiest worden deze getallen gereset.
Gegeven volgende flowchart die een lamp-technieker gebruikt:
Schrijf een applicatie die met de gebruiker de flowchart overloopt om te bepalen wat er met de lamp moet gebeuren. De gebruiker dient telkens met yes of no te antwoorden. Wanneer een van de 3 groene eindpunten wordt bereikt wordt de oplossing in rode tekst getoond en dan vraagt de applicatie aan de gebruiker of deze nogmaals wil starten. Bij “no” sluit het programma af.
Maak een methode Casino. De methode aanvaart een double en een int als parameter en geeft een double terug. De methode zal een casino-simuleren en geeft op het einde de winst (of verlies) van de speler terug. De double die wordt meegegeven is het startkapitaal. De int is het aantal simulaties n. De methode zal n roulette-rondes simuleren als volgt en telkens de winst of verlies bijhouden.
Iedere van de n simulaties gebeurt het volgende:
De computer kiest een willekeurig getal tussen 0 en 60. Dit is zogezegd de keuze van de speler bij roulette.
De computer kiest een willekeurig getal tussen 0 en 60. Dit is zogezegd het getal waar de roulette op belandt.
Indien beide getallen overeenkomen zal het startkapitaal van de speler met 1 verhogen. Indien het getal niet gelijk was wordt er 0.1 van het kapitaal afgehouden.
Finaal geeft de methode terug hoeveel geld er nog overblijft.
Maak een applicatie die aan de gebruiker een startkapitaal vraagt. Vervolgens gebruik je de Casino methode om aan de speler te tonen hoeveel er van zijn kapitaal zou overblijven als hij:
10 keer het roulettespel speelt
100 keer
10 000
1 000 000 keer
Toon telkens ook hoeveel verlies (of winst) dit is ten opzichte van het startkapitaal. Bij winst wordt dit verschil in groene letters getoond, bij verlies in rode letters.
Tekst die start met “>” is invoer van de gebruiker.
Wat is je startkapitaal?
>1000
Gegeven deze informatie krijg ik volgende resultaten
Als je 10 keer roulette speelt zou je eindkapitaal 999,2 zijn, dat is een verschil van -0,8.
Als je 100 keer roulette speelt zou je eindkapitaal 993,4 zijn, dat is een verschil van -6,6.
Als je 10000 keer roulette speelt zou je eindkapitaal 133,8 zijn, dat is een verschil van -866,2.
Als je 1000000 keer roulette speelt zou je eindkapitaal -95486,2 zijn, dat is een verschil van -94486,2.
De opleiding organiseert een conferentie. Om dit in goede banen te leiden is besloten om de deelnemers via een applicatie te registeren. De applicatie zal twee arrays bijhouden, 1 met de achternamen (type string), 1 met de leeftijd van die persoon. De applicatie bestaat uit 3 fases:
Fase 1 Registratie: nieuwe deelnemers kunnen wordt toegevoegd, samen met hun leeftijd.
Fase 2 Statistieken: Statistieken van de conferentie.
Fase 3 Informatie opvragen: de gebruiker kan de leeftijd van een gebruiker opzoeken.
De applicatie vraagt telkens de naam, en dan de leeftijd. Indien als naam “stop” wordt gegeven stopt deze fase. De ingevoerde naam en leeftijd wordt in de respectievelijke array geplaatst (op dezelfde index). Er kunnen maximum 50 mensen deelnemen aan de conferentie.
De gebruiker kan nu éénmalig de leeftijd van één deelnemer opzoeken. De gebruiker dient hiervoor de naam in te voeren. Indien de naam gevonden wordt, dan zal de leeftijd getoond worden. Zo niet dan verschijnt de boodschap “niet gevonden”.
Tekst die start met “>” is invoer van de gebruiker.
Geef deelnemers ("stop" om te stoppen)
>jos
Geef leeftijd van jos
>24
Geef deelnemers ("stop" om te stoppen)
>frans
Geef leeftijd van frans
>88
Geef deelnemers ("stop" om te stoppen)
>marie
Geef leeftijd van marie
>32
Geef deelnemers ("stop" om te stoppen)
>stop
Fase 2 - Statistieken van de deelnemers
Er zijn 3 deelnemers
Gemiddelde leeftijd is 48
Er zijn 2 deelnemers onder het gemiddelde namelijk jos, marie,
Er zijn 1 deelnemers boven of op het gemiddelde namelijk frans
Fase 3 - Welke deelnemer zoekt u?
>frans
Deze heeft leeftijd 88
Gegeven volgende flowchart voor een sauna. De gebruiker kan via een menu'tje ingeven wat hij wenst te doen. Pas de flowchart toe en houdt rekening met volgende zaken:
De veiligheidsvoorschriften tonen gewoon de tekst "OPGELET WARM!" in rode letters.
De sauna start met 5 houtblokken op het vuur. Ieder houtblok zorgt voor 10 graden warmte. Als de gebruiker dus 60 graden wenst, dan moet er 1 blok toegevoegd worden. Telkens een blok wordt toegevoegd wordt de nieuwe warmte getoond. De sauna zal nooit voorbij de gewenste warmte gaan. Als de gebruiker dus 75 graden wenst, dan zullen er in totaal 7 blokken op het vuur moeten liggen.
Telkens het menu wordt getoond verminder het aantal blokken met 1. (dit wil zeggen dat de 5 startblokken ogenblikkelijk 4 worden wanneer het programma opstart en het menu toont).
Tekst die start met ">" is invoer van de gebruiker.
Welkom bij de sauna (40 graden). Je keuze? 1=voorschriften, 2= opwarmen, 3= stoppen.
>1
OPGELET WARM!
Welkom bij de sauna (30 graden). Je keuze? 1=voorschriften, 2= opwarmen, 3= stoppen.
>2
Hoe warm moet het worden?
>65
1 blok toegevoegd. Het is nu 40 graden.
1 blok toegevoegd. Het is nu 50 graden.
1 blok toegevoegd. Het is nu 60 graden.
OPGELET WARM!
Welkom bij de sauna (50 graden). Je keuze? 1=voorschriften, 2= opwarmen, 3= stoppen.
>3
Een methode A (naam: GenGetal)die aan de gebruiker een getal vraagt en dit getal verdubbeld teruggeeft. Indien de gebruiker een negatief getal opgeeft dan zal de methode 0 teruggeven. Deze methode vereist geen parameters.
Een methode B (naam: GenLandcode)die iedere aanroep een string bestaande uit 2 random karakters (hoofdletters "A" tot en met "Z") teruggeeft. 25% van de tijd zal de methode de string "XX" teruggeven in plaats van een random sequentie. Deze methode vereist geen parameters.
Een methode C (naam: Combineer) waar een landcode (bv "BE") en een geheel getal aan kan meegegeven worden. De landcode is optioneel (standaard : "BE"). De methode zal de landcode en het getal samengevoegd als een string teruggeven. Als er dus "FR" en 5 wordt meegegeven, geeft de methode FR5 terug.
Maak een methode GenereerAutoKenteken. Deze methode heeft geen invoer en geeft een string terug, als volgt:
Het roept eerst methode A aan.
Het roept methode B aan.
Het gebruikt de uitvoer van voorgaande methoden om methode C aan te roepen. Indien methode B "XX" teruggaf, dan zal methode C zonder landcode parameter worden aangeroepen.
Roep de methode GenereerAutoKenteken 5 keer aan vanuit de main en bewaar de kentekens in een arrays.
Toon finaal alle gegenereerde kentekens in de array aan de gebruiker.
Volgende methode kan je gebruiken om het IP-adres van je computer te verkrijgen. Deze methode zal je IP-adres teruggeven als een array van 4 strings. Als je adres het volgende is "192.168.1.100", dan zal de methode dit teruggeven als de stringarray met de waarden: "192","168","1","100".
static string[] VerkrijgIP()
{
try
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString().Split(".");
}
}
return new string[] { "0","0","0","0"}; //indien geen adres gevonden
}
catch (Exception ex)
{
return new string[] { "0", "0", "0", "0" };
}
}
Gebruik deze methode om volgende zaken te doen (OPGELET: bovenstaande methodecode mag NIET aangepast worden):
Basis informatie
In het hoofdprogramma gebeuren volgende zaken:
Je toont je eigen IP-adres (verkregen via de VerkrijgIP methode), waarbij je een punt plaatst tussen ieder deel, bijvoorbeeld: "192.168.1.100".
Je toont het masker, waarbij we veronderstellen dat het laatste element uit de array het masker is. Dit laatste deel tonen we als "x" .Als ons huidige IP adres "10.3.34.234" is dan tonen we: "10.3.34.x".
Hulp-methoden
Maak een aantal hulpmethoden aan (bepaald zelf return type en eventuele parameters), met volgende eigenschappen.
IsLokaal: deze methode controleert of een meegegeven IP-adres uit een lokaal netwerk komt. Een IP-adres is lokaal indien het eerste van de 4 delen 10 of 192 is. "10.34.42.2" is dus een lokaal adres. "34.10.12.111" is geen lokaal adres.
ToonOmgekeerd: deze methode toont het meegegeven IP-adres omgekeerd op het scherm. "192.168.1.100" wordt dan "100.1.168.192" op het scherm.
IsCorrectAdres: deze methode controleert of een meegegeven IP-adres een legaal adres is. Een IP-adres is geldig indien ieder deel een getal is tussen 1 tot en met 254. Volgende adres is dus geen correct adres "192.304.2.6", vanwege het tweede deel dat hoger is dan 254.
IsGelijk: deze methode zal laten weten of 2 meegegeven IP-adressen identiek zijn.
VerhoogAdres: deze methode zal het meegegeven IP-adres met eentje verhogen. Het zal het achterste getal met 1 verhogen. Indien het getal op 255 komt, dan wordt dit getal terug 1 (je hoeft niets met het 2e getal te doen). "192.168.1.100" zal "192.168.1.101" worden. "192.157.23.254" zal "192.157.23.1" worden. Het nieuwe adres wordt terug als een string-array gegeven uit de methode.
Toon de werking in je main aan van deze methoden, gebruik makend van je eigen IP-adres dat je van de methode VerkrijgIP kreeg..
Tekst die start met ">" is invoer van de gebruiker.
Je ipadres is: 192.168.1.100
Het masker: 192.168.1.x
Werking Islokaal: Dit is een lokaal adres.
Werking Omgekeerd: 100.1.168.192
Werking IsCorrectAdres: Dit is een correct adres
Werking IsGelijk( vergeleken met 192.168.1.105): deze zijn niet gelijk
Werking VerhoogdAdres, nieuwe adres is: 192.168.1.101
In de vorige eeuw was The Matrix een uiterst memorabele film. In volgende code tonen we hoe je het "bekende" computer-beeld kunnen nadoen waarin groene, random letters op het scherm verschijnen.
Random rangen = new Random();
Console.ForegroundColor = ConsoleColor.Green;
while (true)
{
//Genereer nieuw random teken:
char teken = Convert.ToChar(rangen.Next(62, 400));
//Zet teken op scherm
Console.Write(teken);
//Ietwat vertragen
System.Threading.Thread.Sleep(1);
//Af en toe donker kleurtje
if(rangen.Next(0,3)==0)
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
}
}
Enkele opmerkingen:
System.Threading.Sleep() is een ingebouwde C# methode die aan de computer verteld dat je applicatie(thread) gedurende x milliseconden mag gepauzeerd (Sleep) worden. Het argument geeft weer hoeveel milliseconden dit moet zijn. Wil je dus 1 seconden pauzeren dan geef je 1000 mee.
Opgelet: Sleep zal je programma volledig "blokkeren", het zal met andere woorden ook geen andere zaken doen zoals input van de gebruiker detecteren.
Volgende tutorial toont hoe je een eenvoudig filmpje kan maken dat je, mits wat fantasie, vlot kan uitbreiden over enkele weken met interactieve aspecten.
Volgende voorbeeld toont wat je bijvoorbeeld kan doen. Kopieer dit alles naar een eigen project tussen de accolades van de main:
int framenummer = 0;
int sleeptime = 1000; // in milliseconden
while (true)
{
framenummer = framenummer + 1;
if (framenummer == 1)
{
Console.WriteLine("Het begin");
}
else if (framenummer == 2)
{
Console.WriteLine("Tweede frame");
}
else if (framenummer == 3)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Derde frame Andere kleur");
}
else if (framenummer == 4)
{
sleeptime = 4000; //vergeet niet terug te zetten in latere frames indien je dit maar eenmalig wil
Console.WriteLine("Frame dat langer blijft staan");
}
else if (framenummer == 5)
{
sleeptime = 500;
Console.WriteLine("Moving ball: *");
}
else if (framenummer == 6)
{
Console.WriteLine("Moving ball: *");
}
else if (framenummer == 7)
{
Console.WriteLine("Moving ball: *");
}
else if (framenummer == 8)
{
Console.WriteLine("Moving ball: *");
}
//Voeg hier frames tussen
else
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\n\n\n\nThe End");
}
System.Threading.Thread.Sleep(sleeptime); //Pauzeer programma
Console.Clear();
Deze code zal een teller (framenummer) per seconde (instelbaar via sleeptime) met 1 verhogen. Vervolgens zal de code uitgevoerd worden binnen de else-if clausule die overeenkomt met de huidige framenummer.
De eerste keer staat de teller op 1 en wordt dus de code tussen volgende if uitgevoerd.
if (framenummer == 1)
{
Console.WriteLine("Het begin");
}
Vervolgens wordt deze met 1 verhoogd en wordt deze code uitgevoerd:
else if (framenummer == 2)
{
Console.WriteLine("Tweede frame");
}
En zo voort. Je kan dus zelf frames toevoegen door steeds een constructie als de volgende toevoegen waar de commentaar //Code om uit te voeren in dit frame staat:
else if (framenummer == x)
{
//Code om uit te voeren in dit frame
}
(vervang X door het framenummer dat dit moet zijn)
Je kan ook bepalen wat het volgende frame moet zijn door de variabele framenummer aan te passen naar het framenummer dat je nodig hebt -1 . Stel dat je bijvoorbeeld in frame 8 wenst dat na dit frame frame 3 wordt uitgevoerd, dan schrijf je:
Via de methode ConsoleSetCursorPosition kan je instellen waar de cursor moet gezet worden. Je geeft tussen de haakjes van deze methode de x,y coördinaten (integers) mee waar de cursor moet gezet worden.
Als je vervolgens tekst schrijft dan wordt die weggeschreven vanaf dat punt. De coördinaten zijn x,y coördinaten, waarbij het punt (1,1) het eerste karakter linksboven in de console is.
Volgende frame zet bijvoorbeeld een "X" 10 letters naar rechts, 20 lijnen naar beneden
else if (framenummer == 9)
{
Console.SetCursorPosition(10, 20);
Console.WriteLine("X");
}
Volgende demonstratie toont de kracht van methoden. We zullen een steeds complexer geheel maken, dat dankzij methoden, nog steeds onderhoudbaar én leesbaar zal blijven. We zullen een bottom-up approach hanteren waarbij we eerst beginnen met de meest basis-functionaliteit die we nodig hebben en zo steeds een schil , in de vorm van een methode, er omheen coderen.
Ons doel is een method SpeelFilm te maken die een filmpje, bestaande uit opeen volgende frames en scenes, zal afspelen in de Console.
We zullen een uiterst boeiend filmpje maken waarin een mannetje naar z’n auto wandelt en er vervolgens in wegrijdt.
We maken een methode die 1 karakter op het scherm kan plaatsen op een positie naar keuze. Omdat we willen voorkomen dat dit mislukt indien de coördinaten buiten het scherm vallen, zullen we in deze methode eerst controleren of de coördinaten geldig zijn.
static void DrawChar(char drawchar, int posX, int posY)
{
if (posX >= 0 && posX < Console.WindowWidth)
{
if (posY >= 0 && posY < Console.WindowHeight)
{
Console.SetCursorPosition(posX, posY);
Console.Write(drawchar);
}
}
}
Willen we deze methode gebruiken dan kunnen we bijvoorbeeld in de Main schrijven: DrawChar('@',5,10);
Dit zal resulteren in het "@"-teken op het scherm op de positie 5, 10 (plaatsen naar rechts, 10 lijnen naar beneden).
Een rechthoek tekenen kan nu heel eenvoudig met behulp van 2 for-lussen.Eén lus om van links naar rechts te gaan. Eén lus om van boven naar onder te gaan.
De methode aanvaardt naast het karakter dat we willen tekenen ook nog :
De positie van de linkerbovenhoek van rechthoek op het scherm
De lengte en de breedte van de rechthoek
static void DrawRectangle(char drawchar, int posX, int PosY, int width, int height)
{
for (int i = posX; i < posX + width; i++)
{
for (int j = PosY; j < PosY + height; j++)
{
DrawChar(drawchar, i, j);
}
}
}
We kunnen dus deze methode aanroepen als volgt:DrawRectangle('*',4,6,3,6);
Het hek is van de dam. We kunnen nu allerlei complexere zaken tekenen bestaande uit combinaties van rechthoeken en karakters. Een gezicht kan bijvoorbeeld bestaan uit 1 grote rechthoek voor het gezicht. Met daarin 2 aparte ogen, voorgesteld door het karakter ‘0’ (dus mbv DrawChar) en een neus 'b'. Alsook een mond die bestaat uit een korte rechthoek bestaande uit underscores:
De enige extra complexiteit is dat we steeds rekening moeten houden met de locatie van het gezicht (posx,posy) en de onderlinge posities van de gezichts-onderdelen. We plaatsen dus bijvoorbeeld de mond op 6e lijn ten opzichte van de bovenkant van het gezicht.
Denk er ook aan dat we de volgorde van methode-aanroepen hier relevant is.Indien we de eerste DrawRectangle aanroep helemaal onderaan zouden plaatsen, dan zou deze al de andere gezichts-onderdelen overtekenen.
We kunnen nu een uber-boeiend filmpje maken waarin het mannetje naar de auto loopt en dan er in wegrijdt.We zullen dit stukje top-down benaderen. Eerst maken we een methode PlayMovie() die frame per frame het filmpje zal afspelen.Afhankelijk van het framenummer zal een andere scene getoond worden (lijnen 6,8):
private static void PlayMovie()
{
for (int i = 0; i < 60; i++)
{
if (i < 35)
WalkToCarScene(i);
else if (i >= 35)
RideAwayScene(i - 35);
System.Threading.Thread.Sleep(100);
Console.Clear();
}
}
Merk op dat we i gebruiken als framenummer en zo weten wanneer welke scene moet afgespeeld worden. Voorts geven we het framenummer door naar de scene-methoden voor het geval ze deze nodig hebben om bijvoorbeeld de correcte positie te bepalen:
Het wikipedia artikel over toonhoogte leert ons dat de grondtonen do-re-mi-fa-sol-la-si-do de frequenties : 264-297-330-352-396-440-495-528 hz behelzen (excuses indien dit ‘jargon’ niet klopt...ik ken even veel van muziek als van metsen).
De Console.Beep() methode laat ons toe om tonen te genereren op een bepaalde frequentie (in hz) en van een bepaalde duur (in milliseconden, i.e. 1/1000 seconde).
We kunnen dus de computer de toonladder afspelen, elke noot 1 seconde langs, als volgt:
Zorg ervoor dat je de toonladder van hierboven als volgt kunt aanroepen:
Do();
Re();
Mi();
Fa();
Sol()
La();
Si();
Do2();
Iedere methode zal dus de correcte toon afspelen gedurende 1s (je mag dit ook sneller instellen naar keuze).
Iedere "noot-methode" zal ook steeds op het scherm tonen welke noot wordt afgespeeld (doe dit als eerste in de methode) De uitvoer van voorgaande code wordt dan (het geluid moet je er maar even bij verzinnen):
Do
Re
Mi
Fa
Sol
La
Si
Do
Extra 1: plaats iedere noot in een andere tekstkleur. Extra 2: kan je er voor zorgen dat de noten achter elkaar, met komma, gescheiden op het scherm komen in plaats van onder elkaar?
Door de frequentie van een toon te vermenigvuldigen of te delen met veelvouden van 2 krijg je de tonen op andere octaven. Pas de ‘noot-methoden’ aan zodat 2 parameters kunnen meegeven worden:
De lengte in milliseconden dat de toon moet aangehouden worden
De octaaf van de toon: 1 = basis octaaf die we al hadden, 2= 2e octaaf (dus frequentie x2) 3= 3e octaaf (frequentie x 4) etc.
Als je dus de tweede octaaf wil spelen (met iedere toon om de 500ms) moet je deze als volgt kunnen aanroepen:
Maak minstens 2 methoden naar keuze: iedere methode zal een liedje beginnen spelen dat je zelf hebt gemaakt (bv een bestaand kinderliedje). Hier bijvoorbeeld het begin van "You are my sunshine": Re(); Sol(); La(); Si(); Si(); Si(); La(); Si(); Sol(); Sol();
Bij het opstarten van het programma krijg je nu een menu te zien waaruit de gebruiker een liedje kan kiezen dat gespeeld moet worden. Vervolgens wordt dit liedje gespeeld en nadien wordt de vraag terug gesteld. Indien de gebruiker een onbekende keuze invoert dan zal een random liedje worden afgespeeld uit de mogelijke liedjes.
Wanneer een liedje werd afgespeeld dan dient de methode terug te geven (als double) hoe lang het liedje heeft geduurd. Het hoofdmenu toont dit aan het einde van het afspelen:
Je kan de duur van een methode heel eenvoudig methoden als volgt, gebruikmakende van de StopWatch:
//Start
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
//Voer te meten code uit
///...
//Stop
stopwatch.Stop();
double totaletijd = stopwatch.Elapsed.TotalSeconds;
totaleTijd zal de totaal verstreken tijd in seconden bevatten.
Maak een playlist editor aan in je radio (als extra keuzemenu voeg je "Playlist Maker" toe). Wanneer de gebruiker dit kiest dan krijgt deze alle liedjes te zien. De gebruiker kan nu invoeren welke liedjes na elkaar moeten worden afgespeeld. Je bewaard deze keuze in een array.
In het hoofdmenu komt nu ook de mogelijkheid "Speel playlist" af. Wanneer deze keuze wordt genomen dan zullen de liedjes zoals ze in de playlist staan afgespeeld worden.
Nadien wordt getoond hoe lang de playlist heeft afgespeeld in totaal.
In een aparte array houdt je een log bij van alle keuzes/invoer die de gebruiker tijdens het verloop van het programma heeft uitgevoerd. (bv 1,1,3, 2, 5, etc)
Via een nieuw menuitem "Herhaal acties" worden deze acties terug uitgevoerd zodat het lijkt alsof het programma automatisch werkt!
Het zal niet zo lijken, het zal zijn!
Een verhaalgenerator is een methode die hulp-methoden gebruikt om zo een "automatisch" verhaal te verzinnen. We hanteren een bottom-up approach om dit probleem aan te pakken.
We maken een methode die namen kan genereren. Deze naam gebruiken om het hoofdpersonage voor te stellen.
We maken een methode die steeds een naam generereert met een ingegeven lengte. Een naam bestaat in dit geval uit een reekds willekeurige karakters van a tot en met z.
Een eerste versie kan zijn:
static Random r=new Random();
static string GenerateNameSimple(int namelength)
{
string name = "";
for (int i = 0; i < namelength; i++)
{
name += (char)r.Next('Z', 'Z'+1);
}
return name;
}
De eerste lijn is een klein trukje om ervoor te zorgen dat de variabele r overal in het programma aangeroepen kan worden en we dus niet in iedere methode deze opnieuw moeten aanmaken.
De bovenstaande methode roepen we aan als volgt:
string result = GenerateNameSimple(10);
Console.WriteLine(result);
Een nadeel van deze eerste versie is dat er soms onuitspreekbare namen gemaakt worden. Een betere methode zou zijn dat medeklinker en klinker afwisselend voorkomen (bv "adilo"). Hier gaan we eerst enkele hulpmethoden genereren:
We kunnen nu een methode maken die enkel klinkers genereert:
static char GenereerKlinker()
{
int waarde = r.Next(0, 5);
switch (waarde)
{
case 0: return 'E';
case 1: return 'O';
case 2: return 'I';
case 3: return 'U';
case 4: return 'A';
}
return ' ';
}
We zouden in GenerateNameSimple een if kunnen plaatsen om te controleren of het gegenereerd karakter een klinker is. Dit heeft als nadeel dat we niet kunnen voorspellen hoe snel de methode zal werken: er is zelfs een eindige kans dat de methode nooit kalar zal zijn indien er telkens weer een medeklinker wordt geworpen.
static string GenereerVoorwerp()
{
switch (r.Next(0, 10))
{
case 0: return "een bal";
case 1: return "de hond";
case 2: return "de kat";
case 3: return "een lepel";
case 4: return "het kind";
case 5: return "het boek";
case 6: return "de computer";
case 7: return "een vork";
case 8: return "het scherm";
case 9: return "een dvd";
default:
return "IETS ONBEKENDS";
}
Een zin heeft vaak ook een bijzin die met een voegwoord (bv en) achter de hoofdzin wordt geplakt. Deze methode doet dit en kan even veel bijzinnen achter mekaar plakken als dat er als parameter wordt meegegeven.
static string GenereerVoegwoord()
{
switch (r.Next(0, 6))
{
case 0: return " en ";
case 1: return ", maar ";
case 2: return ", echter ";
case 3: return ", dus ";
case 4: return ", of ";
case 5: return ", doch";
default:
return "IETS ONBEKENDS";
}
}
Maak nu een methode GenereerVerhaal die een willekeurig aantal lange zinnen genereert.
Kan je volgende zaken toevoegen?
De GenereerLangeZin methode heeft als probleem dat alle bijzinnen steeds met een ander ondwerp werken. Het zou beter zijn als het onderwerp uit de hoofdzin ook in de bijzinnen dezelfde is. Pas daarom GenereerKorteZin aan zodat deze methode een optionele parameter aanvaardt, namelijk het te gebruiken onderwerp. Indien de method geen parameter meekrijgt (==null) dan zal de methode een nieuw onderwerp genereren.
Het zelfde voor de verhaal generator: zorg ervoor dat ook de GenereerLangeZin een onderwerp als parameter aanvaardt.
Kan je hier een daar adjectieven toevoegen aan je zin. Een adjactief is een extra 'beschrijving' van het onderwerp of leidende voorwerp. Bijvoorbeeld "groene bal" of "stomme Eric".
In dit all-in-one tonen we hoe je, stap voor stap, kan komen tot een speelbaar, eenvoudige tekst-gebaseerd spel. We hanteren hierbij de principes van "refactoring": we gaan onze code steeds verbeteren op gebied van leesbaarheid en onderhoudbaarheid. Bij iedere stap zullen we dan ook extra functionaliteit toevoegen.
Het doel is te komen tot een spel waarbij de gebruiker kan wandelen door een kaart. De kaart zelf is dynamisch, bepaalde ruimtes zijn pas toegankelijk wanneer aan bepaalde voorwaarden is voldaan.
We gebruiken een array van strings om de opeenvolgende kamers te beschrijven. Door middel van een for-loop doorlopen we de array en tonen we iedere beschrijving van de kamer op het scherm.
Telkens de gebruiker op enter drukt verschijnt de volgende kamer.
Merk op dat de array-lengte geen invloed heeft op de forloop. We kunnen dus eenvoudig kamers toevoegen zonder dat dit invloed heeft op de werking van het programma. We zullen blijven behouden doorheen het hele programma (de speciale kaart uitgezonder in fase 8).
string[] Kamers = new string[]
{
"Je staat voor de ingang.",
"Je bent in de hal.",
"Je bent in het computerlabo",
};
for (int i = 0; i < Kamers.Length; i++)
{
Console.WriteLine(Kamers[i]);
Console.ReadLine();
}
We bieden de mogelijkheid aan aan de gebruiker om zelf te kiezen naar welke kamer er wordt gegaan. De gebruiker kan dus "vooruit’" of "achteruit" gaan in de array. We houden hiervoor een variabele (huidigekamer) bij die bijhoudt waar de gebruiker zich momenteel bevindt.
Telkens de gebruiker zich wil verplaatsen controleren we of deze verplaatsen toegestaan is. De Huidigekamer variabele is dus automatisch ook de index van de te tonen kamer in de string-array.
string[] Kamers = new string[]
{
"Je staat voor de ingang.",
"Je bent in de hal.",
"Je bent in het computerlabo",
};
int huidigekamer = 0;
string keuze = "";
while (keuze != "q")
{
Console.WriteLine(Kamers[huidigekamer]);
Console.WriteLine("Vooruit= V, ACHTERUIT = A, q= quit");
keuze = Console.ReadLine();
if (keuze == "V" && huidigekamer != Kamers.Length - 1)
huidigekamer++;
else if (keuze == "A" && huidigekamer != 0)
huidigekamer--;
else if (keuze == "q")
Console.WriteLine("Byebye");
else
{
Console.WriteLine("Foute invoer");
}
}
Vervolgens willen we de mogelijkheid om een 2D wereld aan te bieden. Hierbij gebruiken we een zogenaamde lookup-table zodat we onze wereld array eenvoudig kunnen houden én kamers kunnen herbruiken.
Eerste definiëren we de verschillende kamers die er bestaan:
string[] Kamers =
{
"Onbekend terrein", //0
"In een gang", //1
"In de lobby", //2
"In de bar", //3
"In de keuken", //4
"Achtertuin"//5
};
Vervolgens maken we 2D-array die onze kaart voorstelt. De array is van het type int. Iedere cijfer in de array zal de index bevatten van de kamer die op die plek moet komen. Dit is dus een zogenaamde look-up-table of Lut (meer info: wiki):
Daar we ons nu op een 2D-kaart bevinden hebben we 2 variabelen nodig om onze huidige positie te onthouden:
int posX = 0;
int posY = 0;
We spreken af dat de locatie (0,0) zicht linksboven in de array bevindt.
We maken een oneindige loop die steeds de volgende stappen zal doen:
Huidige kamertekst op het scherm tonen
Aan de gebruiker vragen naar waar hij wil wandelen
Positie van gebruiker veranderen
Terug naar 1.
Eerst gebruiken we dus de lut om de huidige kamer beschrijving te tonen. We gebruiker de huidige spelerlocatie als index’s in de Kaart-array en vragen zo de kamerindex op. Die kamerindex gebruiken we om de tekst uit de Kamers-array te tonen.
while (true)
{
int kamerindex = Kaart[posX, posY];
Console.WriteLine(Kamers[kamerindex]);
De gebruiker kan zich naar het noorden, oosten, zuiden of westen begeven (respectievelijk naar boven, links, onder, rechts op de kaart). We vragen dus telkens de gebruiker naar waar hij:
Console.WriteLine("NOZW? Naar waar wil je?");
char inp = Convert.ToChar(Console.ReadLine().ToUpper());
Naargelang de richting die de gebruiker ingeeft moeten we dus telkens 2 zaken contoleren:
Bevindt de gebruiker zich momenteel (VOOR we z’n locatie aanpassen) aan de rand van de array (0 of Length-1)
Probeert de gebruiker zich naar verboden vakje te begeven (een onbekend terrein vakje)
Indien aan deze 2 voorwaarden niet is voldaan dan mogen we de huidige locatie van de gebruiker zonder problemen veranderen. Dit behelst dus dat we , naargelang de richting, de posX en posY waarden veranderen, namelijk:
Noorden: posX met 1 verlagen
Zuiden: posX met 1 verhogen
Oosten: posY met 1 verhogen
Westen: posY met 1 verlagen
We krijgen in de switch dus:
case 'N':
if (posX != 0 && Kaart[posX - 1, posY] != 0)
posX--;
else Console.WriteLine("Kan niet");
break;
case 'O':
if (posY != Kaart.Length(1)-1 && Kaart[posX, posY + 1] != 0)
posY++;
else Console.WriteLine("Kan niet");
break;
case 'Z':
if (posX != Kaart.GetLength(0)-1 && Kaart[posX + 1, posY] != 0)
posX++;
else Console.WriteLine("Kan niet");
break;
case 'W':
if (posY != 0 && Kaart[posX, posY - 1] != 0)
posY--;
else Console.WriteLine("Kan niet");
break;
}
We wensen een visuele indicatie van de kaart te tonen aan de gebruiker (zonder dat hij ziet wat voor kamer het is). We voegen daarom een methode DrawMap() toe die de kaart iedere keer opnieuw zal tekenen. Deze methode gaat ook de positie van de gebruiker duidelijk maken a.d.h.v. een "X" op de kaart. Onze game-loop veranderen we dus naar:
while (true)
{
Console.Clear();
DrawMap(Kaart, posX, posY);
int kamerindex = Kaart[posX, posY];
Console.WriteLine(Kamers[kamerindex]);
Console.WriteLine("NOZW? Naar waar wil je?")
De DrawMap() methode toont dus de huidige locatie als een "X". Voorts willen we dat enkel bereikbare kamers getoond worden (we gebruiken een "O" hiervoor). Elementen op de kaart die wijzen naar index 0 ("Onbekend terrein") worden niet getoond.
We doorlopen in de DrawMap() methode de volledige kaart. Lijn per lijn. Hiervoor gebruiken we 2 geneste for-loops. De outer-loop (index i) zal de X-coördinaat aflopen, oftewel lijn per lijn. De inner loop (index j) zal de Y-coördinaat aflopen, oftewel kolom per kolom:
private static void DrawMap(int[,] Kaart, int posX, int posY)
{
for (int i = 0; i < Kaart.GetLength(0); i++)
{
for (int j = 0; j < Kaart.GetLength(1); j++)
{
Merk op dat ook deze methode geen hardcoded array-grenzen bevat. We kunnen dus eender welke kaart aan deze methode aanbieden.
Binnen de inner-for gaan we nu element per element van 1 rij op het scherm tonen. Eerst controleren we of de speler zich bevindt in het element dat we op het punt staan te tekenen. Als dat zo is dan plaatsen we een "X":
if (posX == i & posY == j)
Console.Write("X");
Anders plaatsen we een "o" indien het gaat om gebied waar de speler toegelaten is:
else if (Kaart[i, j] != 0)
Console.Write("o");
Niet toegelaten gebied tonen we niet, we zetten dus een spatie in de plaats:
else
Console.Write(" ");
Na iedere inner-loop moeten we vervolgens een newline toevoegen, anders worden alle rijen van de kaart naast elkaar gezet. Finaal krijgen we dus:
}
Console.Write('\n');
}
Dit resulteert in volgende finale code voor deze fase:
static void Main()
{
int[,] Kaart ={ {1, 2, 1, 3},{0, 1, 0, 1},{0, 4, 0, 5}};
string[] Kamers ={"Onbekend terrein", "In een gang", "In de lobby", "In de bar", "In de keuken", "Achtertuin"};
int posX = 0;
int posY = 0;
while (true)
{
Console.Clear();
DrawMap(Kaart, posX, posY);
int kamerindex = Kaart[posX, posY];
Console.WriteLine(Kamers[kamerindex]);
Console.WriteLine("NOZW? Naar waar wil je?");
char inp = Convert.ToChar(Console.ReadLine().ToUpper());
switch (inp)
{
case 'N':
if (posX != 0 && Kaart[posX - 1, posY] != 0)
posX--;
else Console.WriteLine("Kan niet");
break;
case 'O':
if (posY != Kaart.GetLength(1)-1 && Kaart[posX, posY + 1] != 0)
posY++;
else Console.WriteLine("Kan niet");
break;
case 'Z':
if (posX != Kaart.GetLength(0)-1 && Kaart[posX + 1, posY] != 0)
posX++;
else Console.WriteLine("Kan niet");
break;
case 'W':
if (posY != 0 && Kaart[posX, posY - 1] != 0)
posY--;
else Console.WriteLine("Kan niet");
break;
}
}
}
private static void DrawMap(int[,] Kaart, int posX, int posY)
{
for (int i = 0; i <= Kaart.GetLength(0); i++)
{
for (int j = 0; j <= Kaart.GetLength(1); j++)
{
if (posX == i & posY == j)
Console.Write("X");
else if (Kaart[i, j] != 0)
Console.Write("o");
else
Console.Write(" ");
}
Console.Write('\n');
}
}
Zoals reeds aangehaald staat niets je in de weg om je spel-wereld groter te maken. Hiervoor hoef je enkel (momenteel) de Kamers en Kaart arrays aan te passen. Alle code zal blijven werken.
Bijvoorbeeld:
int[,] Kaart =
{
{1, 2, 1, 3, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 4, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 7, 0, 6, 1, 8},
};
string[] Kamers =
{
"Onbekend terrein", //0
"In een gang", //1
"In de lobby", //2
"In de bar", //3
"In de keuken", //4
"Achtertuin",//5
"In de securityroom", //6
"In de personeelsruimte", //7
"In de folterkamer" //8
};
Het principe van een lut verschilt eigenlijk weinig van een eenvoudige database. We zouden dus meerdere look-up-tables (tabellen) kunnen definiëren en deze gebruiken om meer informatie in onze spelwereld te plaatsen.
We kunnen bijvoorbeeld per kamer ook een beschrijving tonen van die kamer. Daar we nog niets kennen van struct en class (zogenaamde datastructuren) moeten we ons dus behelpen als volgt: we definiëren een nieuwe array Beschrijving waarbij ieder element de index heeft van de respectievelijke kamer:
int[,] Kaart =
{
{1, 2, 1, 3, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 4, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 7, 0, 6, 1, 8},
};
string[] Kamers =
{
"Onbekend terrein", //0
"In een gang", //1
"In de lobby", //2
"In de bar", //3
"In de keuken", //4
"Achtertuin",//5
"In de securityroom", //6
"In de personeelsruimte", //7
"In de folterkamer" //8
};
string[] Beschrijving =
{
"", //0
"Een ordinaire saaie gang met een mooie vloer", //1
"De receptioniste kijkt je verbaast aan. Een plant in de hoek is het enige groen in de purperen ruimte.", //2
"2 gasten zitten half beschonken aan de toog. Een verliefd koppel is zachtjes aan het praten", //3
"Overal liggen etensresten, maar verder is hier niets of niemand interessant.", //4
"Mooie plantjes, enkele bomen en een gezellig terras.",//5
"De veiligheidsagent houdt je nauwlettend in het oog", //6
"Overal staan kastjes.Hier en daar is er een personeelslid zich aan het omkleden", //7
"Wat doet deze vreemde plek in het hotel." //8
};
Door 1 extra lijntje (+ eentje voor een visuele scheiding tussen beschrijving en kamertitel) plaatsen we nu steeds de kamerbeschrijving onder de kamertype:
Na iedere actie van de speler verwerken we steeds weer de kaart in zowel de DrawMap()-methode als tijdens het verwerken van de speler-input. We kunnen dus eenvoudig een dynamische kaart maken die zich aanpast naargelang bepaalde acties.
Je met de kennis die we zo meteen tonen bijvoorbeeld aan de start van het programma met een lege kaart: naargelang de speler zich verplaatst in de wereld zal de kaart aangevuld worden. (tip: gebruik hiervoor een array VolledigeKaart en een array ReedsOntdekteKaart of iets dergelijks. De speler krijgt steeds de ReedsOntdekteKaart te zien in DrawMap(). Naargelang acties van de speler kopieer je dan bepaalde elementen uit VolledigeKaart naar ReedsOntdekteKaart).
We definiëren onze kaart (merk op dat we de folterkamer en geheime gang verwijderen rechts onderaan):
We willen volgende functionaliteit inbouwen:
>indien de gebruiker in de kamer met index 6 ("SecurityRoom") een bepaalde actie onderneemt dan zal een geheime gang en kamer (folterkamer) op de kaart bij verschijnen, rechts van de securityroom.
De actie gaan we nu even eenvoudig beschouwen als volgt: de gebruiker kan in alle kamers "G" als opdracht doorgeven. Echter, enkel wanneer de gebruiker zich in de kamer met index 6 bevind dan zal de geheime kamer zichtbaar worden.
We voegen daarom een extra case toe aan onze switch:
case 'G':
if (kamerindex != 6)
{
Console.WriteLine("Dat zal hier niet werken");
}
else
{
Als de speler wél in de securityroom is dan gaan we de kaart-array aanpassen. We voegen rechtsonder in de array de 2 nieuwe kamers toe:
Wanneer we nu de kaart hertekenen dan deze nieuwe ruimte verschijnen en weet de gebruiker dat hij zich daar kan begeven.
De volledige code wordt dan (we laten de DrawMap()-methode even achterwege):
static void Main()
{
int[,] Kaart =
{
{1, 2, 1, 3, 0, 0},{0, 1, 0, 1, 0, 0},{0, 4, 0, 1, 0, 0},{0, 1, 0, 1, 0, 0},{0, 7, 0, 6, 0, 0},
};
string[] Kamers =
{
"Onbekend terrein", //0
"In een gang", //1
"In de lobby", //2
"In de bar", //3
"In de keuken", //4
"Achtertuin",//5
"In de securityroom", //6
"In de personeelsruimte", //7
"In de folterkamer" //8
};
string[] Beschrijving =
{
"", //0
"Een ordinaire saaie gang met een mooie vloer", //1
"De receptioniste kijkt je verbaast aan. Een plant in de hoek is het enige groen in de purperen ruimte.", //2
"2 gasten zitten half beschonken aan de toog. Een verliefd koppel is zachtjes aan het praten", //3
"Overal liggen etensresten, maar verder is hier niets of niemand interessant.", //4
"Mooie plantjes, enkele bomen en een gezellig terras.",//5
"De veiligheidsagent houdt je nauwlettend in het oog. Typ \"G\" om een geheime ruimte te ontdekken", //6
"Overal staan kastjes.Hier en daar is er een personeelslid zich aan het omkleden.", //7
"Wat doet deze vreemde plek in het hotel." //8
};
int posX = 0;
int posY = 0;
char inp='k';
while (inp != 'Q')
{
Console.Clear();
DrawMap(Kaart, posX, posY);
int kamerindex = Kaart[posX, posY];
Console.WriteLine(Kamers[kamerindex]);
Console.WriteLine("******");
Console.WriteLine(Beschrijving[kamerindex]);
Console.WriteLine();
Console.WriteLine("NOZW? Naar waar wil je?");
inp = Convert.ToChar(Console.ReadLine().ToUpper());
switch (inp)
{
case 'N':
if (posX != 0 && Kaart[posX - 1, posY] != 0)
posX--;
else Console.WriteLine("Kan niet");
break;
case 'O':
if (posY != Kaart.GetLength(1)-1 && Kaart[posX, posY + 1] != 0)
posY++;
else Console.WriteLine("Kan niet");
break;
case 'Z':
if (posX != Kaart.GetLength(0)-1 && Kaart[posX + 1, posY] != 0)
posX++;
else Console.WriteLine("Kan niet");
break;
case 'W':
if (posY != 0 && Kaart[posX, posY - 1] != 0)
posY--;
else Console.WriteLine("Kan niet");
break;
case 'G':
if (kamerindex != 6)
{
Console.WriteLine("Dat zal hier niet werken");
}
else
{
Console.WriteLine("Je ontdekt een geheime ruimte");
Kaart[4, 4] = 1;
Kaart[4, 5] = 8;
Console.ReadLine();
}
break;
}
}
}
Vanaf dit punt kun je nu al een relatief eenvoudig, toch leuk spel maken, op voorwaarde dat je verhaal goed zit. Echter, voor we je hierop loslaten gaan we nog enkele zaken refactoren zodat de code wat leesbaarder blijft. In hoofzaak willen we bepaalde stukken code uit de main-body halen en naar aparte methodes extraheren.
Beeld je in dat je de kaart(en) voor je spel uit een bestand laadt. Op zich is dat niet zo moeilijk , maar het vereist natuurlijk extra lijnen code in je, reeds overbevolkte, Main-methode. We verhuizen daarom de code waarin we onze kaarten initialiseren naar een aparte methode. In onze Main schrijven we dan (merk het gebruik van het out keyword op!):
int[,] Kaart;
string[] Kamers;
string[] Beschrijving;
InitialiseerSpel(out Kaart, out Kamers, out Beschrijving);
Deze methode bevat dan gewoon de code van daarnet, mooi verpakt en afgeschermd:
private static void InitialiseerSpel(
out int[,] Kaart,
out string[] Kamers,
out string[] Beschrijving)
{
Kaart = new int[,]
{
{1, 2, 1, 3, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 4, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 7, 0, 6, 0, 0}
};
//Idem voor Kamers en beschrijving
//..
Het verwerken van de userinput kunnen we ook makkelijk extraheren naar aparte methode zodat onze while-loop overzichtelijker wordt :
while (true)
{
Console.Clear();
DrawMap(Kaart, posX, posY);
int kamerindex = Kaart[posX, posY];
Console.WriteLine(Kamers[kamerindex]);
Console.WriteLine("******");
Console.WriteLine(Beschrijving[kamerindex]);
Console.WriteLine();
Console.WriteLine("NOZW? Naar waar wil je?");
VerwerkInput(Kaart, kamerindex, ref posX, ref posY); //NEW
}
Merk op dat we zelfs de volledige loop naar een aparte methode op zijn beurt kunnen extraheren. Maar dat laten we aan de lezer over. We dienen de posities van de speler by reference mee te geven, daar we de posities onmiddellijk willen updaten in de VerwerkInput()-methode.
private static void VerwerkInput(
int[,] Kaart,
int kamerindex,
ref int posX,
ref int posY)
{
char inp = Convert.ToChar(Console.ReadLine().ToUpper());
switch (inp)
{
//etc
Als kers op de taart tonen we snel hoe je het kaartje sexier kan tonen op het scherm. Hier zijn echter een paar belangrijke opmerkingen aan de orde:
De code bevat enkele hardcoded waarden zoals het plaatsen van de cursor m.b.v. Console.SetCursorPosition. Beter zou zijn als deze waarden als Magic numbers worden behandeld of on-the-fly worden berekend.
De kaart bevat Unicode-art met vaste grootte. Dit zal bugs geven indien onze kaart-array groter is dan de dimensies van de Unicode-art: de art zal over de randen van de Unicode-art getekend worden. We kunnen dit oplossen door delen van de Unicode-art te berekenen (bv het aantal lege lijnen en de breedte van een pagina.
We definiëren de nieuwe Methode en voegen als eerste actie Unicode-art toe van een kaart:
Daar we gaan spelen met de kleuren is het aan te raden om steeds volgende acties te ondernemen indien we de kleur van een bepaald karakter of zinnen willen veranderen:
De huidige kleur van de console bewaren (fore en/of background) in een tijdelijke variabele
Kleur veranderen
Karakter of zin op scherm plaatsen
Kleur terug naar de huidige kleur aanpassen.
We tonen dit in de volgende code waarin we de background array (die de Unicode-art bevat) op het scherm willen tekenen. Daarbij willen we dat de karakters donker-cyaan zijn en dat enkel karakters die geen spatie of liggenstreepje zijn een donkergele achtergrond hebben. De commentaar toont de zonet beschreven stappen:
Vervolgens gebruiken we SetCursorPosition om onze spelerskaart ‘over’ de Unicode-art te tekenen. Hierbij voegen we nog wat extra kleurtje toe, de speler-X wordt rood gekleurd:
ConsoleColor bll2 = Console.BackgroundColor;
Console.BackgroundColor = ConsoleColor.DarkYellow;
for (int i = 0; i <= Kaart.GetLength(0); i++)
{
Console.SetCursorPosition(7, 3 + i);
for (int j = 0; j <= Kaart.GetLength(1); j++)
{
if (posX == i & posY == j)
{
ConsoleColor l = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("X");
Console.ForegroundColor = l;
}
else
if (Kaart[i, j] != 0)
Console.Write("o");
else
Console.Write(" ");
}
Console.Write('\n');
}
Console.SetCursorPosition(1, 15);
Console.BackgroundColor = bll2;
}
De while-loop in de Main()-methode passen we nu nog aan zodat:
We de nieuwe DrawCoolMap methode gebruiken
De titel van de kamer steeds op de rechterpagina van de kaart Unicode-art wordt getoond
De beschrijving en andere tekst steeds onder map komt en niet erover
while (true)
{
Console.Clear();
DrawMapCool(Kaart, posX, posY); //a
int kamerindex = Kaart[posX, posY];
Console.SetCursorPosition(26, 6); //b
Console.WriteLine(Kamers[kamerindex]);
Console.SetCursorPosition(1, 16);//c
Console.WriteLine("******");
Console.WriteLine(Beschrijving[kamerindex]);
Console.WriteLine();
Console.WriteLine("NOZW? Naar waar wil je?");
VerwerkInput(Kaart, kamerindex, ref posX, ref posY);
}
private static void InitialiseerSpel(
out int[,] Kaart,
out string[] Kamers,
out string[] Beschrijving)
{
Kaart = new int[,]
{
{1, 2, 1, 3, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 4, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0},
{0, 7, 0, 6, 0, 0}
};
Kamers = new string[]
{
"Onbekend terrein", "In een gang", "In de lobby", "In de bar", "In de keuken", "Achtertuin",
"In de securityroom", "In de personeelsruimte", "In de folterkamer"
};
Beschrijving = new string[]
{
"", "Een ordinaire saaie gang met een mooie vloer",
"De receptioniste kijkt je verbaast aan. Een plant in de hoek is het enige groen in de purperen ruimte.",
"2 gasten zitten half beschonken aan de toog. Een verliefd koppel is zachtjes aan het praten",
"Overal liggen etensresten, maar verder is hier niets of niemand interessant.",
"Mooie plantjes, enkele bomen en een gezellig terras.",
"De veiligheidsagent houdt je nauwlettend in het oog. Typ \"G\" om een geheime ruimte te ontdekken",
"Overal staan kastjes.Hier en daar is er een personeelslid zich aan het omkleden.",
"Wat doet deze vreemde plek in het hotel."
};
}
Life (of Conway Game of Life) is een leuke manier om 2D arrays te gebruiken om 'leven' te simuleren. Afhankelijk van enkele eenvoudige regels wordt beslist of een cel (1 element in de array) wel of niet overleeft naar de volgende generatie. De regels zijn gebaseerd op de 8 omliggende plekken rond de cel die ofwel leeg zijn ofwel een andere cel bevatten:
Any live cell with fewer than two live neighbors dies, as if by underpopulation.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by overpopulation.
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
{% hint style="info" %}
In dit en volgend hoofdstuk staan bij sommige oefeningen bovenaan een link naar een alternatieve manier van de oefening te maken waarbij je ook feedback krijgt. Bekijk zeker eerst dit filmpje. Indien je geen knop "open in visual studio" hebt in github dan kan je dit oplossen als volgt: open Visual studio en kies voor clone a repository:
Vervolgens copy paste je de githuburl als daar om gevraagd wordt (voor de eerste oefening is dat https://github.com/timdams/ZIESCHERPER_TESTS_H1_RapportModule).
Doel: Maak een klasse Pizza die waarden controleert voordat ze worden opgeslagen.
Specificaties:
Klassenaam:Pizza
Properties (Full Properties met validatie):
Toppings (string): Beschrijving van de toppings.
Diameter (int): Doorsnede in cm.
Price (double): Prijs in euro.
Validatie Regels (in de set van de properties): Bij het toewijzen van een nieuwe waarde (value), controleer het volgende. Indien de waarde niet geldig is, doe je niets (de oude waarde blijft behouden).
Price en Diameter: Moeten groter zijn dan 0. (Indien value <= 0 -> negeer).
Toppings: Mag niet leeg zijn. (Gebruik string.IsNullOrWhiteSpace(value) om te controleren. Indien true -> negeer).
Voorbeeldgebruik: Maak in je Main enkele pizza's aan en probeer foute waarden in te stellen om te testen of ze inderdaad geweigerd worden.
Doel: Werken met overerving of losse klassen (hier losse klassen) en validatie.
Specificaties:
Klasse
Property
Type
Validatie in set
Rechthoek
Lengte
int
Indien value < 1, stel in op 1. Anders value.
Breedte
int
Indien value < 1, stel in op 1. Anders value.
Methode:ToonOppervlakte()
void
Berekent Lengte * Breedte en toont resultaat.
Driehoek
Basis
int
Indien value < 1, stel in op 1. Anders value.
Hoogte
int
Indien value < 1, stel in op 1. Anders value.
Methode:ToonOppervlakte()
void
Berekent (Basis * Hoogte) / 2 en toont resultaat.
Let op: Rechthoek en Driehoek zijn hier twee aparte klassen en hebben niets met elkaar te maken, behalve dat ze toevallig gelijkaardige methoden hebben.
Opdracht: Maak van elke figuur een instantie in je Main en roep ToonOppervlakte aan.
Scenario: Je bent zojuist aangenomen als lead developer voor Camping "Het Nullpointerke". De eigenares, Gerda, doet haar boekingen momenteel nog op bierviltjes, maar sinds de doorbraak van "Glamping" verliest ze het overzicht. Ze heeft vooral problemen met gasten die bij het uitchecken niet genoeg geld blijken te hebben, en ze vergeet vaak de seniorenekorting toe te passen (wat tot boze bejaarden aan de receptie leidt).
Aan jou de taak om een digitaal boekingssysteem te bouwen dat deze problemen oplost.
Doel: Ontwerp een klasse Boeking die fungeert als de digitale receptioniste. De klasse moet invoer streng valideren (Gerda houdt van orde), prijzen berekenen op basis van luxe-niveau, en controleren of de gast wel kan betalen voordat de boeking definitief wordt.
Specificaties:
De Accommodatie (Enum)
Definieer een enum VerblijfType met opties: Tentplek (basic), Stacaravan (comfort), en LuxeChalet (voor de echte IT-managers).
De Boeking (Klasse)
Klassenaam:Boeking
Properties (met Validatie):
Hoofdboeker (string): De naam van de gast. Mag niet leeg zijn. Als iemand een lege naam opgeeft, noem je hem "Onbekende Gast".
GeboorteDatum (DateTime): Mag niet in de toekomst liggen. (Tijdreizigers worden niet toegelaten). Indien fout: stel in op vandaag.
HuidigBudget (double): De inhoud van de portemonnee van de gast. Mag niet negatief zijn bij het instellen (geen schulden bij aankomst!).
Type (VerblijfType): Het gekozen verblijf.
CheckInDatum (DateTime): Wordt bij het aanmaken van het object (in de constructor) standaard op Vandaag gezet. (We boeken enkel last-minute).
Dit is de grote finale. Roep BerekenTotaalPrijs aan om te weten wat het kost.
Check: Heeft de gast genoeg HuidigBudget?
Scenario A (Genoeg geld):
Trek het bedrag af van het HuidigBudget.
Bereken de uitcheck-datum (CheckInDatum + aantal nachten).
Toon in de console: "Boeking geslaagd voor [Naam]! U checkt uit op [Datum]. Restbudget: €[Bedrag]".
Scenario B (Te weinig geld):
Toon in de console: "Helaas [Naam], dit kost €[Prijs], maar u heeft slechts €[Budget]. Ga eerst langs de bankautomaat."
Voorbeeldgebruik (in je Main):
// Scenario: Opa Pol wil 5 nachten in een Chalet, maar is zijn portefeuille vergeten.
Boeking boeking1 = new Boeking();
boeking1.Hoofdboeker = "Pol";
boeking1.GeboorteDatum = new DateTime(1955, 3, 12); // Pol is ouder dan 60
boeking1.Type = VerblijfType.LuxeChalet;
boeking1.HuidigBudget = 200; // Oei, dat is krap voor een chalet
// Test de logica
Console.WriteLine("--- Poging 1 ---");
boeking1.BevestigBoeking(5);
// Verwacht: Foutmelding over budget (Prijs is ong. €400 met korting, budget is 200)
// Pol vindt 300 euro in zijn andere broekzak
Console.WriteLine("\n--- Poging 2 (met meer geld) ---");
boeking1.HuidigBudget += 300;
boeking1.BevestigBoeking(5);
// Verwacht: Succesbericht + correcte uitcheckdatum + restsaldo.
{% hint style="info" %}
Er zijn geen aparte Exception handling oefeningen. De bedoeling is dat je zelf steeds in je oefening naar een goede plek(ken) zoekt waar deze kan toegepast worden.
Doel: Zet een lengte om naar verschillende eenheden met behulp van properties.
Specificaties:
Klassenaam:Meetlat
Property (Input):
BeginLengte (type: double): Write-only property om de lengte in meter in te stellen.
Opslag: Sla deze waarde intern op in een private variabele (bv. _lengte).
Properties (Output - ReadOnly): De volgende properties geven de lengte terug, omgerekend naar de gevraagde eenheid:
Property
Type
Formule
LengteInM
double
Geeft _lengte terug.
LengteInCm
double
_lengte * 100
LengteInKm
double
_lengte / 1000
LengteInVoet
double
_lengte * 3.2808
Voorbeeldgebruik:
Meetlat mijnLat = new Meetlat();
mijnLat.BeginLengte = 2; // We stellen in op 2 meter
Console.WriteLine($"{mijnLat.LengteInM} meter is {mijnLat.LengteInVoet} voet.");
Doel: Meng twee kleuren door het gemiddelde te nemen van hun RGB-waarden.
Specificaties:
Klassenaam:Kleur
Properties:
Rood (int)
Groen (int)
Blauw (int)
Methode:
MengKleur(Kleur andereKleur) (void)
Werking (MengKleur): Wanneer MengKleur wordt aangeroepen, veranderen de eigenschappen van de huidige kleur (this). De kleur die als parameter wordt meegegeven verandert niet.
We gaan een programma schrijven dat ons toelaat enkele basis-eigenschappen van specifieke Pokémon te berekenen terwijl ze levellen. Nadruk van deze oefening is het juist gebruiken van properties. Bekijk de cheat sheet bij twijfel.
{% hint style="info" %}
Disclaimer: de informatie in deze tekst is een vereenvoudigde versie van de echte Pokémon-stats in de mate dat ik het allemaal een beetje kon begrijpen en juist interpreteren.
Korte uitleg over Pokémon en hun interne werking: Iedere Pokémon wordt uniek gemaakt door z’n base-stats, deze zijn voor iedere Pokémon anders. Deze base-stats zijn onveranderlijk en blijven dus doorheen het hele leven van een Pokémon dezelfde. Je kan de base-stats als het dna van een Pokémon beschouwen.
De full-stats zijn echter de stats die de effectieve ‘krachten’ van een Pokémon bepalen in een gevecht. Deze stats worden berekend gebaseerd op de vaste base-stats en het huidige level van de Pokémon. Hoe hoger het level van de Pokémon, hoe hoger dus zijn full-stats.
De base-stats worden als int bewaard. Maak voor al deze basis-eigenschappen full properties, namelijk:
HP_Base
Attack_Base
Defense_Base
SpecialAttack_Base
SpecialDefense_Base
Speed_Base
{% hint style="info" %}
Merk op dat deze waarden eigenlijk nooit nog veranderen in een Pokémon. Het is dus raar dat we ze als full properties beschouwen. In het volgende hoofdstuk zullen we dit oplossen door te werken met een constructor.
Voorts wordt een Pokémon ook gedefinieerd door z’n Naam (string), Type (string, bv. grass & poison) en Nummer (int), maak hiervoor auto properties aan.
Met Nummer bedoelen we de Pokémon index die je in de Pokédex kunt opzoeken. Zo heeft Bulbasaur nummer 1 en Pikachu heeft 25.
{% hint style="info" %}
Nog een goede reden nodig om met enum te werken? Het Type van een Pokémon zou je eigenlijk beter met een enum datatype kunnen doen dan met een string.
Voeg een fullproperty Level toe (int). Deze heeft een public get, maar een private setter.
Voeg een publieke methode VerhoogLevel toe. Deze methode zal, via de private setter van Level, het level van de Pokémon met 1 verhogen. Deze methode heeft géén parameters nodig en return'd niets.
Voeg 2 read-only properties toe (enkel get, géén set) genaamd Average (double) en Total (int):
De Average-property geeft het gemiddelde van de 6 base-stats terug, dus (HP_Base + Attack_Base + Defense_Base + SpAttack_Base + SpDefense_Base +Speed_Base)/6.0.
De Total-property geeft de som terug van de 6 basestats. Daar de base stats niet evolueren met het level veranderen dus Average en Total ook niet van zodra de base-stats werden ingesteld, toch mag je beide statistieken steeds herberekenen in de get.
{% hint style="info" %}
Merk op dat je voor deze twee properties dus geen instantievariable nodig hebt. Dit geldt ook voor de hier na beschreven "level-gebaseerde stats".
De eigenschappen van de Pokémon die mee evolueren met het level gaan we steeds als read-only properties van het type int implementeren:
Voeg een read-only property HP_Full toe om de maximum health voor te stellen. Deze wordt berekend als volgt: ( ( (HP_Base + 50) * Level) / 50) + 10 wanneer de get wordt aangeroepen.
Voeg voor iedere ander base-stat een XX_Full readonly property toe . Dus Defense_Full, Speed_Full, etc. Ook deze properties zijn readonly. Deze stats worden berekend als volgt: ( (stat_Base*Level) / 50 ) + 5. Attack_Full bijvoorbeeld wordt dus berekend als: ( (Attack_Base * Level) / 50) + 5
{% hint style="info" %}
Merk op dat de formules enkel met int werken. Het effect hiervan zal zijn dat je full-stats niet per level veranderen, maar pas om de paar levels, daar we informatie "verliezen" door in de deling met int te werken.
{% hint style="info" %}
Bekijk zeker eerst of jouw Pokémon oplossing juist is (vergelijk met de oplossing in deze cursus) voor je verder gaat.
Het is een heel gedoe om telkens manueel de informatie van een Pokémon op het scherm te outputen. Voeg een methode public void ShowInfo() toe aan je Pokémon klasse. Deze methode zal alle relevante informatie (alle properties!) in een mooie vorm op het scherm tonen, bv:
Pikachu (level 5)
Base stats:
* Health = 56
* Speed = 30
etc
Full stats:
* Health = 100
etc.
Maak nu een nieuwe console-applicatie genaamd "Pokémon Tester":
Voeg je Pokémon-klasse-bestand toe aan dit project. Verander de "namespace" van dit bestand naar de namespace van je nieuwe console-applicatie .
Maak enkele Pokémon objecten aan en stel hun base stats in.
Schrijf een applicatie die aan de gebruiker eerst de 6 base-stats vraagt. Vervolgens wordt de Pokémon aangemaakt met die stats en worden de full-stats aan de gebruiker getoond.
Vraag nu aan de gebruiker tot welke level de Pokémon moet gelevelled worden. Roep zoveel keer de LevelUp-methode aan van de Pokémon. (of kan je dit via een parameter doorgeven aan LevelUp?!)
Toon terug de full-stats van de nu ge-levelde Pokémon.
Voeg een methode met volgende signatuur toe aan je hoofdprogramma (dus ook weer in Program.cs): static int Battle(Pokémon poke1, Pokémon poke2).
De methode zal een getal teruggeven dat aangeeft welke van de twee Pokémon een gevecht zou winnen. 1= poke1, 2 = poke2, 0 = gelijke stand.
Controleer steeds of 1 of beide van de meegegeven Pokémon niet null zijn. Indien er 1 null is, dien je een Exception op te werpen.
Bepaal zelf hoe Pokémon vechten (bv. degene met de hoogste average van full-stats). Werk niet enkel met de base-stats, daar deze constant zijn. Het is leuker dat het level ook een invloed heeft (maar ga niet gewoon het level vergelijken).
Genereer 2 willekeurige Pokémon met je generator en laat ze vechten met je battle-methode. Toon wat output aan de gebruiker zodat hij ziet wat er allemaal gebeurt (en gebruik zeker de ShowInfo methode om dit snel te doen). Kan je dit in een loop zetten en wat leuker maken met Pokémon die telkens levelen als ze een gevecht winnen?!
Doel Deze opdracht combineert alle concepten van dit hoofdstuk (Properties, Methoden, Statics, Referenties vs Copies) in één grote simulatie. Indien je de Pokémon-opdracht helemaal hebt gemaakt, dan heeft het niet zoveel nut om ook deze te maken.
Scenario: Je bent de software-architect van de Aardse Vloot. Je moet een systeem ontwerpen om ruimteschepen te beheren, upgrades te geven en gevechtssimulaties uit te voeren tegen de buitenaardse dreiging.
Naam (string): De naam van het schip (bv. "USS Enterprise").
Kapitein (string, private set): De naam van de bevelhebber. Deze kan enkel ingesteld worden via een methode WisselKapitein(string nieuweKapitein).
Basisstatistieken (Base Stats):
Deze worden bij de bouw van het schip vastgelegd (in de main stel je ze in, daarna blijven ze conceptueel vast, hoewel we nog geen constructors gebruiken).
RompSterkte (int): 0-100.
SchildKracht (int): 0-100.
VuurKracht (int): 0-100.
Status:
Ervaring (int): Het level van de bemanning. Start standaard op 0.
Schade (int): Hoeveel schade het schip heeft opgelopen. Start op 0.
Schrijf nu een Main programma dat alles samenbrengt:
Gebruik de MaakWillekeurigSchip om twee schepen te genereren: "De Voyager" en "De Millenium Falcon".
Zet voor beide schepen een kapitein ("Janeway" en "Solo").
Toon de rapporten van beide schepen.
Laat ze vechten (SimuleerGevecht).
Toon de rapporten opnieuw (zie je de schade en ervaring?).
Stuur de verliezer naar de garage (PimpMijnSchip).
Laat ze nog eens vechten. (De verliezer zou nu moeten winnen met zijn upgrades).
Extra Uitdaging: Wat als je een schip "kloneert"? RuimteSchip s3 = s1;. Pas s3 aan (bv. andere naam). Toon nu s1 opnieuw. Wat merk je? (Dit demonstreert dat variabelen slechts verwijzingen zijn naar hetzelfde object in het geheugen).
Doel: Pas de bestaande Meetlat klasse uit het vorige hoofdstuk aan om met een constructor te werken.
Stappenplan:
Verwijder de write-only property BeginLengte.
Voeg toe een private instantievariabele: private double lengteInMeter;.
Maak een Constructor die één parameter aanvaardt (type double) en wijs deze waarde toe aan lengteInMeter.
Pas de werking van de overige properties aan zodat ze nu deze nieuwe variabele gebruiken in plaats van de property.
Voorbeeldgebruik:
// Oude manier (werkt NIET meer na aanpassing):
// Meetlat m = new Meetlat();
// m.BeginLengte = 5;
// Nieuwe manier:
Meetlat m = new Meetlat(5);
Console.WriteLine(m.LengteInCm);
{% hint style="info" %}
Deze oefening werd gemaakt (en aangepast nadien) met behulp van volgende GPT en heeft daarom de tag (GPT) achter de titel staan.
Doel: Gebruik constructors en object initializers om personen aan te maken.
Specificaties:
Klassenaam:Persoon
Properties (Auto):
Voornaam (string)
Achternaam (string)
Geboortejaar (int)
Email (string)
Constructor:
Parameters: voornaam, achternaam.
Validatie:
Indien voornaam gelijk is aan achternaam -> Werp een ArgumentException op met de boodschap "Voornaam en achternaam mogen niet hetzelfde zijn".
Methode:
ToonInformatie() (void): Toont de tekst: "{Voornaam} {Achternaam} geboren in {Geboortejaar} heeft emailadres: {Email}".
Opdracht in Main:
Maak een Persoon object aan met de constructor.
Gebruik Object Initializer Syntax om ook meteen Geboortejaar en Email in te stellen.
Als CanShowCode == true: Geef de echte code terug.
Als CanShowCode == false: Geef altijd -666 terug.
CodeLevel (int) - ReadOnly:
Formule:code / 1000 (gehele deling).
Constructors:
Constructor die één int aanvaardt en deze instelt als de code.
Methode TryCode(int ingevoerdeCode): Deze methode controleert de code en geeft true (juist) of false (fout) terug. De methode print ook feedback naar de console.
Beslissingstabel voor TryCode:
Situatie
Conditie
Actie (Console Output)
Return Waarde
Valsspeler
ingevoerdeCode == -666
"CHEATER"
false
Reeds Geblokkeerd
aantalPogingen >= 10
"Je hebt je 10 pogingen opgebruikt."
false
Juiste Code
ingevoerdeCode == code
"Geldige code. Aantal pogingen = {aantalPogingen}"
true
Foute Code
ingevoerdeCode != code
"Geen geldige code." (Verhoog aantalPogingen met +1)
Pas je Pokemon klasse aan zodat deze op 3 manieren aangemaakt kan worden. Dit betekent dat je 2 constructors moet toevoegen (de default constructor bestaat al, tenzij je die overschreven hebt).
De 3 manieren:
Default Constructor:
Gebruik: new Pokemon()
Actie: Stel alle 6 base-stats standaard in op 10.
Overloaded Constructor:
Gebruik: new Pokemon(hp, att, def, spAtt, spDef, speed)
Actie: Stel de 6 base-stats in met de meegegeven waarden.
Object Initializer:
Gebruik: new Pokemon() { HP_Base = 40, Naam = "Pikachu" }
Actie: Hiervoor hoef je niets speciaals te doen, dit werkt automatisch als je een parameterloze constructor hebt en de properties toegankelijk zijn.
{% hint style="info" %}
Zet de setters van je Base Stat properties op private. Hierdoor kunnen ze alleen aangepast worden tijdens de constructie (via constructor of initializer), maar niet meer daarna.
Scenario: Proficiat! Je bent zonet aangesteld als CTO (Chief Technical Officer) van GreenRide, de nieuwste hipste start-up van 't Stad. De missie? De wereld veroveren met elektrische deelsteps.
De investeerders zijn enthousiast, maar er is één probleem: er is nog geen software. Aan jou om de Core-Backend te schrijven die alle steps beheert, de winst berekent, en ervoor zorgt dat gebruikers niet kunnen wegrijden met een lege batterij.
Als CTO beslis je om slim gebruik te maken van static variabelen voor zaken die voor alle steps gelden (zoals de prijs), en instance variabelen voor unieke data (zoals de locatie en batterij van één specifieke step).
Toon hoeveel steps er nu in gebruik zijn (via de static property).
Prijsstijging:
Het begint te regenen en de vraag stijgt. De directie beslist: DeelStep.PrijsPerMinuut = 0.50;.
De Aankomst:
Laat step 1 stoppen na 20 minuten.
Laat step 2 stoppen na 10 minuten.
De Balans:
Toon de TotaalWinst van het bedrijf.
Toon de batterijstatus van step 1 (is die verminderd?).
Extra (Pro): Voeg een statische methode GeefGratisStroom() toe aan de klasse, die alle steps (die niet bezig zijn) terug oplaadt naar 100%. (Hiervoor zal je wel een lijst van alle aangemaakte objecten moeten bijhouden in de klasse zelf... uitdagend!).
Maak een array die tot 20 prijzen (double) kan bewaren. Vraag aan de gebruiker om 20 prijzen in te voeren en bewaar deze in de array. Doorloop vervolgens m.b.v. een foreach-lus de volledige array en toon enkel de elementen op het scherm wiens prijs hoger of gelijk is aan €5.00. Toon op het einde van het programma het gemiddelde van alle prijzen (dus inclusief de lagere prijzen).
De klasse computeronderdeel bestaat uit volgende autoproperties:
Prijs (int)
ID (int)
InDoos (bool)
Voorts heeft de klasse een default constructor die voorgaande autoproperties op willekeurige waarden instelt (prijs positief tot max 1000, ID een getal tussen 100 en 999, en InDoos heeft 50% kan om true te zijn)
De klasse heeft 1 methode ToonInfo die de 3 waarden van het object naar het scherm stuurt:
Kan je hier een volledige applicatie van maken die een computerfirma als een soort inventaristool kan gebruiken? (en dus met de nodige menu's en mogelijkheden om bijvoorbeeld een nieuw onderdeel toe te voegen.) Kijk zeker eens naar volgende oefening daaromtrent.
Dit soort "de array als inventaris"-oefeningen waarbij je allerlei zaken met die array moet doen zijn geliefkoosde oefeningen en zal je vaak zien terugkomen.
We gaan nu de Student-klasse uit een vorige hoofdstuk (zie onderaan de opgave) gebruiken om een List<Student> van studenten te vullen.
Maak daarom een studenten-lijst aan die 5 studenten bevat :
Initialiseer alle properties van iedere student op een standaard-waarde via de default constructor.
Het programma start op en geeft de gebruiker een menu waaruit kan gekozen worden:
Student gegevens invoeren (eerstvolgende student wordt ingevuld)
Vervolgens moet de gebruiker kiezen welke student (nummer) moet ingevuld worden, van 1 tot 5. Vervolgens kan de gebruiker de gegevens 1 voor 1 invullen (oude gegevens worden zonder pardon overschreven).
Student gegevens tonen (alle studenten)
Wanneer de gebruiker voor 2 kiest dan wordt de GeefOverzicht-methode aangeroepen van iedere student zodat de 5 ‘rapportjes’ onder elkaar op het scherm
Extra's:
Bouw extra functionaliteit naar keuze bij de StudentOrganizer, zoals:
Vragen aan de gebruiker of de oude gegevens overschreven mogen worden, indien deze reeds ingevuld zijn.
Inbouwen van een eenvoudige zoekfunctie. Je kan bijvoorbeeld zoeken op naam (exacte invoer) of alle studenten tonen die in een bepaalde klas zitten of wiens punten onder/boven een bepaalde waarde zitten. Je kan dit als extra menuitem inbouwen, waarbij een nieuw menu verschijnt dat de gebruiker de verschillende zoekmogelijkheden voorstelt.
Verwijderen van een student (waarbij alle gegevens worden gewist)
Controle in alle methode inbouwen zodat ‘lege studenten’ worden genegeerd. Wanneer bijvoorbeeld menu item 2 wordt uitgevoerd (alle studenten tonen) dan worden enkel de ingevulde studenten getoond.
enum Klassen { EA1, EA2, EA3, EA4}
class Student
{
public string Naam { get; set; }
public int Leeftijd { get; set; }
public Klassen Klas { get; set; }
public int PuntenCommunicatie { get; set; }
public int PuntenProgrammingPrinciples { get; set; }
public int PuntenWebTech { get; set; }
public double BerekenTotaalCijfer()
{
return (PuntenCommunicatie + PuntenProgrammingPrinciples + PuntenWebTech) / 3.0;
}
public void GeefOverzicht()
{
Console.WriteLine($"{Naam}, {Leeftijd} jaar");
Console.WriteLine($"Klas: {Klas}");
Console.WriteLine();
Console.WriteLine("Cijferrapport");
Console.WriteLine("*************");
Console.WriteLine($"Communicatie:\t\t{PuntenCommunicatie}");
Console.WriteLine($"Programming Principles:\t{PuntenProgrammingPrinciples}");
Console.WriteLine($"Web Technology:\t\t{PuntenWebTech}");
Console.WriteLine($"Gemiddelde:\t\t{BerekenTotaalCijfer():0.0}");
}
}
Je kan aan de gebruiker enkel strings als input vragen. Om dus zijn ingevoerde klas om te zetten naar een enum gebruik je ofwel:
a) een switch of if-else structuur die naargelang de invoer een andere enumwaarde toekent aan een enumvariabele
b) (PRO) je gebruikt Enum.Parse() (vb : Klassen mijnKlas= (Klassen)Enum.Parse(typeof(Klassen), "EA2");)
Je gaat een bestelsysteem maken voor een fastfoodrestaurant. Klanten plaatsen bestellingen, de keuken verwerkt ze, en de bestellingen worden opgehaald.
Functionaliteiten:
Klanten plaatsen bestellingen:
Elke klant bestelt één of meerdere items.
Bestellingen worden in een Queue opgeslagen (Queue<Bestelling>).
Bestellingen worden verwerkt:
De keuken verwerkt bestellingen op volgorde en houdt bij welke gerechten populair zijn in een Dictionary (Dictionary<string, int>).
De keuken haalt de eerste bestelling uit de Queue en toont de gerechten.
Geschiedenis van bestellingen
Een List houdt alle afgewerkte bestellingen bij (List<Bestelling>)
De gebruiker kan een bestelling plaatsen. De gebruiker geeft een lijst van gerechten in, gescheiden door enter. Wanneer de gebruiker "stop" als gerecht invoert stopt het verwerken. Het Bestellingsobject wordt aangemaakt en aan de Queue toegevoegd.
De keuken verwerkt de bestellingen. De keuken haalt de eerste bestelling uit de Queue en toont de gerechten. De keuken houdt bij welke gerechten populair zijn in een Dictionary (telkens een gerecht is besteld verhoog je de teller van dat gerecht in de dictionary). De bestelling wordt toegevoegd aan de geschiedenis.
Maak een "bookmark manager". Deze tool zal in de console aan de gebruiker 5 favoriete sites vragen: naam en url. Vervolgens zal de tool alle sites in een lijst tonen met een nummer voor. De gebruiker kan dan de nummer intypen en de tool zal automatisch de site in een vereenvoudigde versie op het scherm tonen.
Je opdracht:
Maak een array of List waarin je 5 bookmark objecten kan plaatsen.
Vul de applicatie aan zodat de gebruiker: een bestaand bookmark kan verwijderen en een bestaand bookmark kan aanpassen
Probeer met behulp van hulpmethoden in Program.cs om zo veel mogelijk code te herbruiken.
Enkele zaken die je nodig hebt:
BookMark klasse:
class BookMark
{
public string Naam { get; set; }
public string URL { get; set; }
public void ToonSite()
{
WebClient wc = new WebClient();
string result = wc.DownloadString(URL);
Console.WriteLine(GetPlainTextFromHtml(result));
}
//Bron: https://www.mercator.eu/mercator/std/info_aruba/reporting-hoe-gegevens-afdrukken-met-html-tags.html
private string GetPlainTextFromHtml(string htmlString)
{
string htmlTagPattern = "<.*?>";
var regexCss = new Regex("(\\<script(.+?)\\</script\\>)|(\\<style(.+?)\\</style\\>)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
htmlString = regexCss.Replace(htmlString, string.Empty);
htmlString = Regex.Replace(htmlString, htmlTagPattern, string.Empty);
htmlString = Regex.Replace(htmlString, @"^\s+$[\r\n]*", "", RegexOptions.Multiline);
htmlString = htmlString.Replace(" ", " ");
return htmlString;
}
}
Voorbeeld van hoe de bookmark klasse zal werken:
BookMark u = new BookMark();
u.Naam = "Google";
u.URL = "https://www.google.be";
u.ToonSite();
Maak een klasse Speelkaart die je kan gebruiken om een klassieke kaart met getal en "kleur" voor te stellen.
Een kaart heeft 2 eigenschappen, een getal van 1 tot en met 13 (boer=11, koningin= 12, heer= 13).
Een kleur, de zogenaamde suite. Deze stel je voor via een enumtype en kan als waarden Schoppen, Harten, Klaveren of Ruiten zijn.
Schrijf nu 2 loops die de 52 kaarten van een standaard pak in een List<SpeelKaart> lijst plaatst.
Maak een applicatie die telkens een willekeurige kaart uit de stapel trekt en deze aan de gebruiker toont. De kaart wordt na het tonen ook uit de lijst verwijderd. Door met een willekeurig getal te werken hoef je dus je deck niet te schudden.
Bij de all-in-one projecten van dit semester vind je als eerst een tekstgebaseerde game (hier). Volg deze uitleg, maak het spel en voeg je eigen zotte ideeën toe.
Scenario:
Je bent de organisator van CodeChella, het festival waar programmeurs en muziekliefhebbers samenkomen om te genieten van beats en bytes. Het is chaos achter de schermen: de line-up moet beheerd worden, de rijen aan de ingang puilen uit en niemand weet hoeveel VIP-tickets er effectief verkocht zijn.
Aan jou om de FestivalManager te schrijven die orde schept in deze wanorde.
Specificaties:
Deze oefening combineert de drie grote collecties: List, Queue en Dictionary.
Kan je alle kennis van dit semester gebruiken om een volwaardige Pokémon-gerelateerde manager te maken? Beeld je in dat je een programma schrijft dat toelaat dat gebruikers kunnen bijhouden welke Pokémon ze reeds hebben. Je array is een soort verzamelmap waarin je alle Pokémon kan plaatsen die je vindt.
De gebruiker krijgt een menu waarin hij kan kiezen om:
Een nieuwe Pokémon toevoegen aan je map. Hiervoor toon je een lijst van geldige Pokémon. De gebruiker kiest welke nummer hij wenst toe te voegen, en die wordt dan aan de map toegevoegd.
Oplijsten welke Pokémon er reeds in de map zitten
Specifieke verzamelde Pokémon uit verwijderen
Statistieken van een specifieke verzamelde Pokémon te tonen
Specifieke verzamelde Pokémon van level te verhogen
Plaat alle logica uit deel 1 in een nieuwe PokeManagerklasse. Plaats je array met Pokémon als static array in deze klasse. Deze klasse zal quasi enkel static methoden hebben, zoals:
ToonMenu
DeletePokemon(int index)
AddPokemon(Pokemon toadd)
ShowCollection()
ShowStats(int index)
Levelup(int index, int amountLevel)
De idee van deze klasse is dat er in je hoofdprogramma zeer weinig code nog steeds, maar die wel zeer duidelijk is. Iets in trend van:
while(true)
{
PokeManager.ToonMenu();
Console.WriteLine("Wat wil je doen?");
//Toon mogelijkheden
switch(keuze)
{
case 1:
PokeManager.ShowCollection();
break;
//etc
}
}
Bij het toevoegen van nieuwe Pokémon toon je alle mogelijke Pokémon door deze uit een csv-bestand uit te lezen inclusief hun basis stats. Je kan deze file hier downloaden.
Je verzamelmap naar een een csv-bestand schrijven en uitlezen (mypoke.csv). Je hoeft hiervoor enkel het id en huidige level weg te schrijven. Nadien kan je met dit id de Pokémon opzoeken in de totaallijst van alle bestaande Pokémon.
Een default constructor die bovenstaande eigenschappen op willekeurige waarden instelt. Bij maxlengte is deze waarde 90% van de tijd tussen 150 en 210. 5% van de tijd is deze een getal tussen 40 en 150. 5% van de tijd een getal tussen 210 en 240.
Een overloaded constructor waarbij de 3 eigenschappen als parameter kunnen doorgegeven worden.
Voorzie een methode ToonMens. Deze vat de informatie van een Mens-object in één lang samen, hierbij zal de achtergrond van de tekst de kleur van de ogen zijn.
De tekst die verschijnt is: maxlengte [in meter], geslacht
Iedere mens heeft een methode 'Plantvoort' die als parameter een Mens met geslacht "Man" vereist.
Enkel bij vrouwen zal deze methode iets doen. Indien deze op mannen wordt aangeroepen geeft de methode null terug.
De methode geeft een nieuw mens object terug. De nieuwe mens heeft als lengte de gemiddelde lengte van de man en vrouw. De oogkleur is 50% van de tijd die van de man en 50%van de tijd die van de vrouw. Het geslacht is willekeurig.
Maak 12 willekeurige mensen en plaats deze in een List. De eerste 6 mensen zijn vrouwen, de laatste 6 mensen zijn mannen. Alle mensen hebben willekeurige eigenschappen, enkel het geslacht is dus al bepaald.
Laat nu de mensen voortplanten.
De eerste helft mensen in de List zoeken een willekeurige partner van het andere geslacht in de andere helft lijst. En maakt hier een nieuwe mens mee. De man wordt meegegeven als parameter aan de Plantvoort methode van de vrouw.
Herhaal bovenstaande voor 10 generaties (merk op dat ouders dus vermoedelijk kinderen zullen maken met hun eigen kinderen/kleinkinderen. Niet over nadenken) en bekijk wat de resultaten zijn. Plaats deze simulatie in een static methode Simuleer die een List van mensen als parameter aanvaardt, alsook een getal dat aangeeft hoeveel generaties moet getest worden. Houdt bij iedere Mens die je aanmaakt om welke generatie het gaat.
Toon aan de gebruiker hoeveel de gemiddelde lengte is, hoeveel percent welke kleur ogen heeft, etc.
Maak een applicatie waarbij de gebruiker experimenten kan doen om te zien wat er gebeurt na x generaties.
Bijvoorbeeld:
Wat als mannen erg klein zijn, vrouwen erg lang
Wat als mensen met blauwe ogen steeds die kleur aan hun kinderen doorgeven, na hoeveel generaties heeft iedereen blauwe ogen
Introduceer mutaties tijdens de voortplanting. Iedere keer als er een nieuwe mens wordt aangemaakt tijdens Plantvoort bestaat er 10% kans dat een van de "regels" overtreden wordt (bv i.p.v. gemiddelde lengte wordt lengte van de mama genomen, of i.p.v. kleur van een van ouder krijgt kind bij mutatie altijd groene ogen, etc). Verzin zelf enkele mutatie regels.
Test je mutaties en verzin extra regels en pas toe in de Simulatiemethode.
Voeg een bool parameter toe aan de simulatiemethode om aan te geven of mutaties zijn toegestaan of niet, aslsook een int parameter om de kans van mutatie mee te geven (bijvoorbeeld 10 = 10%)
Voeg extra eigenschappen aan je Mens toe die je ook betrekt als genetische eigenschappen tijdens het voortplanten (denk aan haarkleur, allergieën of aantal armen).
Ter info
Volgende code toont hoe je je lijst kunt sorteren op Geslacht, veronderstellende dat de lijst mensen heet:
//using System.Linq (toevoegen bovenaan)
mensen = mensen.OrderBy(p => (int)p.Geslacht).ToList();
Opgelet : In deze opgave komen geen arrays van objecten voor.
Een goed mentale gezondheid – quality of life (Qal) - is even belangrijk als je fysieke gezondheid.
De firma "GetWeller" heeft je gevraagd om een prototype te maken van een QualityOfLife-diary app, waarin de gebruiker kan bijhouden hoe het met z’n mentale gezondheid is gesteld.
Je dient dit prototype in een C# console applicatie te maken zodat GetWeller kan zien of ze jouw firma willen inhuren om de volledige mobiele applicatie nadien te ontwikkelen.
DagboekEntry: deze bewaard telkens 1 dag van de gebruiker in het dagboek
QalAnalyzer: deze bevat een aantal hulpmethoden om de verzameling DagboekEntry’s te gebruiken.
OPGELET 1: niet alle zaken die je in de klasse zult zetten zal je mogelijk nodig hebben in de applicatie die je er rond gaat maken.
OPGELET 2: De hoofdmoot gebeurt in de QalAnalyzer methode CreateDiary. Lees dus zeker eerst de hele opgave. Indien je CreateDiary , en de andere methoden in QalAnalyzer, niet in de klasse krijgt, raad ik je aan deze in je hoofdprogramma te plaatsen (voor minder punten weliswaar) zodat je voort kunt.
Autoproperty IsInspired (bool) die bijhoudt hoe geïnspireerd de gebruiker die dag was
Property met private setter IsPrivate (bool) die aangeeft of deze entry als privé moet beschouwd worden
Fullproperty Description (string) die een beschrijving bevat van hoe de gebruiker zich voelde die dag:
Bij Get zal enkel de description worden teruggegeven als IsPrivate niet true is. Indien het wel om een privé entry gaat dan wordt de tekst ***PRIVATE*** teruggegeven.
Fullproperty Qal (int) deze kan enkel waarden tussen 0 en 100 krijgen.
*Indien de gebruiker een getal kleiner dan 0 instelt dan wordt de Qal op 0 ingesteld.
*Indien de gebruiker een getal groter dan 100 instelt dan wordt de Qal op 100 gezet.
MakePrivate: De enige manier om van buiten uit de IsPrivate van een DagboekEntry object aan te passen. De methode aanvaardt een bool die aangeeft of het object privaat moet gezet worden en geeft niets terug.
ResetEntry: deze methode vereist geen parameters en geeft niets terug.
Zet IsInspired op false, de Qal op 50 en de description leeg
ShowInfo: deze methode vereist geen parameters en geeft niets terug.
Output het object naar het scherm als volgt (tekst tussen vierkante haakjes wordt vervangen door de effectieve waarden:
Deze klasse bevat enkel static methoden, namelijk:
SummarizeDiary (15%):
Aanvaardt een array (of lijst) van DagboekEntry’s . Geeft niets terug.
Zal alle ShowInfo-methoden van iedere entry aanroepen zodat het volledige dagboek op het scherm komt
AnalyseDiary (25%):
Aanvaardt een array (of lijst) van DagboekEntry’s. Geeft niets terug.
Zal het gemiddelde IsInspired tonen wat de totale Qal is, rekeningen houdend met de privacy:
De totale Qal bevat de som van alle Qal’s in de DagboekEntry’s OP VOORWAARDE dat deze niét privé is (de privé Qals worden overgeslagen en niét meegerekend)
Het gemiddelde IsInspired is de som van alle DagboekEntry’s waar de IsInspired true was, ongeacht of deze privé was of niet, gedeeld door het totaal aantal elementen in de array.
De methode toont vervolgens deze twee getalen (totale niet privé Qal, gemiddelde IsInspired)
CreateDiary (60%) :
Aanvaardt geen parameters. Geeft een array (of lijst) van DagboekEntry’s terug.
Zal aan de gebruiker enkele vragen stellen en het ‘dagboek’ maken.
De werking van deze methode leggen we in volgende sectie uit.
Een dagboek is een array of lijst van DagboekEntry-objecten
Je toont nu telkens aan de gebruiker om de hoeveelste dag het gaat (starten van 1 ) en welke dag dat ook effectief is. Als het programma wordt uitgevoerd op zondag, dan zal er dus verschijnen:
Dag 1: Maandag
[info uit stap 2b]
Dag 2: Dinsdag
[info uit stap 2b]
…
Opmerking: de dagen mogen in het Engels verschijnen als jouw OS in die taal werd ingesteld.
De gebruiker dient nu steeds in te geven hoe hij zich voelde (description), of hij geïnspireerd was (IsInspired), de Qal score die dag (Qal) en of het om een private entry gaat.
Deze informatie wordt steeds in een DagboekEntry geplaatst en aan de array toegevoegd.
Deel uitvoer/invoer van de methode
Rise and shine
Het is nu 15:25
Hoeveel dagen wil je loggen in je dagboek?
3 //userinput
Dag 1: Monday
Hoe was je dag?
Zeer goed //userinput
Voelde je je geïnspireerd?(y/n)
y //userinput
Welke score geef je deze dag?
60 //userinput
Is dit een private entry?(y/n)
n //userinput
Dag 2: Tuesday
Hoe was je dag?
…
Het spel Magic The Gathering is een populair kaart/verzamel spel. We gaan een vereenvoudigde versie maken die ons zal toelaten om te ontdekken of we een bepaald wezen kunnen maken (casten) gegeven een bepaalde hoeveelheid land-kaarten.
Er zijn 2 soorten kaarten:
CreatureKaarten: deze wezens kan je enkel maken als je genoeg land hebt om de CastingCost te bepalen in mana (van een bepaalde kleur).
LandKaarten: ieder land produceert 1 mana van een specifieke type (kleur).
Wil je dus een wezen produceren dat 4 water(blauwe) mana vereist dan zal je 4 Islands nodig hebben (daar een Island 1 blauwe mana genereert)
We stellen deze voor in de klasse als een string, readonly property
"De casting cost": hoeveelheid mana die nodig is. In bovenstaande voorbeeld heb je 2 blauwe en 4 "kleurloze' mana nodig (kleurloos= gebruiker mag eender welke kleur kiezen).
In onze klasse stellen we de casting cost voor door 3 aparte readonly properties met namen:
ColoredTypeNeeded: is van het ManaType type (enum), readonly property (zie verder, bij Enum landen). Deze stelt de "hoofdkleur" van de kaart voort (Blauw in bovenstaand geval)
AmoundColoredTypeNeeded: type int om aan te geven hoeveel mana er nodig is van het ColoredTypeNeeded type (2 in bovenstaand geval).
AmountUncoloredTypeNeeded: ook een int om aan te geven hoeveel kleurloze mana er nodig is. (4 in bovenstaand geval)
OOP al goed in de vingers? Bekijk dan zeker de extra opgave voor dit stukje achteraan dit document.
SpecialAbilities: We stellen deze voor in de klasse als een string, readonly property.
FlavourText:
We stellen deze voor in de klasse als een string, readonly property
"Attack/Defense":
We stellen deze in de klasse voor als twee readonly int properties met private setters genaamd Attack en Defense.
Beide properties kunnen nooit lager dan 0 zijn (0 is wel toegelaten)
ChangeAttack: deze methode aanvaardt 1 bool en geeft niets terug. Als deze true is dan zal bij aanroep van de methode de Attack property met 1 verhoogd worden. Wanneer de boolfalse is zal de Attack property met 1 verlaagd worden.
Toonkaart: deze methode aanvaardt geen parameters en geeft niets terug. Aanroepen ervan zal een samenvatting van de kaart op het scherm tonen.
*******************************************************
Mahamoti Djinn (4 kleurloos, 2 Water mana)
*******************************************************
"Of royal blood among the spirits [etcetc]"
-------------------------------------------------------
Abilities: Flying
Attack: 5
Defense: 6
-------------------------------------------------------
Namelijk ten eerste de Mahamori Djinn van hierboven.
ColoredTypeNeeded: ManaType.Water, AmountColoredTypeNeeded: 2 en AmoundUncoloredTypeNeeded:4
Alsook een "KinderCatch" (merk ok dat deze kaart geen SpecialAbilities heeft en je deze property dus als een lege tekst mag voorstellen ("")). Deze kaart heeft dus 3 bos-mana en 3 kleurloze mana nodig.
ColoredTypeNeeded: ManaType.Bos, AmountColoredTypeNeeded: 3 en AmoundUncoloredTypeNeeded:3
Als derde deze schattige "Mountain Goat" die als SpecialAbility "Mountainwalk heeft".
ColoredTypeNeeded: ManaType.Vuur, AmountColoredTypeNeeded: 1 en AmoundUncoloredTypeNeeded:0
De gebruiker wordt gevraagd hoeveel landen hij per manatype heeft.
Aantal Water?
4 <-ingevoerd door gebruiker
Aantal Bos?
2 <-ingevoerd door gebruiker
Aantal Zon?
3 <-ingevoerd door gebruiker
etc.
Maak een List<LandKaart> lijst aan waarin je het juiste aantal LandKaart-objecten plaatst. Dus in voorgaande voorbeelden zullen er 4 Water landkaarten vooraan staan, gevolgd door 2 Bos, etc.
De gebruiker wordt gevraagd welk dier hij wilt maken. Hierbij worden de 3 eerder aangemaakt creature objecten (de djinn, de geit en de kindercatch) getoond d.m.v. ToonKaart methode van ieder object.
De gebruiker kan dan 1, 2 of 3 als invoer geven (foute invoer niet controleren)
De applicatie zal nu bekijken of je het gekozen dier kan maken. Hierbij zal de List<LandKaart> bekeken worden of dat er genoeg landen van het juiste type voor het gegeven dier aanwezig zijn.
Gebruik de CastTest methode om te controleren ofhet gevraagde dier kan gemaakt worden. Geef daarvoor als parameters de in stap 1 gemaakt LandKaarten-lijst mee alsook het in stap 2 gekozen dier-object.
Het resultaat van deze methode zal vervolgens gebruikt worden om een zinnetje op het scherm te tonen:
Dier kan gemaakt worden (indien bool true was)
of
Dier kan niet gemaakt worden (indien bool false was)
Nu dat het Suez-kanaal vastzit is het de moment voor de Antwerpse haven om de grootste haven van de wereld te worden. Jouw expertise werd ingeroepen om te helpen om de containerterminal te vernieuwen zodat verdachte containers sneller kunnen gevat worden en we zo het drugsprobleem indijken.
Het gewicht kan nooit onder 0 of boven 100 gezet worden.
Indien een foutieve waarde wordt meegegeven verschijnt er op het scherm “Fout gewicht. Ingesteld op 100” en wordt het gewicht op 100 ingesteld.
Telkens het Gewicht wordt aangepast wordt er 1 dag bij LaatstAangepast toegevoegd. Ongeacht of het om een geldige waarde ging of niet.
Tip: De logica is dat telkens het gewicht van de container wordt aangepast, dit een hele werkdag duurt.
Overloaded constructor die de Bedrijf, Beschrijving en Gewicht als parameters instelt. Voorts zet de constructor GemaaktOp en LaatsteAangepast op de huidige tijd en datum.
Methoden:
Ledig: deze zal de beschrijving van de container op “leeg” zetten en het gewicht op 0. Het bedrijf blijft!
InWerking: deze methode geeft een TimeSpan object terug dat bestaat uit het verschil tussen LaatsteAangepast en GemaaktOp.
AddContainer: deze methode geeft niets terug en aanvaardt 1 parameter van het type Container.
Indien de meegeven container van hetzelfde Bedrijf is als de container zelf, dan zal het volgende gebeuren.
Indien de som van de gewichten van beide containers samen minder dan 100 is dan zal het gewicht van de meegegeven container opgeteld worden bij die van de huidige container. De beschrijving van de huidige container zal bestaan uit de huidige beschrijving gevolgd door “ en [beschrijving meegegeven container]” . Als dus de meegegeven container (de parameter) als beschrijving “Eten” had en de huidige container “Water” dan wordt de beschrijving van de huidige container “Water en Eten”.
Vervolgens wordt de meegegeven container leeg gemaakt met de Ledig methode.
Als de som van beide containers bij samenvoegen boven de 100 zou komen dan verschijnt er een tekst "Kan container niet adden. Dit zou gewicht boven de 100 brengen" en stopt de methode.
Als de bedrijven verschillend zijn van beide container bij samenvoegen boven de 100 zou komen dan verschijnt er een tekst "Containers zijn niet van zelfde bedrijf. Kan niet samenvoegen." en stopt de methode.
Deze klasse heeft één static methode ScanContainer.
Deze methode geeft een string terug en aanvaardt 1 Container object als parameter.
Deze methode zal een tekstueel rapport opstellen van de meegegeven container. Dit rapport ziet er als volgt uit en wordt als string door de methode teuggegeven:
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=70
----------------
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=80
----------------
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=90
----------------
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
Fout gewicht. Ingesteld op 100
---CONTAINERREPORT TIM NV---
Lading:Graan en Water
Gewicht lading=100
*****Deze container heeft verdacht veel gewichtsveranderingen ondergaan
----------------
{% hint style="info" %}
Wil je de leerstof op een andere manier leren gebruiken? Bekijk dan eens de Corona Files oefeningen. Merk op dat de corona files niet zo diepgaand zijn als de andere oefeningen, maar mogelijk wel boeiender.
Het is wel zo dat iedere week voort werkt op hetgeen je de missie ervoor hebt gemaakt waardoor je dus finaal een lekker groot project zal hebben.
Maak bovenstaande klassenhierarchie na. Animal is de parentklasse , mammal en reptile zijn childklassen van Animal en zo voort.
Verzin voor iedere klasse een property die de parent klasse niet heeft. (bv Animal heeft "BeweegVoort", Reptile heeft "AantalSchubben", etc).
Voorzie in de klasse Animal een virtual methode ToonInfo die alle properties van de klasse op het scherm zet. De overgeërfde klassen overriden deze methode door de extra properties ook te tonen (maar gebruik base.ToonInfo om zeker de parentklasse werking te bewaren).
Maak nu van iedere klasse een object en roep de ToonInfo methode van ieder object aan.
Plaats deze dieren nu in een List<Animal> en kijk wat er gebeurt als je deze met een foreach aanroept om alle ToonInfo-methoden van ieder dier te gebruiken.
In deze opdracht ontwerp je een systeem waarin dranken niet alleen dorst lessen, maar ook mysterieuze krachten bezitten. Van gewone drankjes tot zeldzame elixers — elke slok telt! 🧪✨
Ontwerp een systeem waarin verschillende dranken een magische kracht”* hebben.
Maak een basis‑klasse Drank met:
Een property voor de naam van de drank.
Een constructor die de naam instelt.
Een virtuele methode BerekenKracht() die een standaard krachtwaarde (50) teruggeeft.
Maak een sub‑klasse Elixer die erft van Drank en een extra property IsZeldzaam bevat.
Overschrijf de methode BerekenKracht() zodat eerst de basiskracht (verkregen via base.BerekenKracht()) wordt berekend en vervolgens een bonus wordt opgeteld: +20 als IsZeldzaamtrue is, anders +10.
Implementeer een hoofdprogramma waarin je meerdere drankobjecten (bijv. een gewoon drankje en een zeldzaam elixer) aanmaakt en hun berekende kracht op de console toont.
Maak een basisklasse Patient die een programma kan gebruiken om de doktersrekening te berekenen.
Een patiënt heeft:
een naam
het aantal uur dat hij in het ziekenhuis heeft gelegen
Een virtual methode BerekenKost zal de totaalkost berekenen en teruggeven. Deze bestaat uit 50euro+ 20euro per uur dat de patiënt in het ziekenhuis lag.
Maak een methode ToonInfo die steeds de naam van de patiënt toont gevolgd door het aantal uur en z'n kosten.
Maak een specialisatieklasse VerzekerdePatient. Deze klasse heeft alles dat een gewone Patient heeft, echter de berekening van de kosten zal steeds gevolgd worden door een 10% reductie.
Voeg een HiddenBookmark klasse toe aan je bestaande Bookmark Manager applicatie van vorige hoofdstuk.
De HiddenBookmark is een Bookmark klasse die de ToonSite methode override door VOOR en NA dat de site op het scherm werd getoond er de tekst **********INCOGNITO MODE************ getoond wordt
Test wat er gebeurt als je al je bookmarks vervangt door HiddenBookmarks.
We maken een klasse Ball die via Update en Draw zichzelf over het consolescherm beweegt. Enkele opmerkingen:
We maken sommige variabelen protected zodat later de overgeërfde klassen er aan kunnen
Een static methode CheckHit laat ons toe te ontdekken of twee Ballobjecten mekaar raken
class Ball
{
public int X { get { return x; } }
public int Y { get { return y; } }
private int x = 0;
private int y = 0;
protected int vx = 0;
protected int vy = 0;
protected char drawChar = 'O';
protected ConsoleColor drawColor = ConsoleColor.Red;
public Ball(int xin, int yin, int vxin, int vyin)
{
x = xin;
y = yin;
vx = vxin;
vy = vyin;
}
public void Update()
{
x += vx;
y += vy;
if (x >= Console.WindowWidth || x < 0)
{
vx *= -1;
x += vx;
}
if (y >= Console.WindowHeight || y < 0)
{
vy *= -1;
y += vy;
}
}
public void Draw()
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = drawColor;
Console.Write(drawChar);
Console.ResetColor();
}
static public bool CheckHit(Ball ball1, Ball ball2)
{
if (ball1.X == ball2.X && ball1.Y == ball2.Y)
return true;
return false;
}
}
We maken nu een rudimentair spel waarin de gebruiker een bal moet proberen te raken.
static void Main(string[] args)
{
Console.CursorVisible = false;
Console.WindowHeight = 20;
Console.WindowWidth = 30;
Ball b1 = new Ball(4, 4, 1, 0);
PlayerBall player = new PlayerBall(10, 10, 0, 0);
while (true)
{
Console.Clear();
//Ball
b1.Update();
b1.Draw();
//SpelerBall
if (Console.KeyAvailable)
{
var key = Console.ReadKey();
player.ChangeVelocity(key);
}
player.Update();
player.Draw();
//Check collisions
if (Ball.CheckHit(b1, player))
{
Console.Clear();
Console.WriteLine("Gewonnen!");
Console.ReadLine();
}
System.Threading.Thread.Sleep(100);
}
}
Kan je dit uitbreiden met?
Ballen met andere eigenschappen
Meerdere ballen die over het scherm vliegen (benodigdheden: array )
Meerdere levels
Score gebaseerd op tijd die gebruiker nodig had om bal te raken (benodigdheden: teller die optelt na iedere Sleep)
PRO: collision detection tussen de ballen
Nu je overerving in de vingers krijgt, is het tijd om de ingebouwde "Class designer" van Visual Studio eens te bekijken. Volgende kennisclip toont hoe je deze handige tool kunt installeren en gebruiken:
Class diagram en de class designer in Visual Studio
Voeg ToString toe aan bestaande van volgende projecten. Ik raad aan dat je dit even test in een nieuwe applicatie waarin je de bestaande klasse even toevoegt en niet de hele main overneemt.
Implementeer de ToString() methode in zowel de Bookmark als de HiddenBookmark klasse. Bij bookmark moet de output bestaan uit de titel van de site, gevolgd door de url tussen haakjes, bv:
Google (www.google.com)
Bij HiddenBookmark wordt er achteraan nog "---HIDDEN---" gezet:
Reddit (www.reddit.com) ---HIDDEN---
Zorg ervoor dat er géén dubbele code in HiddenBookmark staat (tip: base()).
Maak een klasse Boek en gebruik auto-properties voor de velden:
ISBN (long)
Titel (string)
Auteur (string)
Maak voorts een full property voor Prijs (double)
Maak een child-klasse die van Boek overerft genaamd TekstBoek. Een TekstBoek heeft één extra property:
SchoolGraad (int)
Maak een child-klasse die van Boek overerft genaamd KoffietafelBoek. Deze klasse heeft geen extra velden.
Voorts kunnen boeken "opgeteld" worden om als omnibus uitgebracht te worden. De titel wordt dan "Omnibus van X". waarbij X de Auteurs bevat, gescheiden met een komma. De prijs van een Omnibus is steeds de som van beide boeken gedeeld door 2. Schrijf een static methode TelOp die twee Boek objecten als parameter aanvaardt en als returntype een nieuw Boek teruggeeft. Deze methode voeg je toe aan de klasse Boek
In beide child-klassen, override de Prijs-setter zodat:
a) Bij TekstBoek de prijs enkel tussen 20 en 80 kan liggen
b) Bij KoffietafelBoek de prijs enkel tussen 35 en 100 kan liggen
PRO: Bekijk gerust de appendix indien je wilt weten hoe je de + operator kunt overriden om boeken op te tellen.
Zorg ervoor dat boeken de ToString overriden zodat je boekobjecten eenvoudig via Console.WriteLine(mijnBoek) hun info op het scherm tonen. Ze tonen deze info als volgt: "Titel - Auteur (ISBN) _ Prijs" (bv The Shining - Stephen King (05848152) _ 50)
Maak boeken aan van de 3 klassen, toon dat de prijs niet altijd zomaar ingesteld kan worden.
Maak enkele klassen die een bank kan gebruiken (of hergebruik je BankManager code) :
Abstracte klasse Rekening: deze bevat een methode VoegGeldToe en HaalGeldAf. Het saldo van de rekening wordt in een private variabele bijgehouden (en via de voorgaande methoden aangepast) die enkel via een read-only property kan uitgelezen worden. Voorts is er een abstracte methode BerekenRente de rente als double teruggeeft.
Een klasse BankRekening die een Rekening is. De rente van een BankRekening is 5% wanneer het saldo hoger is dan 100 euro, zoniet is deze 0%.
Een klasse SpaarRekening die een Rekening is. De rente van een SpaarRekening bedraagt steeds 2%.
Een klasse ProRekening die een SpaarRekening is. De ProRekening hanteert de Rente-berekening van een SpaarRekening (base.BerekenRente) maar zal per 1000 euro saldo nog eens 10 euro verhogen.
Schrijf deze klassen en toon de werking ervan in je main.
Maak een abstracte klasse GeometricFigure. Iedere figuur heeft een hoogte, breedte en oppervlakte. Maak autoproperties voor van Hoogte en Breedte. De Oppervlakte is een read-only property want deze wordt berekend gebaseerd op de hoogte en breedte. Deze berekening gebeurt in de methode BerekenOppervlakte: deze roep je met andere woorden aan in de getter van Oppervlakte en dat resultaat geeft de getter terug
Let er dus op dat Oppervlakte enkel een getter heeft. Een setter schrijven zou vreemde bugs geven: wat als de gebruiker de Oppervlakte van de figuur zo aanpast, maar wel andere hoogte en breedte heeft ingesteld? Je zou dan een foute oppervlakte krijgen daar die niet berekend wordt.
Voorzie een abstracte methode BerekenOppervlakte die een double teruggeeft.
Maak 3 klassen:
Rechthoek: erft over van GeometricFigure. Oppervlakte is gedefinieerd als breedte * hoogte.
Vierkant: erft over van Rechthoek. Voorzie een constructor die lengte en breedte als parameter aanvaard: deze moeten gelijk zijn, indien niet zet je deze tijdens de constructie gelijk. Voorzie een 2e constructor die één parameter aanvaardt dat dan geldt als zowel de lengte als breedte. Deze klasse gebruikt de methode BerekenOppervlakte van de Rechthoek-klasse.
Driehoek: erft over van GeometricFigure. Oppervlakte is gedefinieerd als breedte*hoogte/2.0.
Maak een applicatie waarin je de werking van deze klassen aantoont
Maak een console-applicatie waarin je een zelfverzonnen abstract klasse Dier in een List kunt plaatsen. Ieder dier heeft een gewicht en een methode Zegt (die abstract is) die het geluid van het dier in kwestie op het scherm zal tonen. Maak enkele childklassen die overerven van Dier en uiteraard de Zegt methode overriden.
Plaats enkele dieren in de nieuw aangemaakt lijst.
Vervolgens verschijnt er een menu Wanneer de gebruiker 'q' kiest stopt het programma.Het keuze menu heeft volgende opties:
Dier verwijderen , gevolgd door de gebruiker die invoert het hoeveelste dier weg moet uit de List.
Diergewicht gemiddelde: het gemiddelde van alle dieren hun gewicht wordt getoond
Dier praten: alle dieren hun Zegt() methode wordt aangeroepen en via WriteLine getoond
Opnieuw beginnen: de List wordt leeggemaakt en het programma zal terug van voor af aan beginnen. Waarbij de lijst terug gevuld wordt met enkele start dieren.
Een President is een minister maar met 1 extra property met private setter: hij heeft een Teller (autoproperty type int) die start op 4 alsook een methode JaarVerderdie deze teller bij iedere aanroep met 1 verlaagt.
1 president object die aan de private president variabele wordt toegekend
Een List<Minister> object waarin tussen de 1 tot en met 5 ministers in staan: de eerste minister in de lijst wordt toegewezen aan de private eerste minister variabele. De overige ministers in de lijst worden aan de private lijst van ministers toegewezen.
Deze methode zal enkel iets doen indien er geen president in het land is (null). Indien er reeds een regering is dan zal er een foutboodschap verschijnen.
Deze methode aanroepen zal de JaarVerder aanroepen op de president indien deze er is (en dus niet null is). Deze methode controleert ook of de Teller van de president na deze aanroep op 0 staat. Als dat het geval is dan worden alle ministers en president in het land op null gezet.
Controleer je klasse Land door enkele ministers en een president te maken en deze in een object van het type Land via MaakRegering door te geven. Test dan wat er gebeurt indien je enkele malen JaarVerder op het land aanroept.
Maak klasse VerkiezingsUitslag. Deze klasse heeft een default constructor die volgende twee properties random waarden zal geven:
Een full property met private set VerkozenPresident van het type President.
Een full property met private set VerkozenMinisters van het type List<Minister>.
Maak in je hoofdprogramma een VerkiezingsUitslag-object aan en gebruik deze om de MaakRegeringmethode van je Land van de nodige informatie te voorzien.
Maak een klasse Moederbord die een, je raadt het nooit, moederbord van een computer voorstelt. Kies een van de vele moederborden die je online vindt (enkele voorbeelden) en bekijk uit welke delen een moederbord bestaat ('heeft een').
Maak voor ieder deel een aparte klasse. Voorzie vervolgens via compositie de nodige objecten in je moederbord. Denk er aan dat je bijvoorbeeld 2 (of 4) RAM-slots hebt en dus hier ofwel een array moet voorzien van het type List<RAM>, oftewel twee aparte delen RAMSlot1 en RAMSlot2.
Maak een methode TestMoederbord in de klasse Moederbord. Wanneer je deze aanroept zal deze weergeven welke onderdelen nog leeg zijn (==null).
Iedere module moet via een property langs buiten ingesteld worden. (beeld je in dat je effectief een moederbord ineenknutselt):
Moederbord Z390E_GAMING = new Moederbord();
Z390E_GAMING.AGP= new AGPSlot("GeForceRTX2080");
Z390E_GAMING.CPU= new CPUSlot("IntelCorei9_9900K");
//etc.
Kan je zelf een computer samenstellen door enkele objecten van verschillende types aan te maken en deze aan je moederbord-object toe te wijzen?
In deze oefening werk je een vereenvoudigd model uit van een RPG-spelwereld.
Spelers kunnen reizen door verschillende werelden (Worlds), waarin zich verschillende zones (Zones) bevinden, zoals een mystiek bos of een verzengende woestijn.
In elke zone kunnen voorwerpen (Items) gevonden worden, zoals magische wapens, geneeskrachtige drankjes of schatten.
Je modelleert de relaties tussen deze elementen, waarbij:
Een World verantwoordelijk is voor het beheren van zijn Zones.
Elke Zone verantwoordelijk is voor het beheren van de Items die erin liggen.
Items zelfstandig bestaan (ze kunnen later bijvoorbeeld ook door spelers meegenomen worden).
Een Zone is een deelgebied binnen een wereld, bijvoorbeeld een magisch bos of een ruïne.
Properties:
Name (string): de naam van de zone.
DifficultyLevel (int): hoe moeilijk het is om in deze zone te overleven (op schaal bv. 1–10).
Items (List): de voorwerpen die in deze zone te vinden zijn. (tip: dit is aggregatie: de zone bevat verwijzingen naar bestaande items, maar vernietigt ze niet automatisch als de zone wordt verwijderd.)
Methoden:
AddItem(Item item): voegt een item toe aan de lijst van beschikbare voorwerpen in deze zone.
GetValuableItems(int minimumValue): geeft alle items terug die minstens zoveel waard zijn als de opgegeven minimumwaarde.
PrintZoneInfo(): toont de gegevens van de zone, inclusief een opsomming van de items.
In het bordspel Risk heeft ieder Land-object volgende eigenschappen:
Naam van het land
Lijst met buurlanden
Leger dat in het land gestationeerd staat.
De referenties in deze beide zijn aggregaties: wanneer het land verdwijnt dan verdwijnen niet de buurlanden en ook niet de legers die er op gestationeerd zijn (ze kunnen gewoon naar een ander land bewegen).
Voorts implmenteert het de ToString methode en zal het de informatie oplijsten als volgt:
*[Naamland] (Buurlanden:[oplijsten buurlanden, enkel de naam]) . Grootte gestationeerd leger: *[grootte van het leger]
Maak een klasse Bordspel dat een lijst van Land-objecten bevat (dit is compositie: wanneer het bordspel in brand wordt gestoken dan zijn ook de landen er op weg).
Maak een vereenvoudigde voorstelling van de landkaart met de Bordspel klasse, enkele Land-objecten en enkele legers.
Voeg aan de Bordspel klasse een methode "ToonKaart": deze methode zal de landen in de lijst onder elkaar schrijven (via de ToString methode van Land).
Maak een methode VerplaatsLeger dat 2 referenties naar 2 landen aanvaardt. Wanneer de aanroept gebeurt zal eerst gecontroleerd worden of het eerste land een leger bevat (zoniet wordt er een exception opgeworpen). Indien dit in orde is dan zal het leger in kwestie verhuizen naar 2e land op voorwaarde dat daar ook geen leger al is. Als dat wél het geval is dan wordt het leger in het eerste land verwijderd, en wordt de capaciteit van het 2e leger verhoogd met die van het eerste leger.
Gebruik compositie én overerving om een klasse Huis te voorzien van enkele kamers, waarbij iedere kamer een klasse op zich is (denk aan BadKamer, Salon, etc). Alle kamers erven over van de klasse Kamer. Iedere kamer heeft een oppervlakte (in vierkante meter), een naam en prijs. Standaard is de prijs van een kamer 400euro, maar mogelijke child-klassen zullen deze property soms overriden. De Prijs is een readonly property (zonder setter, en heeft ook geen achterliggende instantievariabele).
Maak minstens volgende klassen:
Badkamer: kost 500 euro
Gang: kost 10euro per vierkante meter dat deze kamer groot is
Salon: kost 300 euro indien er geen schouw aanwezig is (via bool bijhouden) anders 500euro
De klasse Huis heeft een lijst van kamers. De klasse heeft ook een methode BerekenPrijs die de totale prijs van het huis berekent gebaseerd op de prijzen van iedere kamer in de lijst.
Test je klasse door enkele huizen te maken en er enkele kamers in te plaatsen (bepaal zelf hoe je de kamers aan het huis toevoegt: via methode, constructor, etc) en vervolgens de prijs ervan te tonen.
Voorzie een Teken methode die een huis kan tekenen, gebruikmakend van de Teken-methoden van de kamers. Hiervoor dien je een X en Y coördinaat per , alsook lengte en breedte per huis én kamer te hebben zodat je deze op de juiste plekken op het scherm kan plaatsen.
Kan je ervoor zorgen dat een architect nieuwe kamers kan toevoegen en verwijderen?
Ontwerp een applicatie waarin diverse typen vliegende voertuigen meedoen aan een luchtvaartshow en hun unieke vlieg‑gedrag demonstreren. In deze opgave werk je met inheritance, polymorfisme, het base‑keyword, de Dictionary‑klasse en statische methoden.
Maak een basisklasse Vliegtuig met een property ModelNaam en een constructor die deze initialiseert.
Implementeer een virtuele methode Vlieg() die een standaardbericht naar de console schrijft (bijvoorbeeld "Het vliegtuig [ModelNaam] stijgt op.").
Voeg een static instantievariabele toe: een Dictionary<string, Vliegtuig> waarin alle aangemaakte vliegtuigobjecten geregistreerd worden (gebruik de modelnaam als sleutel).
Implementeer een statische methode, ToonVliegtuigenRegister(), die alle geregistreerde objecten uit de dictionary uitleest en hun details (zoals modelnaam en type voertuig) weergeeft op het scherm.
Subklassen:
Raket:
Laat Raket overerven van Vliegtuig.
Overschrijf de methode Vlieg() zodat een uniek bericht wordt weergegeven, namelijk "De raket [ModelNaam] schiet de ruimte in!"”"
Helikopter:
Laat Helikopter erven van Vliegtuig en voeg een extra property toe, RotorSnelheid.
Overschrijf de methode Vlieg() zodat eerst het standaardgedrag van Vliegtuig wordt aangeroepen (met base.Vlieg()) en daarna een extra bericht wordt getoond met de huidige rotor snelheid (namelijk "De helikopter [ModelNaam] draait met een rotor snelheid van [RotorSnelheid] RPM.").
Bordspelen zoals Ganzenbord of Monopoly zijn goede oefeningen om je polymorfisme mee te oefenen. Het speelbord is niet meer dan een lijst van objecten, met ieder vakje een object in die lijst. Echter, sommige vakjes kunnen meer dan andere en je lijst bevat dus objecten van verschillende child-klassen die allemaal overerven van een basisklasse Vakje of iets dergelijks. Volgende opgave uit een oud examen toont dit. Kan je deze oefening maken?
{% hint style="info" %}
Volgende opgave komt uit de vaardigheidsproefopdracht voor 2e zit examen van dit vak (OOP) in augustus 2021.
De kinderen van meneer Dams en Van Camp spelen graag Ganzenbord. Laatst toen we speelden vroegen ze zich af of mijn studenten eigenlijk ganzenbord zouden kunnen programmeren? "Uiteraard!" antwoordde meneer Dams. "Weliswaar een vereenvoudigde versie, maar toch. Ze zouden dat wel kunnen, ja", vulde hij fier aan.
En hier zit je nu dus, opgescheept met het programmeren van de basisfunctionaliteit van ganzenbord voor 1 speler (geen flauw benul hoe ganzenbord werkt? Geen probleem! Alles wordt duidelijk doorheen de opgave!)
Ganzenbord, the single player edition, wordt gespeeld door één speler die moet proberen zo ver mogelijk te geraken op een traject van vakjes. Sommige vakjes doen iets met de speler wanneer deze op het vakje belandt (bijvoorbeeld een stapje vooruit), anderen doen niets.
Het bord wordt aan de start van ieder spel random aangemaakt. De speler moet een dobbelsteen werpen om te weten hoeveel stappen z'n pion vooruit zal gaan. De speler verdient punten hoe verder hij geraakt.
Het spelbord zal opgebouwd worden door een reeks van speelvakjes. Daarom maken we eerst dit vakje.
Een vakje wordt gedefinieerd door:
Een read-only int-property BeweegVakjes (met private set): deze eigenschap geeft aan hoeveel vakjes vooruit (positief) of achteruit (negatief) de speler zal gaan als op dit vakje wordt geland.
Een default constructor die de BeweegVakjes instelt op een waarde als volgt:
30% kans op +1 of +2
20% kans op -1 of -2
50% kans op 0
Een virtuele methode ToonVakje dat op de huidige locatie van de cursor in de console de BeweegVakjeswaarde van het vakje op het scherm schrijft. Indien de waarde positief of 0 is, toon je dit met een + voor. Bijvoorbeeld: +2 of +0. Een negatief toon je met de - , zoals -2.
Deze methode zal de speler voortbewegen op het bord en laten weten of de speler het einde heeft gehaald heeft of niet.
De speler kan een getal (het getal dat hij met de dobbelsteen verderop zal rollen) aan deze methode meegeven zodat het volgende gebeurt:
De pionIndex wordt verhoogd met het getal dat wordt meegeven, vervolgens:
Indien pionIndex hierdoor hoger wordt dan 9 en dus voorbij het laatste vakje wordt gegaan, dan wint de speler en wordt eerst de HuidigeScore met 10 verhoogd en wordt vervolgens true teruggegeven om aan te geven dat de speler gewonnen is.
Indien pionIndex eindigt op een getal 8 of lager, dan gebeurt het volgende:
In de lijst van SpeelVakje-objecten wordt gekeken op welk vakje de speler is aangekomen. De BeweegVakjes waarde van dit vakje wordt bijgeteld of afgetrokken van pionIndex. Dit wordt de nieuwe locatie van de speler. Er gebeurt niets meer na het belanden op dit nieuwe vakje (ook al is het een vakje waar vooruit of achteruit zou moeten gegaan worden).
De methode geeft false terug indien pionIndex terug een getal tussen 0 en 8 wordt, anders true indien hoger dan 8 (hij is dan gewonnnen-. Indien de speler op een index onder 0 belandt wordt false teruggegeven, wordt de score met 10 verlaagd én wordt de pionIndex finaal op 0 teruggezet (reset), ongeacht waar de speler op negatief belandde.
Deze methode zal de 10 vakjes naast elkaar op het scherm visualiseren door de lijst SpeelVakjes te overlopen en van ieder object de ToonVakje methode aan te roepen. Vervolgens wordt de pionIndex locatie gebruikt om dat vakje op het scherm te overschrijven met een 'T'
Indien de speler dus op index 3 (het vierde vakje) zit van een willekeurig bord, dan kan de output zijn:
-1+2+1-T+0+0-2+1+1+0
Dus het eerste vakje heeft waarde -1, het volgende 2, het derde 1, het vierde zien we niet want daar staat het mannetje (het was was blijkbaar een negatief vakje) en zien we een T, dan krijgen we twee vakjes met waarde 0.
Een loop wordt gestart die blijft duren tot de speler aan het einde geraakt. Deze loop doet het volgende:
Het spelbord wordt getoond mbv van de TekenBord methode.
Een nieuw getal wordt met de Rol methode van de dobbelsteen gerold. Dit getal wordt op het scherm getoond , onder het spelbord Je rolde 2
Het gerolde getal wordt aan de BeweegPion-methode meegeven en het resultaat van die methode wordt gebruikt om te bepalen of de loop nog een iteratie zal doen of niet.
De loop pauzeert nu tot de gebruiker op enter duwt.
Het scherm wordt leeggemaakt.
Finaal wordt de HuidigeScore van de speler getoond.
Voeg volgende uitbreidingen toe nadat je een werkend geheel hebt.
Maak een klasse KleurVakje dat overerft van SpeelVakje
Dit vakje doet alles wat een gewoon vakje doet, het zal enkel de ToonVakje method aanvullen zodat het huidige vakje een rode achtergrond met witte letters heeft indien de BeweegVakjes waarde negatief is. Anders groen met zwarte letters bij positieve of waarde 0.
Aan de start van het spel wordt aan de speler gevraagd of hij de kleuren of zwartwit versie van het spel wil spelen.
Voeg een overloaded constructor aan GanzenBord toe die een bool aanvaardt. Deze bool geeft aan of de speler een kleuren of klassiek zwart/wit speelbord wil gebruiken. Afhankelijk van deze parameter wordt dan het juiste soort vakjes in de ``SpeelVakjes`lijst geplaatst.
Bij het opstarten van het spel vraag je aan de gebruiker of hij de kleur of de zwartwit versie van Ganzenbord wil spelen.
Begin aan het all-in-project "Map Maker". Stop aan de sectie interfaces (die je pas in volgend hoofdstuk zult leren gebruiken). Je zal in dit project dingen herkennen die je eerder al in de "Een eigen huis" oefening hebt moeten maken.
{% hint style="info" %}
Deze oefening gaat erg ver voorbij de leerstof van dit boek en is enkel bedoeld voor diegene die 'above and beyond' willen gaan in hun kennis.
Tot hiertoe hebben we altijd gepraat over enerzijds objecten, en anderzijds methoden. Twee zaken die wel een relatie met elkaar hebben (een klasse kan methoden hebben, een methode kan objecten als parameter of return type hebben). Maar wat als ik je vertel dat je ook methoden als objecten kunt gebruiken. Het concept "delegate" laat ons toe om methoden als parameters doorheen een applicatie door te geven. Hier een droog, maar duidelijk voorbeeld (bron)
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
static void Main(string[] args)
{
MyDelegate del = MethodA; //same as MyDelegate del = new MyDelegate(MethodA);
del("Hello world");
}
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
Vanaf nu kan je de variabele del als object gebruiken én aanroepen:
Omdat delegates al wat oldschool zijn geworden, heeft .NET ook al vele jaren wat meer generieke (en dus bruikbaardere) versies hiervan, namelijk Action<T> en Func<T>. De werking hiervan legt deze gekende man stap voor stap uit in deze blog.
Kan je de hele tekst volgen en de gemaakte finale oefening uitbreiden naar een echte "applicatie"?
Gebruik je Rechthoek-klasse uit de Figuren oefening die je eerder hebt aangemaakt. Maak een List aan waarin je een 10 rechthoek-objecten plaatsen, allen met een verschillende grootte. Zorg ervoor dat je nu je rechthoeken met de Sort()-methode kan sorteren op oppervlakte.
Toon de werking aan in een klein voorbeeld programma.
1 methode BerekenFootprint heeft die een int teruggeeft en geen parameters nodig heeft
1 methode VerlaagFootprint die niets teruggeeft en geen parameters nodig heeft
Breidt de volgende klassen met de interface uit:
De carbon footprint van een huis is gebaseerd op het volume van het huis in kubieke meter maal 10.
De carbon footprint van een fabriek is gebaseerd op het aantal werknemers maal 100.
De carbon footprint van een auto is gebaseerd op het merk
Het verlagen van de footprint in iedere klasse verzin je zelf (door bijvoorbeeld bij het huis de factor 10 met 1 te verlagen).
Zorg ervoor dat van iedere klasse de footprint kan bevraagd worden (maak/verzin dus de nodige properties per klasse om dit te bereken). De klasse plant moet je niet aanpassen.
Plaats van iedere klasse 2 objecten in een gemeenschappelijke lijst en zorg ervoor dat:
de footprint van alle objecten getoond wordt (planten worden overgeslagen)
de gemiddelde footprint van alle objecten (ook planten worden meegeteld) berekend
toont welk object de hoogte footprint heeft
van alle objecten de footprint kan verlaagd worden
Shadow Pokémon zijn een speciaal ras Pokémon (zie hier) en kunnen "purified" worden op verschillende manieren. Maak een interface IShadow die een methode Purify heeft. Verzin enkele Pokémon die Shadow Pokémon zijn, geef ze de interface, en verzin manieren hoe ze purified kunnen worden (bv door hun HP op -1 te zetten). Kan je door je lijst van Pokémon gaan enkel de Shadow Pokémon op het scherm tonen?
Vervolledig het all-in-project "Map Maker". Inclusief interfaces en is/as .Kan je zelf extra zaken toevoegen zoals andere kamers, andere functionaliteit, etc.
Zie onderaan pagina voor minimale klasse-hiërarchie en interfaces.
Maak een spel dat als volgt werkt:
De speler dient met zijn pion de overkant van het veld te bereiken.
Het veld bestaat uit 20 bij 20 vakjes. Op ieder vakje kan maximum één mapelement staan:
De speler zelf
Een monster
Een rots
Een speler kan niet door rotsen of monsters wandelen.
Een speler kan in zijn beurt telkens één vakje bewegen OF naar rechts schieten:
Indien geschoten wordt dan zal het mapelement op het vakje rechts van de speler vernietigd worden (rots of monster)
Monsters kunnen ook bewegen. In de beurt van de monsters beweegt ieder monster in een willekeurige richting indien er geen rotsen of spelers LINKS van het monster staan.
Indien er WEL een rots of speler LINKS van het monster staat dan schiet het monster en vernietigd het de speler of rots.
Enkel RockDestroyer monsters kunnen schieten. De setup van het spel bestaat uit volgende stappen:
Maak een 20 bij 20 array aan en plaats bepaalde hoeveelheid monsters en rotsen op de kaart, behalve op kolom 0.
Plaats de speler op de plek 0,10 in de array (midden van kolom 0)
Doorloop de volgende stappen tot er winnaar is
Iedere beurt van het spel bestaat uit volgende stappen:
Vraag speler om input (bewegen in 1 van de 4 richtingen OF schieten)
Voer actie van speler uit
Kijk of speler overkant van kaart heeft bereikt, zo ja: gewonnen!
Beweeg ieder monster op de kaart in een willekeurige richting
Beweeg iedere RockDestroyer OF laat RockDestroyer schieten
Stel de speler voor door een X, een rots door O , een monster door M een RockDestroyer door D.
{% hint style="info" %}
Je zal de meeste logica in je Main of een Manager klasse moeten plaatsen. De Speler klasse bijvoorbeeld kan niet beslissen at een monster moet doen, dat zou willen zeggen dat de speler als jet ware " in het monster" beslissingen kan maken, wat tegen het principe van OOP zou zijn.
Maak een applicatie die een gebruiker in staat stelt om zijn/haar boekencollectie te beheren. De boekengegevens worden opgeslagen in een tekstbestand op de computer. De gebruiker moet boeken kunnen toevoegen, verwijderen, en de volledige lijst van boeken kunnen bekijken.
De applicatie moet de volgende menu-opties bieden:
Een nieuw boek toevoegen
Een boek verwijderen
Alle boeken weergeven
Programma afsluiten
Elke regel in het tekstbestand (boeken.txt) representeert een boek in het volgende formaat: Titel;Auteur;Jaar
Bijvoorbeeld:
De Hobbit;J.R.R. Tolkien;1937
Harry Potter en de Steen der Wijzen;J.K. Rowling;1997
Het Leven van Pi;Yann Martel;2001
Op deze site vind je de top 100 films ooit volgens IMDB. Download het bestand en gebruik het om een applicatie rond te ontwikkelen. De applicatie toont een menu'tje met volgende functionaliteiten:
Top 100 titels tonen.
Zoeken naar een titel (of deel ervan) en dan tonen op welke plek de titel staat.
Voor een nummer tussen 1 en 100 in en open vervolgens de browser (zoek zelf op hoe dit kan mbv Process) naar de bijhorende IMDB-pagina van die film. Je gebruikt hiervoor het id van de film, bv: "https://www.imdb.com/title/tt0111161/" indien je de pagina van The Shawnshank Redemption nodig hebt.
Maak een applicatie die de headerinformatie van een bitmap-afbeelding binair inleest en de basisinformatie ervan toont. Je gaat de hoogte, breedte en bitdiepte van de afbeelding tonen aan de gebruiker. De gebruiker kan zelf ingeven welk bitmap (.bmp)-bestand moet ingelezen worden.
Een BMP-header bevat veel details, maar voor deze opdracht richten we ons op de volgende informatie:
Breedte van de afbeelding: bytes 18-21 (4 bytes, Little Endian)
Hoogte van de afbeelding: bytes 22-25 (4 bytes, Little Endian)
Bitdiepte van de afbeelding: bytes 28-29 (2 bytes, Little Endian)
Ter info de volledige structuur van de BMP header (eerste 54 bytes):
BMP Signature: bytes 0-1 (2 bytes)
File Size: bytes 2-5 (4 bytes)
Reserved: bytes 6-9 (4 bytes)
Data Offset: bytes 10-13 (4 bytes)
DIB Header Size: bytes 14-17 (4 bytes)
Width: bytes 18-21 (4 bytes)
Height: bytes 22-25 (4 bytes)
Planes: bytes 26-27 (2 bytes)
Bit Depth: bytes 28-29 (2 bytes)
Tips:
De ReadBytes methode van een BinaryReader aanvaardt een int als parameter om aan te geven hoevel bytes je van het bestand wilt inlezen.
De BitConverter-klasse kan eenvoudig bytes omzetten naar int met behulp van de ToInt32 klasse.
Maak een digitale console-versie van het klassieke kinderspel hamertje Tik
In dit spel heeft het kind een hele hoop kleurige blokjes ter beschikking waarmee hij op een kurken bord eender welke ‘tekening’ kan maken door de blokjes in de kurk met een nagel te kloppen.
Maak een abstracte klasse Vorm die z’n locatie (via x,y coördinaten als autoprops) op het scherm kan bijhouden alsook een abstracte methode TekenVorm. Voeg voorts een virtual property Kleur toe van het type ConsoleColor. Deze property is read-only en geeft ConsoleColor.Red terug.
De klasse Vorm heeft een overloaded constructor die steeds de x,y coördinaten verwacht als parameters vervolgens instelt in de bijhorende autoprops.
De Vorm heeft géén default constructor.
De locatie van de vormen die we hierna zullen definiëren is steeds het punt linksboven indien we een rechthoek omheen de vorm zouden tekenen. Het voorbeeld hier toont deze plek bij het vliegtuig van stap 3:
Zorg ervoor dat beide vormen via TekenVorm zichzelf op het scherm kunnen tonen in hun eigen kleur.
Lijn:
Heeft een Lengte autoproperty
Heeft 1 overloaded constructor die x,y en lengte vraagt
Heeft als kleur ConsoleColor.Green
Een lijn bestaat uit een reeks sterretjes (*) horizontaal naast elkaar, gelijk aan de lengte die je via de constructor van bij de start kunt meegeven. Bijvoorbeeld bij lengte 3:
* * *
Rechthoek:
Heeft een Lengte en Breedte autoproperty
Heeft 2 constructors:
1 overloaded die x,y, lengte en breedte vraagt
default die standaard een rechthoek op locatie 1,1 zet met lengte en breedte 2
Heeft als kleur ConsoleColor.Yellow
Een rechthoek verwacht een lengte en breedte bij het aanmaken en kan zichzelf ook tekenen. Als je lengte 4 en breedte 2 ingaf zou deze er als volgt uitzien:
Maak een klasse Vliegtuig dat ook een Vorm is. Een vliegtuig bestaat (compositie!) uit 1 Rechthoek en 2 Lijn-objecten en ziet er altijd hetzelfde uit, namelijk
Een rechthoek van 2 bij 5
Links en rechts van deze rechthoek een lijn van 3 breed, telkens in de helft van de lengte van deze rechthoek
Enkel de locatie op het scherm kan anders zijn per vliegtuig, hun afmetingen echter niet.
* *
* *
* * * * * * * *
* *
* *
Een Vliegtuig heeft een constructor die de x,y locatie vraagt (zie tekening vorige pagina i.v.m. coördinaten) en zal in de constructor de 3 vormen (2 lijnen en 1 rechthoek) aanmaken.
Merk op dat dus dat het lichaam (de Rechthoek) geel zal zijn, en de twee vleugels groen (van de lijnen).
Maak een klasse Vloot dat ook een Vorm is. Een vloot bestaat uit 1 of meerdere vliegtuigen. Je kan via de constructor instellen hoeveel vliegtuigen er moeten zijn in 1 Vloot, alsook de x,y coördinaten (linksboven).De nodige vliegtuigen worden in de constructor aangemaakt en in een lijst bijgehouden in het Vloot-object zelf.
Houdt via een lijst in de klasse de vliegtuigen bij. Een vloot vliegtuigen dat getekend wordt tekent gewoon alle vliegtuigen onder mekaar.
Een vloot van 3 vliegtuigen zal er als volgt uitzien op het scherm:
Maak een interface IBeweegbaar, bestaande uit 1 methode Beweeg. Deze geeft niets terug en heeft 1 parameter van het type Richting.
Richting is een enum-type dat 4 mogelijke waarden heeft: Links, Rechts, Boven, Beneden.
Pas de interface toe op Vliegtuig en Vloot. Deze methode zal de Locatie van het object 1 plekje opschuiven in de richting die in de parameter werd meegegeven. Als dus vervolgens het object opnieuw wordt getekend zal het object 1 plek naar rechts opgeschoven zijn.
Vormen verplaatsen is gewoon een kwestie van de X,Y coördinaten aan te passen. Meer is niet nodig.
Maak nu een hammertje tik programma: een console-programma dat de gebruiker steeds volgende vragen stelt en vervolgens de gevraagde vormen toevoegt aan het scherm. Op de duur zal de gebruiker grote, complexe tekeningen kunnen maken door meerdere vormen en types te combineren. Iedere vorm die wordt toegevoegd zal in een lijst worden bijgehouden.
Een loop zal steeds volgende stappen uitvoeren tot de gebruiker het programma afsluit.
Alle vormen die reeds zijn toegevoegd in de lijst op het scherm tekenen via TekenVorm
Aan gebruiker vragen wat er moet gebeuren
Beeld leegmaken
De vragen die gesteld kunnen
Lijst leegmaken => alle vormen verdwijnen en de gebruiker kan terug opnieuw beginnen
Vorm toevoegen => zal de gewenste vorm toevoegen aan een lijst nadat volgende 2 of 3 extra zaken aan de gebruiker werden gevraagd:
Welke vorm? (rechthoek, lijn, vliegtuig, vloot)
Locatie (x,y) op het scherm
Vormafhankelijke informatie? (bv aantal vliegtuigen)
Afsluiten => programma sluit af
Verplaats object naar…: gevolgd door de vraag in welke richting moet verplaatst worden. Wanneer de gebruiker deze optie zullen alle objecten die de IBeweegbaar hebben 1 plekje in de ingegeven richting verschoven worden
Voeg een nieuw menu-item toe namelijk Vergroot vloot. Wanneer de gebruiker deze optie kiest zullen alle Vloot-objecten in de lijst 1 extra vliegtuig bijkrijgen. Je zal hiervoor een extra methode VergrootVloot aan de Vloot-klasse moeten toevoegen.
Voeg een nieuw menu-item Sorteer toe, indien de gebruiker dit kiest dan worden alle Vormen gesorteerd op hun x-locatie, hoe kleiner x, hoe eerder in de lijst. Bij gelijke x wordt gekeken naar de y-locatie waar degene met de laagste y voor die met hogere komt.
Vervolgens worden de objecten met een loop op het scherm beschreven als volgt: VormType, x, y
{% hint style="info" %}
Volgende opgave was de vaardigheidsproefopdracht voor het 2e zit examen van dit vak (OOP) in augustus 2019
We maken een eenvoudige veiling-simulator. Hierbij kunnen spelers bieden op getoonde schilderijen en deze kopen indien ze wensen. Het spel wordt gespeeld door 2 spelers, waarbij 1 speler de gebruiker is, de andere wordt door de computer bestuurd.
TekenSchilderij: de methode zal een willekeurig schilderij op het scherm tekenen in linkerbovenhoek. Een schilderij is steeds 10 bij 10 groot en bestaat uit een willekeurige hoeveelheid gele, rode en groene vlakken. Enkele voorbeelden:
Opgelet: ieder object tekent een ander schilderij. Als op hetzelfde object 2x na mekaar TekenSchilderij wordt aangeroepen dan zal uiteraard 2x hetzelfde schilderij getekend worden. De klasse houdt intern bij uit hoeveel rode, hoeveel gele, en hoeveel rode vlakken het schilderij bestaat.
KrijgData: deze methode geeft terug uit hoeveel rode vlakken de schilderij bestond.
Maak een klasse WaardeBepaler. Deze bestaat uit 1 static methode genaamd BerekenWaarde. Deze methode aanvaardt 1 int als parameter. Het geeft een double terug als resultaat.
De methode zal de waarde van het schilderij bepalen gebaseerd op het aantal rode vlakken. De waarde van een schilderij is het aantal rode vlakken maal 1000 en daar vervolgens de vierkantswortel van.
Een schilderij met 50 rode vlakken heeft dus een waarde van €223,6 (vierkantswortel van 1000*50)
Dit getal tot 1 cijfer na de komma wordt door de methode teruggegeven.
Een koper heeft bij de start steeds een budget van 1500 euro.
Het budget kan enkel als readonly property van buitenaf uitgelezen worden. De setter is private.
Een koper heeft een lijst van schilderijen (leeg bij de start) waarin ieder gekocht schilderij komt.
Een koper heeft een constructor die een interne waarde ogenblikkelijk op 1500 zet
Een methode “Koop”: deze methode aanvaardt 1 parameter van het type schilderij en geeft een bool terug.
Eerst wordt de waarde van het meegegeven schilderij berekend mbv van de WaardeBepaler klasse.
Vervolgens: Indien de koper genoeg budget heeft dan zal de waarde van het schilderij van het budget gehaald worden (via de private setter) en wordt het schilderij aan de lijst van gekochte schilderijen van de koper toegevoegd.
Vervolgens geeft de methode ‘true’ terug.
Indien de koper niet genoeg budget heeft wordt false teruggeven.
Een koper heeft een methode TotaleWinst: deze methode geeft de totale waarde van alle schilderijen samen in zijn lijst terug als een int.
Schrijf een programma dat voorgaande klasse gebruikt als volgt:
1 speler-object wordt door de gebruiker bedient. 1 door de computer.
Er verschijnt telkens een schilderij, met daaronder de waarde ervan.
Er wordt aan de gebruiker gevraagd of hij/zij dit wenst te kopen. Indien ja, en dit kan, dan wordt het schilderij aan zijn lijst toegevoegd en z’n budget verlaagt.
Indien neen dan zal de computer het schilderij kopen indien deze nog genoeg budget heeft.
Vervolgens komt het volgende schilderij.
Het ‘spel’ stopt wanneer beide speler het huidige schilderij niet kunnen of willen kopen.
De “TotaleWinst” van iedere speler wordt vergeleken. De speler wiens TotaleWinst + overgebleven Budget het hoogst is wint.
Voorbeeld: speler 1 heeft TotaleWinst 300 en Budget over 300, dus 600
Speler 2 (de computer) heeft TotaleWinst 400 en Budget 100, dus 500. Speler 1, de gebruiker, wint de veiling
Het spel toont wie heeft gewonnen en sluit dan af.
Maak een klasse Picasso. Deze klasse is een Schilderij, maar bestaat uit een 15 bij 15 groot schilderij (in plaats van 10 bij 10) en zal dus meestal meer waard zijn.
Zorg ervoor dat er op de veiling ongeveer 30% van de tijd een Picasso verschijnt die de spelers kunnen kopen. De overige werking blijft dezelfde.
De klasse Koper heeft een extra methode “SorteerBezit”. Wanneer deze wordt aangeroepen dan worden de schilderijen in zijn bezit gesorteerd op basis van hun waarde. De hoogste waarde komt vooraan en zo verder.
De klasse Koper heeft een extra methode “KrijgSchilderij”: deze methode aanvaardt 1 parameter van het type Koper. Wanneer de methode wordt aangeroepen op een koper en een andere koper wordt als parameter meegegeven, dan krijgt de koper die de methode aanroept het eerste schilderij uit de lijst van de meegegeven koper. Het schilderij verdwijnt vervolgens uit de lijst van deze koper.
Voeg aan achteraan het spel code toe die aantoont dat deze twee methoden werken.
Een school, "Stedelijk Lyceum 90", heeft je gevraagd een administratief pakket voor hen te ontwikkelen. Maak een applicatie die simuleert hoe leerlingen in een school worden gemaakt op voorwaarde dat er genoeg geld aanwezig is. Vervolgens kunnen leerlingen uit een school gerekruteerd worden om als werkstudent te dienen.
geldHoeveelheid: een int die nooit onder 15 of lager kan gaan en die bijhoudt hoeveel geld je school nog heeft, private set
IsBijnaLeeg: een readonly property die true teruggeeft indien de hoeveelheid geld 15 of lager is
leerlingen: Een lijst van leerlingen (zie hierna) als gewone property die initieel een capaciteit van 15 plekken heeft.
Een autoproperty Naam die steeds op school90 staat.
Volgende publieke methoden:
Geefgeld: deze methode aanvaardt een double. Het getal dat je meegeeft wordt bijgeteld bij geldHoeveelheid
Maakleerling: Deze methode voegt een nieuwe leerling aan de lijst toe. Een leerling kan enkel gemaakt worden indien je school minstens 40 of hoger geld heeft. Vervolgens wordt de hoeveelheid geld met 15 verlaagt. Deze methode geeft een bool terug: true indien het aanmaken gelukt is, false indien niet (omdat er niet genoeg geld was)
Geefleerling: deze methode geeft een object van het type leerling terug indien er minstens 2 leerlingen in de lijst aanwezig zijn. De methode kiest altijd de eerste leerling uit de lijst om terug te geven en zal deze vervolgens uit de lijst verwijderen.
Je school override ToString zodat de geld hoeveelheid, de Naam ,IsBijnaleeg en het aantal leerlingen in de lijst mooi op het scherm toont.
Deze heeft een default constructor die bij het aanmaken van de leerling de naam van de leerling zal instellen op StudentX waarbij de X vervangen wordt door de zoveelste leerling die in het programma al werd aangemaakt. De eerste heet dus Student1, dan Student2, etc.
Toon in je main aan dat je klassen werken door een programma te maken dat:
Een school aanmaakt
Een lege lijst leerlingen, werkstudenten genaamd, aanmaakt
Een loop start die 15 keer zal lopen, per loop:
wordt een random hoeveelheid geld (tussen 15 en 30) aan je school gegeven.
Wordt een leerling aangemaakt in je school
Indien een leerling kon aangemaakt worden (omdat er genoeg geld was) bestaat er 60 % kans dat vervolgens een ridder met de Geefleerlingmethode uit je school wordt gehaald en in de werkstudenten lijst wordt gestoken.
Wordt de informatie van je school op het scherm getoond (mbv ToString)
Na de loop wordt de lijst van werkstudenten overlopen en worden alle namen de leerlingen in die lijst getoond.
In je main wordt van elke klasse 1 object aangemaakt:
Plaats deze elementen in een dictionary waarbij je steeds een random getal tussen 100 en 2000 als “key” toewijst. Zoek eerst op of deze key reeds in de dictionary aanwezig is, zo ja, dan genereer je nieuw getal en probeer je opnieuw toe te voegen. Toon deze key op het scherm.
Vraag eenmalig aan de gebruiker een getal, de key, en toon van dit object de RapportStatus (ga er van uit dat de gebruiker steeds een geldige key invoert)
Bereken de gemiddelde risicograad van alle objecten in de dictionary
Bereken de gemiddelde risicograad van alle objecten die geen IRampGebiedResponder zijn
De sportleraar is nogal slordig. Hij verliest altijd zijn dure drinkbussen. De school heeft daarom jouw diensten ingehuurd om een deel van het materiaal eenvoudig terug te vinden.
Volgende filmpje toont de volledige werking van de applicatie:
Een sportleraar kan een rugzak met 2 soorten items vullen:
Niet trackable items (ballen, fluitje, etc).
Drinkbussen die wel getrackt kunnen worden.
De rugzak zelf is ook trackable en zal zelfs kunnen aangeven op welke hoogte deze zich bevindt.
Om het leuk te maken zullen de posities van de trackable items (drinkbussen en rugzakken) telkens veranderen wanneer je ze aanroept.
De spullen die je in een rugzak plaats zullen zich in het progamma niet op dezelfde locatie als de rugzak zelf bevinden, daar alle trackable elementen (rugzak en drink) steeds nieuwe willekeurige locaties krijgen (beeld je in dat de leraar de rugzak vult, ermee naar het park vertrekt, uitlaadt en nu geraken alle spulletjes zoek in het park)
2 autoproperties, type int, genaamd Latitude en Longitude
Een overloaded constructor waarmee je de Latitude en Longitude kunt instellen.
Een default constructor die de Latitude en Longitude instelt op telkens een random getal tussen 1 en 9.
ToString wordt overschreven en output het object als volgt Latitude: 4, Longitude: 6 (met de getallen natuurlijk de effectieve waarde van de properties van dat object).
Maak een klasse Rugzak die de ITrackable interface implementeert.
De klasse geeft een nieuwe willekeurige AdvancedGPSLocation terug telkens GetCurrentLocation wordt aangeroepen.
De klasse heeft een Dictionary van sportitems (de rugzakinhoud) waarbij een string als key van ieder item zal gehanteerd worden.
De rugzakinhoud (de Dictionary) is bereikbaar via een full property.
De klasse overschrijft ToString zodat informatie als volgt op het scherm verschijnt (onderaan voorbeeld). Tip:Gebruik maximaal de ToString-methode van objecten:
Eerst wordt er een zin gegeven die de huidige locatie van de rugzak toont.
Vervolgens wordt ieder sportitem in de rugzak onder elkaar geschreven (met de tostring van ieder sportitem) en de key.
Indien een sportitem in de rugzak ITrackable heeft dan zal de locatie van het sportitem met GetCurentLocation aangeroepen worden om ook deze informatie te tonen.
Een voorbeeld van de ToString methode output van een rugzak met daarin een drinkbus en een gewoon sportitem:
Rugzak op locatie: Latitude:1, Longitude:9, Height:1
Met inhoud:
mijndrinkbus (Een drinkbus)
-Laatste locatie is Latitude:3, Longitude:5
bal (Een eenvoudig sportitem)
-Geen tracker aanwezig
( mijndrinkbus en bal zijn de keys van ieder sportitem)
De klasse heeft een methode Visualiseer wanneer deze wordt aangeroepen (geen parameters) zal deze de inhoud van de rugzak én de rugzak zelf op het scherm tonen aan de hand van lettertjes, als volgt:
De GPSLocation coordinaten (Latitude en Longitude) stellen de coordinaten voor waar op het scherm het element komt (Latitude geeft de kolom weer, Longitude de rij in de console). Op die plek zet je een letter:
r voor een rugzak
D voor een drinkbus
Merk op dat deze methode telkens een andere 'kaart' zal tonen, daar de GPSlocaties bij iedere aanroep van GetCurrentLocation veranderen (willekeurig).
Indien meerdere elementen op dezelfde locatie staan dan wordt gewoon 1 letter getoond (van het laatste element dat op deze plek diende gevisualiseerd te worden).
Een voorbeeld van de uitvoer van de Visualiseer-methode indien we een rugzak hebben op locatie (2,3), met daarin 1 drinkbus op (4,4) en 1 drinkbus op (5,6):
Vraag aan de gebruiker hoeveel sportitems in de rugzak moeten komen.
Per sportitem dat in de rugzak komt maak je een willekeurig sportitem aan (SportItem of Drinkbus, beide 50% kans om gekozen te worden) en vraag je vervolgens de key waarmee dit sportitem in de rugzak-dictionary moet bewaard worden.
Vervolgens start er een loop die oneindig blijft doorlopen die telkens:
Het scherm leegmaakt
De inhoud van de rugzak op het scherm toont in tekstvorm (via ToString)
Wacht tot de gebruiker op enter duwt.
Het scherm leegmaakt
De Visualiseer methode van de rugzak aanroept.
Wacht tot de gebruiker op enter duwt.
Merk op dat de locaties die in stap 2 getoond worden niet overeenkomen met de locaties die bij de visualisatie in stap 5 worden gebruikt.
Knap hoor! We zijn er in geslaagd om eindelijk de aarde voorgoed achter ons te laten en naar nieuwe planeten, ver weg, te reizen. Voor we onze kostbare mensen de ruimte insturen heeft NASA en ESA jou gevraagd om een ruimte-reis-simulatie-pakket te maken. Hopelijk toont jouw applicatie aan dat onze raketten ver genoeg zullen geraken!
Een ruimteschip zal in de simulatie vertrekken vanop aarde met een gegeven energie aan de start. Voorts wordt er een fictieve route van planeten en tussenstations aangemaakt waar de rakket, soms, kan bijtanken.
De applicatie bestaat uit 2 delen (we gaan verderop in de opgave in op de details van ieder deel)
Eerst wordt de fictieve wereld, de reisweg, aangemaakt die de tussenstops in volgorde toont. Er wordt telkens getoond om wat voor tussenstop het gaat en hoeveel lichtjaren de stop van de aarde verwijderd is. Voorbeeld:
Dit is je reisplan:
RijkePlaneet:1684
RijkePlaneet:1703
RijkePlaneet:1911
Planeet:3230
TankTussenstation:4067
Planeet:5339
TankTussenstation:5642
TankTussenstation:6765
TankTussenstation:7016
TankTussenstation:9504
Vervolgens toont de applicatie de startsituatie van het ruimteschip (dat altijd met 3000 energie begint):
Dit is je schip:
Je hebt 3000 energie en bent 0 units verwijderd van de aarde.
Vervolgens zal de simulatie een rakket dit traject laten vliegen. Dit gebeurt automatisch. Op plaatsen waar getankt kan worden (RijkePlaneet en TankTussenstation) zal het ruimteschip dit sowieso doen en dan verder vliegen. Wanneer het ruimteschip niet meer genoeg energie heeft om de volgende etappe af te leggen dan stopt de simulatie daar.
Eén lichtjaar reizen kost 1 energie.
Voorbeeld van de uitput (gegeven het voorbeeld in deel 1 hierboven):
De reis gaat van start:
We proberen te reizen naar bestemming 1
Bestemming bereikt. Nog 1316 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 168 energie en staat nu op 1484 energie.
We proberen te reizen naar bestemming 2
Bestemming bereikt. Nog 1465 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 170 energie en staat nu op 1635 energie.
We proberen te reizen naar bestemming 3
Bestemming bereikt. Nog 1427 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 191 energie en staat nu op 1618 energie.
We proberen te reizen naar bestemming 4
Bestemming bereikt. Nog 299 energie over.
Laten we proberen bij te tanken
Hier kan niet bijgetankt worden
We proberen te reizen naar bestemming 5
Dit schip heeft niet genoeg energie daarvoor.
De reis eindigt hier.
Je hebt 299 energie en bent 3230 units verwijderd van de aarde.
Je bent tot aan bestemming 5 geraakt met info: TankTussenstation:4067
Volgende diagram toont alle klassen en interfaces die je moet maken:
We beschrijven nu de individuele klassen in de volgorde dat je ze best maakt, uiteraard ben je vrij om een andere vologrde te hanteren
IEnergiegever
Plekken waar het ruimteschip zal kunnen tanken hebben deze interface. De interface is als volgt gedefinieerd:
interface IEnergieGever
{
long GeefEnergie();
}
Reisbestemming
Deze abstracte klasse wordt gedefinieerd door de afstand (in lichtjaren) van de aarde. Enkele opmerkingen:
r is een staticRandom-object zodat je dat overal kan gebruiken
heeft een read-only property AfstandVanAarde
heeft een constructor die de instantievariabele afstandVanAarde op een willekeurig getal tussen 400 en 10.000 zet.
heeft de IComparable-interface en zal toelaten om (later) een lijst van Reisbestemmingen te sorteren op hun afstand van de aarde (zie verder).
heeft de ToString-methode geïmplementeerd en geeft het object weer als [Type object]:[Afstand van Aarde], bijvoorbeeld RijkePlaneet:1911 (zie de output deel 1 bovenaan).
Tip: met de GetType().Name property krijg je het type terug zonder de overbode namespace ervoor.
Planeet
Een Planeet is een Reisbestemming. Niets meer.
Ter info: er kan dus niet getankt worden daar het niet de IEnergieGeven-interface heeft.
RijkePlaneet
Een RijkePlaneet is een Planeet die de IEnergieGever-interface heeft. Dit type planeet geeft altijd 10% terug van de afstand tot de aarde. Als de planeet zich dus op 3246 lichtjaren bevind dan zal GeefEnergie 324 energie teruggeven.
TankTussenstation
Een TankTussenstation is een Reisbestemming die de IEnergieGever-interface heeft. Dit type geeft altijd een willekeurige hoeveelheid tussen 500 en 1500 energie terug bij GeefEnergie. Deze waarde is steeds anders telkens de methode wordt aangeroepen.
Wereld
Deze klasse heeft één methode met volgende signatuur:
public static List<ReisBestemming> GenereerWereld(int aantal)
De methode geeft een lijst van Reisbestemming-en terug. De parameter aantal geeft aan hoeveel objecten in de lijst zitten.
De methode plaats een combinatie van Planeet, RijkePlaneet en TankTussenstation-objecten in de lijst. Het kiest willekeurig uit deze 3 types volgende volgende tabel:
25% kans op een Planeet
25% kans op een RijkePlaneet
50% kans op een TankTussenstation
Finaal wordt de lijst gesorteerd waarbij de Reisbestemming die het dichts bij de aarde zit van voor komt, en zo verder. Deze gesorteerde lijst wordt als resultaat van de methode teruggegeven.
Tip: weet je niet hoe je moet sorteren? Geen probleem, geef gewoon de ongesorteerde lijst terug en werk hier op verder! (verlies dus niet te veel tijd met dit stuk)
Ruimteschip
Deze klasse heeft:
Een read-only property met private set om de Energie(type: long) bij te houden.
Een ruimteschip heeft altijd 3000 energie aan de start.
Een instantievariabele afstandVanAarde die bijhoudt hoeveel lichtjaren van de aarde het schip is.
Deze start altijd op 0 (daar we op aarde vertrekken).
De methode ToSTring die volgende zinnetje teruggeeft Je hebt [Energie] energie en bent [afstandVanAarde] units verwijderd van de aarde. (met natuurlijk de effectieve waarden in plaat van de placeholders met vierkante haken). Voorbeeld Je hebt 294 energie en bent 3489 units verwijderd van de aarde.
De klasse heeft twee speciale methode:
StartReis:
Deze methode geeft een bool terug en aanvaardt een Reisbestemming-object als parameter. De methode werkt als volgt:
Het geeft met de bool weer of het schip genoeg energie heeft om naar de reisbestemming te reizen. Een schip kan enkel naar die plek, het doelwit, reizen (de parameter) indien deze minstens evenveel energie heeft als het aantal lichtjaren dat het schip van de planeet verwijderd is.
De te reizen afstand is natuurlijk het verschil tussen de afStandVanAarde-instantie van het ruimteschip en de AfstandVanAarde van de bestemming.
Als het schip op afstand 2000 is van de aarde en het doelwit is op 2500 afstand van de aarde, dan heeft het schip 500 (2500-2000) energie nodig.
Indien het schip niet genoeg energie heeft dan wordt er false teruggegeven nadat volgende zin op het scherm komt: "Dit schip heeft niet genoeg energie daarvoor."
Indien het schip wél genoeg energie heeft dan wordt de energie van het schip verminderd met de zonet berekende hoeveel energie die gegeven de afstand tussen beide nodig was (dus 500 in vorig getalvoorbeeld) en worden volgende 2 zinnen getoond: Bestemming bereikt. Nog [Energie} energie over. Laten we proberen bij te tanken.
Vervolgens wordt de afstandVanAarde verhoogt met de afgelegde afstand (namelijk de gespendeerde energie)
Voor je nu true teruggeeft (om aan te geven dat de reis gelukt is) roep je nu de methode EnergieBijtanken(zie volgende stuk) en geeft de doelwit Reisbestemming mee als argument.
EnergieBijtanken
Deze methode geeft niets terug en aanvaardt een Reisbestemming-object als parameter. De methode werkt als volgt:
Indien het meegeven object de IEnergieGeven-interface heeft dan zal het schip hiervan gebruik makenen bijtanken. Het roept hierbij de GeefEnergie-methode van het doelwit op en zal de teruggekregen energie optellen bij z'n huidige energie en vervolgens volgende zinnetje tonen: Hier werd bijgetankt. Je kreeg [verkregenEnergie] energie en staat nu op [Energie] energie. Vervolgens stopt de methode.
Indien er op het object niet kan getankt worden verschijnt er Hier kan niet bijgetankt worden en stopt de methode.
Het wordt nu tijd om alles samen te gooien. Dat gaat hopelijk eenvoudig. Het hoofdprogramma werkt als volgt:
Een nieuwe wereld wordt aangemaakt mbv van de GenereerWereld-methode van de Wereld-klasse
Ieder tussenstop van deze nieuwe wereld wordt op het scherm getoond (zie voorbeeld uitvoer vooraan de opgave)
Een nieuw RuimteSchip-object wordt aangemaakt en ook op het scherm getoond.
De reis gaat van start. Hierbij wordt een loop gestart die blijft duren:
zolang het schip nog energie heeft (dus meer dan 0),
zolang een teller minder is dan het totaal aantal bestemmingen in de wereld
zolang het schip nog genoeg energie heeft om naar de volgende bestemming te gaan
In de loop houdt je met een teller bij aan welke bestemming je bent en verhoogt deze teller telkens het schip naar de volende bestemming reist.
Finaal toon je tot waar het schip is geraakt.
Volgende voorbeeldoutput toont nogmaals het geheel:
Dit is je reisplan:
TankTussenstation:1401
RijkePlaneet:1519
TankTussenstation:2390
Planeet:4167
TankTussenstation:5736
TankTussenstation:6386
Planeet:6426
Planeet:6466
RijkePlaneet:9646
RijkePlaneet:9872
Dit is je schip:
Je hebt 3000 energie en bent 0 units verwijderd van de aarde.
De reis gaat van start:
We proberen te reizen naar bestemming 1
Bestemming bereikt. Nog 1599 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 788 energie en staat nu op 2387 energie.
We proberen te reizen naar bestemming 2
Bestemming bereikt. Nog 2269 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 151 energie en staat nu op 2420 energie.
We proberen te reizen naar bestemming 3
Bestemming bereikt. Nog 1549 energie over.
Laten we proberen bij te tanken
Hier werd bijgetankt. Je kreeg 838 energie en staat nu op 2387 energie.
We proberen te reizen naar bestemming 4
Bestemming bereikt. Nog 610 energie over.
Laten we proberen bij te tanken
Hier kan niet bijgetankt worden
We proberen te reizen naar bestemming 5
Dit schip heeft niet genoeg energie daarvoor.
De reis eindigt hier.
Je hebt 610 energie en bent 4167 units verwijderd van de aarde.
Je bent tot aan bestemming 5 geraakt met info: TankTussenstation:5736
Ultimate Beast Master is een populaire, Amerikaanse, tv-show waarin topatleten een ongelooflijk zware obstakelkoers zo snel mogelijk moeten afleggen. Enkel de sterkste, meest atletische mannen en vrouwen slagen er in om het einde van het parkoers te bereiken.
Als organisator van de tvshow wordt je gevraagd om een systeem te ontwikkelen waarin een parkoers kan gegenereerd worden waarvan ook de moeilijkheidsgraad kan berekend worden.
die de moeilijkheidsgraad van het object op een willekeurige waarde geeft van 1 tot en met 4 (dat vervolgens in BerekenMoeilijkheidsgraad zal gebruik worden).
Een Ultratrampoline is een trampoline die gevaarlijk is. Er is geen mogelijkheid om netten rond het ding te plaatsen, dus deze klasse verdient zeker de term dodelijk.
De klasse:
Is een Trampoline.
Heeft een default constructor die het tekenChar op T instelt.
Implementeert de IDodelijk interface en zal altijd false teruggeven bij VeiligheidsActief (de beveiligingsinstelling van een Ultratrampoline kan dus nooit anders zijn).
De moeilijkheidsgraad van deze klasse is "10 + de waarde die in de default constructor van de Trampolinewerd berekend".
De dodelijk deadwall is een klimmuur waar eventueel veiligheidsnetten onder kunnen geplaatst worden zodat deelnemers die vallen opgevangen kunnen worden.
Is een Klimmuur.
Heeft een default constructor waarmee kan ingesteld worden of de wall met veiligheidsnetten werkt of niet (aan de hand van een meegegeven bool). Een DeadWallheeft altijd 21 klimelementen. tekenchar is M.
Implementeert de IDodelijke interface en zal de bool teruggeven in VeiligheidsActief die in de constructor werd meegegeven.
De moeilijkheidsgraad is 5 indien er veiligheidsnetten zijn, anders is deze 10.
Deze klasse beschrijft een volledig parkoers van toestellen die de speler zal moeten bedwingen in de Ultimate Beast Master tv-show.
Deze klasse heeft een lijst van toestellen.
Een constructor die 2 parameters aanvaard, namelijk het aantal toestellen (x) waaruit het parkoers bestaat en een bool (y) om aan te geven of dodelijke toestellen met beveiliging moeten worden toegevoegd:
De constructor zal x willekeurige toestellen aan de lijst toevoegen. Ieder toestel (Trampoline, UltraTrampoline, Klimmuur en Deathwall) heeft even veel kans om gekozen te worden.
Indien een Klimmuur wordt gekozen dan krijgt deze een willekeurig aantal klimtoppen tussen 10 en 50.
Indien een Deathwall wordt gekozen dan wordt de bool y meegeven om aan te geven of er wel of geen veiligheidsnet moet toegevoegd worden.
De klasse heeft een methode VerwijderDodelijke. Wanneer deze methode wordt aangeroepen dan worden alle IDodelijke toestellen uit de lijst verwijderd.
De klasse een private methode BerekenMoeilijkheidsgraad die een int teruggeeft. De moeilijkheidsgraad van een parkoers bestaat uit de som van de moeilijkheidsgraden van alle toestellen in de lijst.
De klasse heeft een methode ToonParkoers . Deze methode zal alle toestellen na elkaar op het scherm tonen waarbij de achtergrond van ieder element rood of groen zal zijn:
Rood indien het een IDodelijk toestel is (ongeacht of er veiligheidsnetten aanwezig zijn), groen in de andere gevallen.
Nadien wordt ook nog de totale moeilijkheidsgraad van het parkoers getoond.
Eerst worden er 5 willekeurige Parkoer-objecten aangemaakt en in een lijst bewaard.
Vervolgens worden alle Parkoer-objecten in de lijst gevisualiseerd.
De gebruiker kiest met welk parkoer hij verder wilt gaan.
Er wordt nu aan de gebruiker gevraagd of de dodelijke toestellen uit het parkoers moeten worden gehaald. Indien ja, wordt dit gedaan (alle IDodelijke objecten worden uit de lijst van het gekozen Parkoer object gehaald).
Finaal wordt het gekozen parkoers nogmaals getoond, al dan niet zonder de dodelijke toestellen.
Voorbeeld output:
Volgende opgave was de vaardigheidsproefopdracht voor het inhaalexamen van dit vak (OOP) in augustus 2022
Na vele jaren vloeken op de roosters, heeft de firma "Roosteren-maar" eindelijk besloten hun roostersoftware aan te passen. Aan jou deze taak om een deftig roosterprogramma te schrijven. Veel succes gewenst!
Een vak heeft een titel (type string), een duur (int) en een toegewezen lector (type Lector, zie verder). Voorzie de nodige properties hiervoor, wetende dat:
a) de duur enkel 1 of 2 uur kan zijn, niets anders. Controleer hier op.
b) de titel standaard "Onbekend" is.
De klasse override ToString en toont een object als volgt: Titel - Lector (bijvoorbeeld: OOP - Jansens).
Standaard heeft een nieuw gemaakt Vak-object een Lector-object met als naam "Nog Toe te wijzen``.
Een lector heeft een naam (string) en een maximaal aantal uur (maxUur, type int) dat de persoon les kan geven op een week. De waarde van maxUur is altijd 6. Voorzie dit via een readonly property.
Deze klasse heeft een private lijst van Vakken die standaard leeg is. Deze lijst stelt de dagrooster voor en bevat alle vakken van de dag.
De klasse heeft een property VrijeUren: deze geeft een int terug en bevat de totale som van alle duren van de vakken in de lijst. Als er dus 2 vakken in de lijst staan, 1 van 1 uur duur, de andere van 2uur duur, dan zal deze property 3 teruggeven (1+2).
De klasse heeft voorts volgende methoden:
a) ToonRooster: deze methode zal ieder vak in de lijst via ToString op het scherm onder elkaar tonen. Indien een vak 2uur duurt dan zal het vak 2x onder elkaar getoond worden. Voorbeeld output:
b) VoegVakToe: deze methode aanvaardt een Vak-object. Dit object wordt aan de lijst toegevoegd indien dat kan. Een rooster kan nooit meer dan 8uur totale duur bevatten (gebruik VrijeUren hiervoor). Als je dus een vak van 2uur probeert probeert toe te voegen terwijl de roosterlijst reeds 7uur bevat, dan zal dit niet lukken en wordt er een RoosterException teruggegooid (maak deze Exception klasse zelf aan).
c) VerbeterRooster: wanneer deze methode wordt aangeroepen dan zal de lijst met vakken gesorteerd worden volgens 1° hun naam alfabetisch 2° hun duur (lange vakken eerst).
d) WijsLectorToe : deze methode aanvaart een index x (int) en een Lector object. De methode zal de meegegeven lector toewijzen (en de bestaande overschrijven) aan het vak in lijst met de index "x" die je als parameter hebt meegeven. Indien er geen vak bestaat met die index dan verschijnt er een foutboodschap.
LaboVak is een Vak. Deze zal als ToString aangeroepen wordt vooraan de titel nog "(labo)" toevoegen. Bijvoorbeeld: (labo) OOP - Jansens.
Deze heeft een constructor waar je een Vak-object aan kan meegeven. De informatie van dit object wordt gebruikt om het LaboVak in te stellen (je neemt dus de duur, lector en titel over uit het object en wijst dit toe aan het huidige LaboVak-object).
Een labovak kan ook 3uur duren en is dus niet beperkt tot 1 of 2 uur duur.
Voeg voorts aan de klasse Rooster een nieuwe methode ToonLabos toe. Deze zal net als ToonRooster het rooster visualiseren, maar enkel voor vakken van het type LaboVak.
In het hoofdprogramma wordt een lijst van 3 lectoren aangemaakt (kies zelf de namen), waarvan 1 een halftijdselector is.
Maak een applicatie die bovenstaande klassen gebruikt door aan de gebruiker een menu aan te bieden met volgende items (bepaal zelf hoe je de input van de gebruiker gaat verwerken):
Toon rooster: de huidige rooster wordt op het scherm getoond.
Voeg vak toe: de gebruiker dient vervolgens de naam van het vak te geven, de duur, en welke lector (voor de lector geeft hij gewoon de index in, 0, 1 of 2 en gebruik je vervolgens de lector in de lijst die je aanmaakte aan de start van het programma). Indien de gebruiker bij duur 3 ingeeft dan wordt dit vak automatisch een labovak.
Verbeter rooster: dit zal de VerbeterRooster methode aanroepen.
Toon labo's: Enkel de LaboVak-objecten in het rooster worden op het scherm getoond.
Maak een klasse WeekRooster. Deze klasse heeft 5 lijsten van het type Vak, 1 voor iedere weekdag. De klasse heeft een default constructor en zal een random rooster aanmaken door de 5 week-lijsten te vullen met telkens 4 willekeurige Vak-objecten (20% kans op een LaboVak).
De klasse heeft volgende methode:
Toon rooster: deze zal de rooster per dag onder elkaar op het scherm tonen en voor iedere lijst de dag tonen.
Voeg aan het hoofdmenu de optie Toon weekrooster. Deze zorgt ervoor dat een WeekRooster object wordt aangemaakt dat vervolgens op het scherm wordt getoond.
Je firma werd gevraagd om voor een grote rederij een manifest-generator te maken. Wanneer een schip gevuld wordt met dozen en containers dan moet de kapitein ook steeds een manifest hebben. Op dit document (=het manifest) staat welke lading het schip aan boord heeft.
Het bedrijf biedt verschillende soorten dozen aan die de gebruiker kan gebruiken om z’n pakket mee te verzenden. Afhankelijk van het type doos zal de kostprijs anders zijn. Voorts biedt het bedrijf een SecureContainer aan. Dit is een doos die kan verzegeld worden. Een verzegelde container heeft als extra eigenschappen dat het ten eerste z’n kostprijs niet zal teruggegeven (zodat dieven niet weten wat de waarde van de inhoud is) en het zal ook onthouden hoe vaak externen de kostprijs van de doos wensen te weten komen.
abstract class Doos
{
public Doos(int id)
{
ID = id;
}
public int ID { get; private set; }
public int Gewicht { get; set; }
public string Inhoud { get; set; }
public virtual int KostPrijs
{
get { return Gewicht * 10; }
}
}
GeefAantalLeesAttemps() geeft terug hoe vaak de KostPrijs van het object werd uitgelezen via de get’r. VerzegelInhoud(): vanaf je dit aanroept zal de container verzegeld zijn. Een verzegelde container zal 0 als Kostprijs teruggeven in plaats van de effectieve kostprijs. (eens verzegeld kan dit niet meer ongedaan gemaakt worden).
Heeft een Lijst van Dozen genaamd vrachtRuim die naar buiten toe beschikbaar is via public get, maar private set.
Heeft een methode VoegDoosToe:
vereist 1 parameter van het type Doos en geeft een bool terug.
zal de doos in de parameter toevoegen aan het Vrachtruim, maar enkel indien het totale gewicht van alle dozen in het vrachtruim niet boven de 10 komt (indien de huidige dozen dus reeds samen 8 wegen, en de nieuw toe te voegen weegt 3 dan zal de doos niet toegevoegd worden):
Indien een doos te zwaar is zal er een Exception opgeworpen worden met de boodschap: “Te zwaar. Doos niet toegevoegd”.
Indien de doos wel werd toegevoegd zal er true terug gegeven worden
Heeft een methode ToonManifest:
Vereist geen parameters en geeft niets terug.
Deze methode aanroepen zal resulteren in het afdrukken van het manifest naar het scherm. De output hiervan wordt besproken in een later deel van deze opgave.
De ToonManifest()-methode van het DHLSchip zal de volgende output genereren:
Hoofding: Naam van het schip
Midden: informatie van de dozen.
Start telkens met een minteken, gevolg door de Inhoud van de doos, het gewicht en de kosptrijs ervan.
Indien de doos een ISafe interface bevat dan zal er achteraan de informatie van de doos ook de uitvoer van GeefAantalLeesAttempts getoond worden (voorafgegaan door 5 ‘hekjes’ (#)
Einde:
Het totaalgewicht van alle dozen samen wordt getoond
De totale prijs van alle dozen wordt getoond:
Per ISafe doos zal er een standaard prijs van 10 worden bijgeteld
Indien de doos Verzegeld is dan zal deze doos dus 0+10 kosten.
Een niet verzegelde doos zal dan z’n effectieve prijs + 10 kosten.
Voorbeeld output Manifest van een schip genaamd ‘The flying pegassus’ (Strips zit in een PostDoos, Goud zit in een verzegelde SecureContainer waarvan de kostprijs 1keer werd uitgelezen en Auto zit in een Container):
Maak nu een console-applicatie die toelaat om dozen op een schip te zetten en vervolgens het manifest te tonen. (screenshots van het programma worden achteraan deze opgave getoond)
Een menu wordt getoond dat steeds zal terugkeren tot de gebruiker het programma afsluit. De gebruiker kan 3 zaken kiezen in het menu a. Een doos aanmaken en op het schip zetten (zie deel 3c). b. Het schip-manifest op het scherm afdrukken (zal ToonManifest van het schip aanroepen). c. Het programma afsluiten.
Dit menu bestaat uit 3 stappen: a. Type doos vragen b. Gewicht en inhoud vragen c. (Optioneel) Doos verzegelen vragen Vervolgens zal de doos aan het vrachtruim van het schip toegevoegd worden (op voorwaarde dat het schip niet over z’n capaciteit van 10 komt uiteraard)
Stap 1 Indien de gebruiker voor optie a in het hoofdscherm kiest dan zal eerst gevraagd worden wat voor doos moet gemaakt worden: a. PostDoos b. Container c. SecureContainer
Stap 2 De volgende stap wordt gevraagd om de inhoud en het gewicht van de doos. Deze informatie wordt aan de gekozen doos toegevoegd.
Stap 3 (optioneel) Indien de gebruiker een SecureContainer heeft aangemaakt dan wordt in deze stap gevraagd of de gebruiker de doos wenst te vergrendelen. Bij ja wordt de VerzegelInhoud-methode aangeroepen.
Ongeacht stap 3 zal nu de doos worden toegevoegd, op voorwaarde dat er nog plek op het schip is.
Zorg ervoor dat je een doos-object naar de WriteLine()-methode kunt sturen als volgt Console.WriteLine(myDoos);, en er een mooie output op het scherm verschijnt, namelijk het doostype, gewicht, kostprijs en inhoud. Bij een SecureContainer wordt er ook nog getoond of de doos is verzegeld of niet.
Maak in je hoofdprogramma een methode die toelaat om snel alle SecureContainers in een schip te vergrendelen. De methode aanvaard één parameter van het type DHLSchip. Biedt in je applicatie in het hoofdmenu (3b) als 4e optie “Vergrendel alles” om dit voor de gebruiker te doen.
Het Oude Egypte met z'n faraos, pyramides, vreemde goden en mummies spreekt tot de verbeelding. Voor een firma ga je een simulatie van het Oude Egypte maken.
ReignStartYear (full, int): Het jaar waarin de Pharaoh begon met regeren. Kan enkel negatief zijn.
ReignEndYear (full, int): Het jaar waarin de regering van de Pharaoh eindigde. Kan enkel negatief zijn. Kan nooit kleiner zijn dan ReignStartYear, zoniet dan worden beide waarden verwisseld voor ze toegekend worden.
Voorts heeft iedere Pharaoh een private lijst van Achievements, waarin de belangrijkste prestaties of gebeurtenissen tijdens de regering van de Pharaoh in worden bijgehouden. Deze lijst bevat strings.
De klasse heeft volgende methoden:
CalculateReignLength() -> int: Bereken de lengte van de regeringsperiode van de Pharaoh, uitgedrukt in jaren.
AddAchievement(string achievement): Voeg een prestatie toe aan de lijst van belangrijke prestaties. Dit stelt je in staat om dynamisch prestaties toe te voegen aan het record van de Pharaoh.
ShowAchievements(): Deze methode zal alle prestaties van de Pharaoh onder elkaar oplijsten op het scherm.
Je dient twee constructors te implementeren voor de Pharaoh klasse:
Een constructor die alle eigenschappen als parameters neemt, inclusief ReignEndYear. De constructor controleert dat ReignEndYear later is dan ReignStartYear.
Een constructor die ReignEndYear weggelaten, voor het geval het einde van de regering onbekend is. ReignEndYearwordt dan op 0 gezet.
Deze klasse modelleert een dynastie in het oude Egypte, met eigenschappen en methoden die de relatie en informatie van meerdere Pharaoh's binnen dezelfde dynastie weergeven:
De klasse heeft volgende eigenschappen
Name (auto,string, ): De naam van de dynastie, bijvoorbeeld "18e Dynastie".
StartYear (full, int): Het jaar waarin de dynastie begon. Kan enkel negatief zijn.
EndYear (full, int): Het jaar waarin de dynastie eindigde. Kan enkel negatief zijn. Kan nooit kleiner zijn dan StartYear.
De klasse heeft ook een lijst van Pharaoh objecten die de Pharaoh's binnen deze dynastie vertegenwoordigen.
AddPharaoh(Pharaoh pharaoh): Voeg een Pharaoh object toe aan de lijst van Pharaoh's. Deze methode maakt het mogelijk om Pharaoh's dynamisch toe te voegen aan een dynastie. Indien een Pharaoh wordt toegevoegd wiens regeerperiode niet overlapt met die van de dynastie, dan wordt er een Exception opgeworpen. Voorbeeld: dynastie is van -500 tot -300, dan zal de Pharaoh die leefde tussen -510 en -480 wél worden toegevoegd. Maar de Pharaoh die leefde tussen -600 en -530 niet.
CalculateDuration() -> int: Bereken de duur van de dynastie, uitgedrukt in jaren.
ShowEvents(): Deze methode toont alle achievements van de Pharaohs in deze dynastie door de ShowAchievements methode van iedere faroah in de lijst aan te roepen, voorafgegaan door de naam van de Pharaoh.
ShowPharaohs: Deze methode lijst de Pharaohs op die in de lijst van Pharaoh objecten staat.
Creëer ten minste twee Pharaoh objecten met verschillende namen, regeerperioden, en voeg aan elk minimaal twee prestaties toe met de AddAchievement methode. Zorg ervoor dat de regeerperioden van deze Pharaoh's overlappen met de periode van de dynastie die je in stap 2 zult creëren.
Maak een Dynasty object en initialiseer deze met een naam en de start- en eindjaren. Zorg ervoor dat de start- en eindjaren negatieve getallen zijn om de historische tijdlijn van het Oude Egypte na te bootsen.
Voeg de Pharaoh objecten toe aan de Dynasty met behulp van de AddPharaoh methode. Vang eventuele exceptions op die worden opgeworpen als een Pharaoh niet binnen de periode van de dynastie valt.
Roep de CalculateDuration methode aan op je Dynasty object om de duur van de dynastie te tonen.
Gebruik de ShowEvents methode van de Dynasty klasse om alle prestaties van de Pharaoh's binnen die dynastie te tonen.
Je bent aangenomen als softwareontwikkelaar bij de Belgische Voetbalbond. Een aantal trainers heeft gevraagd om een digitale toepassing waarmee ze hun teamopstelling kunnen beheren en analyseren. Ze willen niet alleen spelers toevoegen en de sterkte van hun team bekijken, maar ook weten hoeveel hun opstelling waard is — iets wat belangrijk is bij transfers, scouts, en media-aandacht.
Deze gegevens worden opgegeven via een constructor bij het aanmaken van een speler.
De Kracht van een speler moet steeds tussen 1 en 10 liggen. Als een andere waarde wordt ingegeven, moet het programma een foutmelding geven via een ArgumentOutOfRangeException.
Elke speler heeft ook een IsBasisSpeler-eigenschap.
De marktwaarde wordt berekend als kracht × €100.000. En wordt via een readonly property teruggegeven.
Daarnaast moet een static property aanwezig zijn dat het totaal aantal spelers bijhoudt dat ooit is toegevoegd. Deze teller verhoogt automatisch bij elke creatie van een nieuwe speler.
Een Wedstrijd simuleert een duel tussen twee voetbalteams.
Eigenschappen:
Thuisploeg: een VoetbalTeam
Uitploeg: een VoetbalTeam
Constructor:
Neemt twee VoetbalTeam-objecten aan en stelt ze in als thuis- en uitploeg.
Methode:
Simuleer(): bepaalt de winnaar van de wedstrijd.
Vergelijk de totale kracht van beide teams.
Het team met de hoogste kracht wint.
Bij een gelijkstand wint het team met de hoogste marktwaarde.
Is ook die gelijk? Dan is het een gelijkspel.
De methode geeft een string terug in volgende stijl:
"Team Gent wint van Team Brugge met kracht 76 tegen 65."
Of
"Gelijkspel tussen Team Gent en Team Brugge met kracht 70."
Opmerking: deze klasse hoeft niet via het hoofdmenu opgeroepen te worden, maar moet wel instantieerbaar en bruikbaar zijn in code (bv. voor latere uitbreiding)
Schrijf een applicatie die aan de gebruiker in de console een folderpath vraagt (bijvoorbeeld “c:”). Vervolgens wordt een grootte in megabyte gevraagd. Vervolgens de applicatie alle bestanden in die folder, en alle subfolders, wiens bestandsgrootte gelijk of meer dan de ingegeven grootte is.
De applicatie toont de naam van het bestand, de grootte in MB en de datum waarop het bestand is aangemaakt. Bij het verwerken van de bestanden mogen eventuele uitzonderingen geen impact hebben op de nog te verwerken bestanden. Bestanden die dus niet geopend kunnen worden, worden overgeslagen. De applicatie toont dan wel een melding in de console dat het bestand niet geopend kon worden.
Tekst die start met ">" is invoer van de gebruiker.
Geef het pad van een folder in:
>c:\temp
Geef de minimum grootte (in megabyte) van bestanden die ik moet tonen:
>50
Bestanden groter dan 50 MB:
Bestand: c:\temp\mycontract.docx
Grootte: 83,58 MB
Aangemaakt op: 2024-09-30 15:19:46
Bestand c:\temp\corruptefile.docx kon niet geopend worden.
Bestand: c:\temp\video\zookeeper.mp4
Grootte: 535,40 MB
Aangemaakt op: 2024-09-30 15:19:46
Bestand: c:\temp\ffmpeg\bin\ffprobe.exe
Grootte: 63,45 MB
Aangemaakt op: 2024-09-30 15:19:48
De prijs voor meest sexy titel gaan we niet winnen. Maar naar de aloude traditie van de klassieke tekst-gebaseerde adventure-games (zie hier ) zullen we een eenvoudig object georiënteerd framework maken dat ons toelaat snel onze eigen games te maken. De nadruk van dit artikel ligt daarbij niet tot het creëren van een perfecte imitatie, maar wel om aan te tonen dat met een beetje object georiënteerde inzichten we tot zeer propere, herbruikbare én onderhoudbare code kunnen komen.
We maken uiteraard het spel in een Console-applicatie.
We willen de Main() methode van Program.cs zo leeg mogelijk laten. Daarom zullen we de meeste functionaliteit verpakken in een klasse GameManager. Het enige dat we dan nog hoeven te doen in onze main is een loop starten die steeds 3 zaken zal doen:
Huidige locatie beschrijven
Aan gebruiker tonen welke acties hij kan uitvoeren
Gewenste actie van gebruiker verwerken en uitvoeren
In code behelst dit:
static void Main(string[] args)
{
Console.WriteLine("Welkom bij AP Adventure. Een avontuur voor moedige en minder moedige studenten. Ben je er klaar voor?");
GameManager theGame= new GameManager();
//Start gameloop
while(!theGame.Exit)
{
//Beschrijf kamer
theGame.DescribeLocation();
//Toon acties
theGame.ToonActies();
//Lees actie uit
theGame.VerwerkActie();
}
}
Een bool property Exit binnen het GameManager object zal ons toelaten om de loop te stoppen wanneer het spel wordt beëindigd.
Doorheen de verschillende locaties zullen elementen te vinden zijn. We beschrijven deze als GameObjects:
class GameObjects
{
public string Name { get; set; }
public string Description { get; set; }
public void Describe()
{
Console.WriteLine(Name+","+Description+".");
}
}
Binnen de locatie klasse voegen we een methode toe die de GameManager kan gebruiken om te weten te komen naar welke locatie de gebruiker gaat. De methode aanvaardt een Direction (i.e. de richting waarin de gebruiker wenst te gaan) en zal een referentie naar het location-object teruggeven waarnaar de gebruiker zal bewegen. Indien de richting waarin hij wenst te bewegen niet geldig is dan tonen we dit op het scherm:
public Location GetLocationOnMove(Directions direction)
{
foreach (var exit in Exits)
{
if (exit.ExitDirection == direction)
{
return exit.GoesToLocation;
}
}
Console.WriteLine("Dat is geen geldige richting");
return this;
}
Wanneer dus een exit wordt gevonden in de Exits lijst die voldoet aan de meegegeven Direction dan geven we een referentie terug naar de bijhorende locatie (GoesToLocation). Wordt er geen exit gevonden en bereiken we dus het einde van de foreach lus dan verschijnt de tekst op het scherm en geven we een referentie terug naar de huidige locatie.
Stel nu dat we soms willen dat een bepaalde locatie pas bereikt kan worden indien de gebruiker reeds een bepaald GameObject in zijn bezit heeft. Hiervoor moeten we 2 zaken aanpassen:
We beschrijven in de Exit klasse welk object(en) nodig zijn om deze exit te mogen gebruiken
We controleren of de speler het GameObject heeft wanneer deze naar een nieuwe locatie wil gaan mbv de GetLocationOnMove() methode.
De nieuwe, volledige Exit klasse wordt dan:
class Exit
{
public Exit()
{
NeedsObject = new List<GameObjects>();
}
public Directions ExitDirection { get; set; }
public Location GoesToLocation { get; set; }
public List<GameObjects> NeedsObject { get; set; }
public bool TestPassCondition(List<GameObjects> playerInventory)
{
int passCount = 0;
for (int i = 0; i < NeedsObject.Count; i++)
{
if (playerInventory.Contains(NeedsObject[i]))
passCount++;
}
if (passCount == NeedsObject.Count)
return true;
else
{
return false;
}
}
}
In deze ietwat knullige code tellen we dus of de speler alle GameObjecten in z’n inventory heeft (playerInventory) nodig om deze exit te gebruiken.
Deze methode TestPassCondition gebruiken we nu in de GetLocationOnMove()-methode in de Location klasse om te bepalen of de exit mag gebruikt worden. De methode wordt dan:
public Location GetLocationOnMove(Directions direction, List<GameObjects> playerInventory )
{
foreach (var exit in Exits)
{
if (exit.ExitDirection == direction)
{
if(exit.TestPassCondition(playerInventory))
return exit.GoesToLocation;
else
{
Console.WriteLine("Je kan hier niet langs (je hebt niet alle vereiste items).");
return this;
}
}
}
Console.WriteLine("Dat is geen geldige richting");
return this;
}
Rest ons nu enkel nog de GameManager klasse te maken. Ruw gezien is deze als volgt:
class GameManager
{
public GameManager()
{
InitGame();
}
private Location currentLocation = null;
public bool Exit { get; set; }
public void DescribeLocation()
{
//...
}
public void VerwerkActie()
{
//...
}
public void ToonActies()
{
//...
}
private List<Location> GameLocation = new List<Location>();
private List<GameObjects> Objects = new List<GameObjects>();
private List<GameObjects> playerInventory= new List<GameObjects>();
private void InitGame()
{
//...
}
}
Wat ogenblikkelijk opvalt zijn:
De 3 publieke methoden DescribeLocation,VerwerkActie en ToonActies
Een instantievariabelen currentLocation die een referentie bijhoudt naar de huidige locatie van de speler
3 lijsten met daarin de objecten die de speler heeft (playerInventory), alle objecten in het spel (Objects) en alle locaties in het spel (GameLocation)
Een InitGame() methode waarin we alle gameobjecten, exits en locaties zullen aanmaken bij aanvang van het spel
Een bool Exit zodat de externe gameloop weet wanneer het spel gedaan is
We laten de speler dus toe door n,o,w,z in te typen dat gecontroleerd wordt naar welke nieuwe locatie zal gegaan worden. We passen hierbij de currentLocation property van de GameManager aan naar de, al dan niet nieuwe, locatie.
public void ToonActies()
{
Console.WriteLine("Mogelijke acties: (typ bijvoorbeeld n indien u naar het noorden wil)");
Console.WriteLine("n= noord");
Console.WriteLine("o= oost");
Console.WriteLine("z= zuid");
Console.WriteLine("w= west");
Console.WriteLine("e=exit");
}
In deze methode definiëren nu de volledige spelinhoud. Wil je dus bijvoorbeeld dit spel uitbreiden met extra kamers en objecten, dan doe je dat in deze methode. Ter illustratie tonen we eerst hoe we 2 locaties aanmaken en deze aan elkaar hangen mbv de Exits (waarbij kamer één zich ten zuiden van kamer 2 bevindt)
private void InitGame()
{
//Maak Locaties
Location l1 = new Location()
{
Title = "De poort",
Description = "Je staat voor een grote grijze poort die op een kier staat. Rondom je is prikkeldraad, je kan enkel naar het noorden, door de poort gaan. "
};
Location l2 = new Location()
{
Title = "Receptie",
Description = "De receptie....veel blijft er niet meer over van wat eens een bruisende omgeving was. Hier en daar zie je skeletten van , waarschijnlijk, enkele studenten. Een grote poort staat op een kier naar het zuiden. Je ziet twee deuren aan de westelijke en noordelijke zijde."
};
//Place exits
l1.Exits.Add(new Exit() { ExitDirection = Directions.North, GoesToLocation = l2 });
l2.Exits.Add(new Exit() { ExitDirection = Directions.South, GoesToLocation = l1 });
//Voeg locatie toe
GameLocation.Add(l1);
GameLocation.Add(l2);
currentLocation = l1;
}
Vergeet niet op het einde de 2 kamers toe te voegen aan de GameLocation lijst van de GameManager, alsook in te stellen wat de beginkamer is.
Stel dat we even later in een kamer een sleutel plaatsen die als conditie dient om een andere kamer te kunnen openen. We schrijven dan in de GameInit() methode:
Location l6 = new Location()
{
Title = "Gang",
Description = "Een brede gang waar makkelijk 5 mensen schouder aan schouder door kunnen. Zowel in het oosten als het westen zie je een deur."
};
Location l7 = new Location()
{
Title = "Computerruimte",
Description = "Eindelijk; je hebt het gehaald. De plek waar iedereen naar toe wil: het computerlabo!"
};
//Place objects in rooms
GameObjects keytol7 = new GameObjects() { Description = "Verroest en groot", Name = "Sleutel" };
l5.ObjectsInRoom.Add(keytol7);
//...
l6.Exits.Add(new Exit() { ExitDirection = Directions.West, GoesToLocation = l4 , NeedsObject= new List<GameObjects>(){keytol7}});
l6.Exits.Add(new Exit() { ExitDirection = Directions.East, GoesToLocation = l7 });
//Voeg locatie toe
//..
GameLocation.Add(l6);
GameLocation.Add(l7);
We hebben nu de belangrijkste onderdelen geschreven. We tonen daarom een iets uitgebreider spel, demo zeg maar, waar in we alles gecombineerd in actie zien:
private void InitGame()
{
//Maak Locaties
Location l1 = new Location()
{
Title = "De poort",
Description = "Je staat voor een grote grijze poort die op een kier staat. Rondom je is prikkeldraad, je kan enkel naar het noorden, door de poort gaan. "
};
Location l2 = new Location()
{
Title = "Receptie",
Description = "De receptie....veel blijft er niet meer over van wat eens een bruisende omgeving was. Hier en daar zie je skeletten van , waarschijnlijk, enkele studenten. Een grote poort staat op een kier naar het zuiden. Je ziet twee deuren aan de westelijke en noordelijke zijde."
};
Location l3 = new Location()
{
Title = "Koffieruime",
Description = "Je staat in de koffieruimte achter de receptie. Menig pralinetje is hier vroeger met veel gusto opgesmikkeld. Een lege pralinedoos is het enige bewijs dat het hier ooit gezellig was. Een deur is de enige uitgang uit deze kamer naar het oosten."
};
Location l4 = new Location()
{
Title = "Tuin",
Description = "Het is duidelijk herfst. Een kale boom en vele bruine bladeren op de grond...mistroosteriger kan eigenlijk niet. Je ziet een deur in het zuiden en in het westen en een grote klapdeur naar het noorden."
};
Location l5 = new Location()
{
Title = "Cafetaria",
Description = "Ooit was dit een bruisende locati: veel eten, geroezemoes en licht door de grote ruiten. Nu enkel stof en lege tafel. Enkel een klapdeur is zichtbaar naar het zuiden."
};
Location l6 = new Location()
{
Title = "Gang",
Description = "Een brede gang waar makkelijk 5 mensen schouder aan schouder door kunnen. Zowel in het oosten als het westen zie je een deur."
};
Location l7 = new Location()
{
Title = "Computerruimte",
Description = "Eindelijk; je hebt het gehaald. De plek waar iedereen naar toe wil: het computerlabo!"
};
//Place objects in rooms
GameObjects keytol7 = new GameObjects() { Description = "Verroest en groot", Name = "Sleutel" };
l5.ObjectsInRoom.Add(keytol7);
//Place exits
l1.Exits.Add(new Exit() { ExitDirection = Directions.North, GoesToLocation = l2 });
l2.Exits.Add(new Exit() { ExitDirection = Directions.South, GoesToLocation = l1 });
l2.Exits.Add(new Exit() { ExitDirection = Directions.West, GoesToLocation = l3});
l2.Exits.Add(new Exit() { ExitDirection = Directions.North, GoesToLocation = l4 });
l3.Exits.Add(new Exit() { ExitDirection = Directions.East, GoesToLocation = l2 });
l4.Exits.Add(new Exit() { ExitDirection = Directions.South, GoesToLocation = l2 });
l4.Exits.Add(new Exit() { ExitDirection = Directions.West, GoesToLocation = l6 });
l4.Exits.Add(new Exit() { ExitDirection = Directions.North, GoesToLocation = l7 });
l5.Exits.Add(new Exit() { ExitDirection = Directions.South, GoesToLocation = l4 });
l6.Exits.Add(new Exit() { ExitDirection = Directions.West, GoesToLocation = l4 , NeedsObject= new List<GameObjects>(){keytol7}});
l6.Exits.Add(new Exit() { ExitDirection = Directions.East, GoesToLocation = l7 }); //needs key condition
l7.Exits.Add(new Exit() { ExitDirection = Directions.East, GoesToLocation = l6 }); //Winning room
//Voeg locatie toe
GameLocation.Add(l1);
GameLocation.Add(l2);
GameLocation.Add(l3);
GameLocation.Add(l4);
GameLocation.Add(l5);
GameLocation.Add(l6);
GameLocation.Add(l7);
currentLocation = l1;
}
Maar een eerste uitdaging zou kunnen zijn: hoe kunnen we de speler objecten van de grond laten oprapen en in de inventaris plaatsen? Dat raadsel laten we aan jou over over om op te lossen!
Volgende hoofdstuk toont het gebruik van van de belangrijkste OO concepten in een applicatie waarmee we een huis-plattegrond kunnen visualiseren. Het doel van dit hoofdstuk is zoveel mogelijk elementen van de voorbije hoofdstukken te integreren tot een groter werkend geheel.
Eerst definiëren we een kleine hulpklasse Point die een punt in de ruimte voorstelt. We kunnen deze klasse ook gebruiken om een vector voor te stellen:
class Point
{
private int x;
private int y;
public Point(int inx, int iny)
{
x = inx;
y = iny;
}
public int X
{
get{return x;}
set{x=value;}
}
public int Y
{
get{return y;}
set{y=value;}
}
}
We maken nu een abstracte klasse MapObject, die we vervolgens zullen gebruiken om over te erven zodat nieuwe klassen aangemaakt kunnen worden.
abstract class MapObject
{
private Point location;
private double price ;
private char drawChar;
//Teken object in de console
public abstract void Paint();
}
De variabele Price zal de prijs van het object bevatten, zodat we vlot kunnen berekenen wat de totale kostprijs van onze kaart zal zijn. Location bevat de coördinaten (x,y) waar het object in de console zal getekend moeten worden. drawChar geeft aan met welk karakter het item moet getoond worden.
Belangrijk: Merk op dat deze klasse minimaal is en allerlei essentiële zaken mankeert, zoals minstens een default constructor etc.
Indien je dit project dus in de praktijk wenst te gebruiken dan zal je nog zelf de nodige properties (of get/set-methoden, naar keuze) waarmee je toegang krijgt tot Location, Price krijgt en ook drawChar methode moeten schrijven.
We maken de MapObject klasse expres abstract, we willen voorkomen dat deze klasse rechtstreeks als object in het programma kan gebruikt worden.
Laten we nu een nieuwe klasse aanmaken dat overerft van de abstract klasse MapObject
class WallElement: MapObject
{
public override void Paint()
{}
}
De methode van Paint moeten we verplicht overriden (daar ze abstract was in de base klasse), voorts is het aan te raden om een default constructor te maken. De Paint-methode bevat zeer eenvoudigweg volgende 2 lijntjes code:
We kunnen nu in ons hoofdprogramma (main-methode) al direct elementen op het scherm brengen met bijvoorbeeld volgende code:
WallElement steen1= new WallElement();
steen1.Paint();
Dit geeft,als je een default constructor hebt gemaakt die automatisch ieder object op locatie (1,1) zet,, een sterretje op positie (1,1) op het scherm.
We zouden dus nu bijvoorbeeld meerdere stenen kunnen plaatsen (met verschillende prijs, naargelang de soort) en dan de totaalprijs opvragen.
We hebben nu een basis om andere zaken te maken. Stel dat we grotere objecten op het scherm wensen. We zouden dan kunnen definiëren dat de variabele Location het punt linksboven van het object bepaalt. Volgende nieuwe object erft over van de MapObject en geeft een grotere figuur weer (vierkant, maar je kan natuurlijk je fantasie de vrije loop laten gaan):
class FurnitureElement: MapObject
{
private int unitSize;
public int UnitSize
{
get { return unitSize; }
set { if (value > 0) unitSize = value; }
}
public override void Paint()
{
for (int i = Location.X; i < Location.X + UnitSize; i++)
{
for (int j = Location.Y; j < Location.Y + UnitSize; j++)
{
if (i < Console.WindowWidth && j < Console.WindowHeight)
{
Console.SetCursorPosition(i, j);
Console.Write(DrawChar);
}
}
}
}
}
We kunnen dan eenvoudig weg allerlei meubels definiëren, zoals een zetel:
class ZetelElement: FurnitureElement
{
public ZetelElement()
{
Price = 100;
DrawChar = '+';
UnitSize = 2;
}
}
Of als je de zetel anders wil getekend zien (geen rechthoek bijvoorbeeld, maar iets dat meer op zetel trekt, dan voeg je nog volgende code toe:
public override void Paint()
{
//Code om complexere zetel op scherm te tonen
}
We kunnen nu ongelooflijk veel objecten op het scherm tonen (laten we veronderstellen dat je een overloaded constructor telkens hebt geschreven), met behulp van een List-object, als volgt:
List<MapObject> allObjects= new List<MapObject>(); //lang leve polymorfisme
//Muurtje
for (int i = 0; i <10 ; i++)
{
Point tempLoc= new Point(2+i,3);
WallElement tempWall= new WallElement(tempLoc,'=',10.0);
allObjects.Add(tempWall);
}
//Zetel
allObjects.Add(new ZetelElement(new Point(6,8), 3 ));
//Teken alle objecten
for (int i = 0; i < allObjects.Count; i++)
{
allObjects[i].Paint();
}
Dankzij polymorfisme kunnen we alle objecten die overgeërfd zijn van MapObject in de MapObject-list plaatsen. Wanneer we dan Paint aanroepen gebruiken we de implementatie van het object zelf indien aanwezig.
We geven onze lijst van objecten mee aan ons Menu zodat het Menu object nieuwe zaken aan de map kan toevoegen:
public void GetInput(List<MapObject> list)
{
string input=Console.ReadLine();
if(input=="A" || input=="a")
{
//Voeg randomzetel toe
}
if (input == "B" || input == "b")
{
//Beweeg kaart naar beneden
}
}
We kunnen dan in de main volgende code plaatsen die constant het scherm hertekent en telkens op input van de gebruiker wacht:
List<MapObject> allObjects = new List<MapObject>();
Menu menu= new Menu();
do
{
menu.ShowMenu();
menu.GetInput(allObjects);
Console.Clear();
//Teken alle objecten
for (int i = 0; i < allObjects.Count; i++)
{
allObjects[i].Paint();
}
} while (true);
De map verplaatsen is wederom verrassend eenvoudig. Stel dat je je map naar beneden wenst te verplaatsen als de B wordt ingedrukt; Je update gewoon de locatie van ieder object waarbij de y-positie gewoon met 1 wordt verhoogd:
if (input == "B" || input == "b")
{
//Beweeg kaart naar beneden
for(int i=0;i<list.Count;i++)
{
list[i].Location = new Point(list[i].Location.X, list[i].Location.Y + 1);
}
}
Voorts kunnen we bijvoorbeeld nu meerdere klassen aanmaken (tafels, stoelen, deuren, etc) en dan een composiet-klasse aanmaken die bijvoorbeeld een volledig salon beschrijft, de code zou er dan als volgt kunnen uitzien:
class SalonElement: MapObject
{
private List<MapObject> elementen= new List<MapObject>();
public SalonElement(Point salonLoc)
{
elementen.Add(new ZetelElement(new Point(2, 2), 3, '+'));
elementen.Add(new ZetelElement(new Point(5, 9), 3, '+'));
Location = salonLoc;
}
public override void Paint()
{
for (int i = 0; i < elementen.Count; i++)
{
elementen[i].Paint();
}
}
}
Merk op dat we rekening moeten houden met het feit dat de locatie van het salon het punt linksboven is, en dat dus de nieuwe locaties van de zetels vanaf dit punt hun oorsprong hebben. Althans dat willen we.. Als we in het main-programma dan schrijven:
SalonElement salon1= new SalonElement(new Point(6,5));
salon1.Paint();
Dan verschijnen onze zetels wel, maar niet op de locatie zoals we wilden (nu verschijnen de zetels op locatie (2,2) en (5,9), terwijl we liever hebben dat ze verschijnen op (2+6, 2+5) en (5+6, 9+5), dus rekening houdende met de locatie van het salon zelf
Telkens we dus UpdateElements aanroepen dan worden alle elementen die bij het object horen ook geüpdatet.
Nu rest ons nog één aanpassing, dat is ervoor zorgen dat deze methode ook effectief telkens wordt aangeroepen. De methode moet aangeroepen worden telkens we een aanpassing aan de Location van het SalonElement doen. Hierbij controleren we eerst of de locatie überhaupt al geïnitialiseerd is (anders is deze waarde gelijk aan ‘null’). Vervolgens berekenen we de offset, dit is het verschil tussen de huidige en de nieuwe locatie van de composietklasse.
Daar Location bij MapObject hoort, moeten we dus in die klasse een aanpassing doen. We bereiden daarom de Locationproperty uit als volgt:
public Point Location
{
get { return location; }
set
{
Point prevloc = location;
Point offset = new Point(1, 1);
if (location != null)
{
offset.X = value.X - prevloc.X;
offset.Y = value.Y - prevloc.Y;
}
location = value;
if (this is IComposite)
{
IComposite obj = this as IComposite;
obj.UpdateElements(offset);
}
}
}
Deze code kan misschien wat toelichting gebruiken:
Telkens we de set aanroepen van Location (dus in bijvoorbeeld allObjects[0].Location= new Point(10,10);) dan veranderen sowieso de locatie van het object naar de nieuwe waarde.
We bewaren de huidige locatie zodat we de offset kunnen berekenen.
Indien er een ‘huidige locatie’ is (location!=null) dan berekenen we de offset in de x en de y richting.
Nu passen we de locatie van de composietklasse aan.
Vervolgens kijken we of het object in kwestie (aangegeven met this, daar we in het object zelf zitten) de IComposite interface ‘heeft’.
Als dit zo is dan zetten we het object even om naar een IComposite-object zodat we de UpdateElements()-methode kunnen aanroepen.
We kunnen nu dus zelfs een volledig Huis als klasse beschrijven en zo verschillende soorten huizen definiëren. Telkens we dan een huis verplaatsen dan verplaatst de hele inboedel mee.
Belangrijk: Het gebruik van de interface is hier louter illustratief. Dit probleem kan je beter oplossen door een CompositeElement klasse aan te maken die overerft van MapObject. Deze klasse bevat dan een lijst van elementen en een UpdateElements methode. In MapObject controleer je dan of een object van het type CompositeElement is (ipv IComposite)
Een nog betere oplossing is die waarbij je gewoon direct zegt dat MapObject een lijst van elementen kan bevatten. Als een MapObject exact 1 element in zijn lijst bevat dan is de werking dezelfde als ervoor, maar nu kunnen we dus zonder veel code aanpassingen ook composiet objecten aanmaken.
Ga naar (deze site)[https://github.com/timdams/MapEditor_LearnSomeWPF] en volg de pdf daar. Deze oefening toont hoe je van start gaat met een console-applicatie en die dan stelselmatig zal omzetten naar een echte grafische Windows applicatie (WPF).
Dit project hoort niet bij de leerstof, daar het het concept van API gebruikt dat we nog niet hebben gezien. Dit is echter zo eenvoudig dat ik hoop dat het sommige studenten zin geeft om verder exploreren.
Volgende voorbeeld is gebaseerd op een oude versie van de nuget package en zal dus niet meer werken met de huidige. De auteur van dit boek (ikke) is te lui om de tutorial aan te passen en verwijst daarom naar hier waar tal van codevoorbeelden staan!
We maken een applicatie die aan de gebruiker alle edities van Magic toont. De gebruiker kiest vervolgens van welke editie hij een 'boosterpack' wenst te generen (boosterpack= pakje kaarten dat je in de winkel kan kopen met daarin een vast aantal kaarten waarvan ook steeds minstens 1 zeldzame kaart).
SetService service = new SetService();
var result = service.All();
foreach (var set in result.Value)
{
Console.WriteLine($"{set.Name} ({set.Code})");
}
var boosterresult = service.GenerateBooster(code);
var boosterpack = boosterresult.Value;
if (boosterpack != null)
{
for (int i = 0; i < boosterpack.Count; i++)
{
Console.WriteLine($"{i}:{boosterpack[i].Name}");
}
}
Console.WriteLine("Welke kaart wenst u meer info");
int keuze = Convert.ToInt32(Console.ReadLine());
Console.Clear();
MtgApiManager.Lib.Model.Card chosenCard = boosterpack[keuze];
Console.WriteLine(chosenCard.Name);
Console.WriteLine(chosenCard.Text);
Console.WriteLine(chosenCard.Rarity);
Console.WriteLine("Druk op enter om afbeelding te tonen");
Console.ReadLine();
System.Diagnostics.Process.Start(chosenCard.ImageUrl.ToString());
SetService service = new SetService();
var result = service.All();
foreach (var set in result.Value)
{
Console.WriteLine($"{set.Name} ({set.Code})");
}
Console.WriteLine("Voor welke set wil je booster (voer code tussen haakjes in)?");
string code = Console.ReadLine().ToLower();
bool isValid = false;
foreach (var set in result.Value)
{
if (set.Code.ToLower() == code)
{
isValid = true;
break;
}
}
if (isValid)
{
var boosterresult = service.GenerateBooster(code);
var boosterpack = boosterresult.Value;
if (boosterpack != null)
{
for (int i = 0; i < boosterpack.Count; i++)
{
Console.WriteLine($"{i}:{boosterpack[i].Name}");
}
Console.WriteLine("Welke kaart wenst u meer info");
int keuze = Convert.ToInt32(Console.ReadLine());
Console.Clear();
MtgApiManager.Lib.Model.Card chosenCard = boosterpack[keuze];
Console.WriteLine(chosenCard.Name);
Console.WriteLine(chosenCard.Text);
Console.WriteLine(chosenCard.Rarity);
Console.WriteLine("Druk op enter om afbeelding te tonen");
Console.ReadLine();
System.Diagnostics.Process.Start(chosenCard.ImageUrl.ToString());
}
else
{
Console.WriteLine("Iets is mislukt, sorry");
}
}
Dit is niet echt een oefening, eerder een "wist-je-datje".
Wist je dat er op github.com ongelooflijk veel C#-remakes en plugins bestaat van/voor bekende en minder bekende games. Een leuke oefening is:
Deze broncode eens te bekijken (meestal in de "src" map) en proberen te begrijpen waarvoor ieder deel voor dient (en waarom ze het zo hebben opgelost).