T8 Verwerkingsopdrachten 2324

Inleiding

Om te leren hoe je objectgeoriënteerd programmeert, gaan we stap voor stap een objecgeoriënteerd programma maken. We maken hiervoor een epidemiesimulator die visueel maakt hoe organismen elkaar kunnen besmetten met een ziekteverwekker. Tussen de opdrachten door vind je theorie over objectgeoriënteerd programmeren.

Opdracht 0 - Klaar voor de start

Start een eigen repo en begrijp de code:

  • Ga naar GitHub classroom en schrijf je in voor de opdracht ‘Epidemiesimulator’
  • Bekijk in je browser wat de simulator nu al doet. De simulator doet nog niet veel: het laat een vierkantje bewegen en stuiteren tegen de randen van het scherm.
  • Bekijk de code van de simulator. In de code zie je globale variabelen die de positie en de horizontale en verticale snelheid bevatten. Ook zie je de constante BREEDTE, die de waarde van de grootte van het vierkantje bevat.
var x;
var y;
var speedX;
var speedY;

const BREEDTE = 20;

In setup krijgen deze variabelen hun initiële waarde. De positie is in het midden van het canvas. (Het midden van het vierkant is overigens niet exact in het midden. De waarden x en y worden gebruikt voor de linkerbovenhoek…) De horizontale en verticale snelheid krijgen bij de start een random waarde tussen -5 en 5.

x = width / 2;
y = heigth / 2;
speedX = random(-5, 5);
speedY = random(-5, 5);

In draw wordt netjes een wit vierkantje getekend met behulp van de waarden van x, y en BREEDTE. Herinner je je nog dat de functie rect een vierkant tekent met de linkerbovenhoek op de meegeven positie?

rect(x, y, BREEDTE, BREEDTE);

Lees nu hoofdstuk 1 van de theorie





Opdracht 1 – 25 random ‘mensen’ maken. En wat doen die katten daar? 😼

In de theorie van hoofdstuk 1 is een heel groot deel van de klasse Mens gegeven. Je maakt deze klasse verder af en gebruikt deze om 25 mensobjecten te maken die zich in onze simulatie bewegen:

Programmeren

a) 25 random mensen

We gaan nu de array mensen vullen met 25 random mens-objecten. Verwijder de code die je bij opdracht 2 in setup hebt gezet om handmatig 5 mens-objecten te maken. Schrijf in plaats daarvan deze code:

// maak 25 random mensen
for (var teller = 0; teller < 25; teller++) {
  // we moeten ze niet te dicht bij de rand tekenen
  // om geen problemen met stuiteren te krijgen
  var ruimteTotRand = 50;
  
  // creëer random positie en snelheid
  var randomX = random(ruimteTotRand, width - ruimteTotRand);
  var randomY = random(ruimteTotRand, height - ruimteTotRand);
  var randomSpeedX = random(-5, 5);
  var randomSpeedY = random(-5, 5);

  // maak nieuw mensobject
  var nieuwMens = new Mens(randomX, randomY, randomSpeedX, randomSpeedY);
  
  // voeg mensobject toe aan array
  mensen.push(nieuwMens);
}

Deze code maakt 25 keer een nieuw mens-object met random waarden aan en voegt deze toe aan de array mensen. Zorg ervoor dat je deze regels begrijpt. Uitleg over push vind je onder andere op de shite van w3schools Bekijk het resultaat. Als het goed is, heb je nu 25 vierkantjes die door elkaar heen vliegen en tegen de randen stuiteren.

Controleer je code

b) besmettingen

Het wordt tijd dat deze mensen elkaar kunnen besmetten. Het idee is dat mensen elkaar besmetten als ze elkaar in hun beweging overlappen.

  • Geef de klasse Mens een nieuw attribuut isBesmet. Dit attribuut initialiseer je in de constructor op false. Je hoeft hiervoor dus geen argument aan je constructor toe te voegen.

    Hint

  • Voeg in setup, na de for-loop die de 25 mensen aanmaakt, deze regel code toe:

    mensen[0].isBesmet = true;
    

    Hierdoor wordt alvast één mens besmet.

  • Verander de code in de methode show zo, dat een mens als rood vierkant wordt getekend als deze besmet is. Als het goed is, wordt één vierkant nu rood getekend.

    Hint

  • Vervolgens maken we een methode die kan controleren of een ander mens-object overlap heeft met het object dat de methode uitvoert. Ga voor jezelf na of je de volgende zin begrijpt: Omdat een mens getekend wordt als een vierkant, overlappen twee mensen elkaar als één van de hoeken van het ene vierkant zich binnen de randen van het andere vierkant bevindt. Onderstaande code bevat het begin van de methode isOverlappend. Voeg deze code toe aan de klasse Mens.

isOverlappend(andereMens) {
  // zet teruggeefwaarde standaard op false
  var overlappend = false;

  // zet teruggeefwaarde op true als er een overlap is
  if ( (this.x + this.breedte >= andereMens.x &&
        this.x <= andereMens.x + andereMens.breedte &&
        this.y + this.breedte >= andereMens.y &&
        this.y <= andereMens.y + andereMens.breedte)
      ) {

    overlappend = true;
  }

  // stuur de teruggeefwaarde terug
  return overlappend;
}
Uitleg
  • Nu moeten we in draw code toevoegen die alle mogelijke paren van mensobjecten controleert of ze overlappen. Indien ze overlappen, controleren we of een van die objecten besmet is. Als dat zo is wordt het andere ook besmet (als het dat nog niet is). Een simpele manier om dit te controleren is in een for-loop ieder object te controleren met ieder ander object, behalve zichzelf. Dit ziet er zo uit:
// ga alle mensen langs
for (var i = 0; i < mensen.length; i++) {
  var mensA = mensen[i];
  // ga met mensA opnieuw alle mensen langs om te checken op overlap, behalve met zichzelf
  for (var j = 0; j < mensen.length; j++) {
    var mensB = mensen[j];
    if (mensA != mensB) {
      // check overlap
      var mensenOverlappen = mensA.isOverlappend(mensB);
      if (mensenOverlappen) {
        // check of er een besmetting optreedt
        if (mensA.isBesmet || mensB.isBesmet) {
          // als er één besmet is, wordt ze allebei besmet
          // als ze allebei besmet zijn, verandert deze code niets.
          mensA.isBesmet = true;
          mensB.isBesmet = true;
        }
      }
    }
  }
}

Ga de code eens regel voor regel af en leg aan jezelf (of je buur) uit wat hier gebeurt.

Controleer je code

c) katten… 🐈

Helaas komen de gezondheidsinstanties erachter dat ook katten een rol spelen in de verspreiding van de ziekte. We zullen ook deze moeten opnemen in onze simulatie.

  • De array mensen gaat ook dieren bevatten. Het is raar als deze naam hetzelfde blijft. Alle ‘dingen’ die iets in onze simulatie doen, heten ‘actoren’. Verander door je hele code de naam van de array mensen in actoren. Dat kan in GitPod heel handig: Zoek de regel waar je de mensen als globale variabele declareert. Waarschijnlijk staat er var mensen;. Klik met de rechtermuisknop op mensen en kies in het menu dat verschijnt ‘Rename Symbol’. Wanneer je op deze manier de naam wijzigt, wordt de naam van deze variabele overal gewijzigd. Wel moet je nog even door de comments gaan om te zien of je ook daar misschien ‘mensen’ moet wijzigen in ‘actoren’

  • Maak onder de klasse Mens een nieuwe klasse met de naam Kat. Laat deze precies hetzelfde doen als Mens, maar met deze verschillen:

    • de breedte van een kat is 10 pixels
    • een niet-besmette kat is blauw in plaats van wit
    • een besmette kat is oranje in plaats van rood
  • Voeg in setup na de 25 mensen ook 10 katten toe aan de simulatie. Geef de katten een random snelheid tussen -2 en 2.

    Hint

Controleer je code





Lees nu hoofdstuk 2 van de theorie





Opdracht 4

In de theorie van hoofdstuk 2 heb je de gezien hoe de code van de superklasse Actor eruit ziet. Je gaat nu de code van Mens en Kat aanpassen.

Programmeren

a)

  • Voeg, zoals in de theorie voorgedaan, de klasse Dokter toe aan je code en voeg 1 dokterobject toe aan de actoren. Controleer of de dokter verschijnt en anderen geneest.

Controleer je code

b)

  • Maak Mens en Kat subklassen van Actor. Bedenk goed welke code weg mag en welke code veranderd moet worden. Eén methode blijft onveranderd. Weet je welke?
    Hint
    Hint

Controleer je code

c)

  • Vervolgens gaan we de ‘statistieken’ van onze simulatie laten zien. De verantwoordelijkheid voor deze code ligt niet bij een van de actoren, maar bij het ‘raamwerk’ van de simulatie. Deze code schrijven we daarom in dit geval onder draw. Zorg dat je op die plek met behulp van de p5js-functie text twee regels in de linkerbovenhoek plaatst: een met het aantal onbesmette actoren en een met het aantal besmette actoren.
    Hint
    Hint

Controleer je code

d)

  • Iedere actor die eenmaal besmet is, wordt in onze simulatie nooit meer beter, tenzij de dokter langskomt. Dat moet veranderen. Actoren moeten ook uit zichzelf weer beter kunnen worden. We gaan daarvoor een teller maken die bij besmetting voor een Mens begint bij 400 en voor een Kat begint op 200. Bij iedere aanroep van de methode update wordt de afteltimer 1 kleiner. Als de afteltimer 0 is, wordt het attribuut isBesmet weer op false gezet. Vraag jezelf hiervoor het volgende af:
    • in welke klasse definieer je besmettelijkheidsTeller?
    • hoe zorg je dat besmettelijkheidsTeller wordt ingesteld wanneer er een besmetting plaatsvindt? Tip: maak een methode besmet() die isBesmet op true zet EN de besmettelijkheidsTeller instelt.
    • hoe maak je het verschil in gedrag tussen Mens en Kat? Als je het in kleine stapjes wilt doen:
      • Maak het eerst werkend voor één klasse.
      • Maak het daarna werkend voor de andere klasse.
      • Verplaats waar mogelijk dubbele code naar Actor.
    • wat gebeurt er met de besmettelijkheidsTeller als update wordt aangeroepen en de actor is niet besmet?
    • wat gebeurt er met de besmettelijkheidsTeller als deze aan het aflopen is en er opnieuw contact is met een andere, besmette, actor?

Controleer je code

Speel gerust eens met de waarden van de besmettelijkheidsTeller of het aantal dokters om te zien wat er in je simulatie gebeurt.





Lees nu hoofdstuk 3 van de theorie





opdracht 5

Programmeren
  • In de theorie van hoofdstuk 3 is een heel aantal veranderingen genoemd. Verander je code zo, dat de genoemde attributen private worden en ze de juiste getters en setters hebben.
  • Alle code staat nog in één bestand: script.js. Dit is niet handig als je code gemakkelijk herbruikbaar wilt maken. Daarom doen we het volgende:
    • we maken voor iedere klasse een apart bestand aan, zoals actor.js, mens.js etc.
    • je javascript wordt uitgevoerd binnen de HTML-pagina index.html. Het JavaScript-bestand wordt hierin netjes geladen. Nu we de code hebben verdeeld over meerdere bestanden, moeten we ook aangeven dat deze worden geladen. Voeg boven de regel:
    <script id="canvas" src="script.js"></script>
    
    voor ieder bestand nieuwe regel toe zoals:
    <script src="actor.js"></script>
    
  • Maak zelf een heel nieuwe actor voor de simulatie. Je mag zelf weten of het een directe subklasse van Actor, Mens, Kat of Dokter is, zolang je maar geen code in (één van de) superklassen gaat veranderen om jouw nieuwe klasse te laten werken. Zet deze code in een los bestand.
  • Maak een volledig UML klassendiagram van de vijf klassen die in jouw simulatie voorkomen.
  • Wissel met een klasgenoot jullie zelfbedachte actorklassen uit en neem deze op in je eigen simulatie. Als het goed is, heb je niet veel code nodig om dit voor elkaar te krijgen.
    Hint





Lees nu hoofdstuk 4 van de theorie





Opdracht 6

In deze opdracht maak je een eigen klasse in C++. Kies uit de volgende twee klassen:

  • Een klasse die twee LEDs om en om laat knipperen, dus als de waarschuwingslichten bij een spoorwegovergang. Deze lichten kunnen ook in zijn geheel uit staan.
  • Een klasse die een knop uitleest. Bij het indrukken van de knop wisselt de status van het bebehorende object van aan naar uit en andersom.
a) uitdenken

Maak, met theorie van het hoofdstuk 4 in je achterhoofd, een beschrijving (d.w.z. een UML-schets en informele beschrijving van methoden) van de nieuwe klasse. Probeer uit hoever je kan bedenken wat er allemaal in de klasse moet komen.

b) programmeren
  • Maak in C++ de klasse zoals je die hebt bedacht.
  • Test de klasse uit en pas aan waar nodig, totdat deze werkt zoals gevraagd.
c) uitbreiden
  • Heb je gekozen voor de waarschuwingslichten? Kun je het zo maken dat je de knippersnelheid kunt aanpassen? Op welke manier maak je deze eigenschap toegankelijk voor andere programmeurs?
  • Heb je gekozen voor de knop. Kun je het zo maken dat de lichte storing die optreedt rond het indrukken van de knop weggefilterd wordt? Je noemt dit debouncen. Check deze voorbeeldcode voor een idee.