T8 Epidemiesimulatoropdracht
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
Begrijp de code:
- 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);
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.
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 - Menseen nieuw attribuut- isBesmet. Dit attribuut initialiseer je in de constructor op- false. Je hoeft hiervoor dus geen argument aan je constructor toe te voegen.
- 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 - showzo, dat een mens als rood vierkant wordt getekend als deze besmet is. Als het goed is, wordt één vierkant nu rood getekend.
- 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;
}
- Nu moeten we in drawcode 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 eenfor-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.
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 - mensengaat 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- mensenin- actoren. Dat kan in GitPod heel handig: Zoek de regel waar je de- mensenals globale variabele declareert. Waarschijnlijk staat er- var mensen;. Klik met de rechtermuisknop op- mensenen 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 - Menseen 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 - setupna de 25 mensen ook 10 katten toe aan de simulatie. Geef de katten een random snelheid tussen -2 en 2.
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 Doktertoe aan je code en voeg 1 dokterobject toe aan de actoren. Controleer of de dokter verschijnt en anderen geneest.
b)
- Maak MensenKatsubklassen vanActor. Bedenk goed welke code weg mag en welke code veranderd moet worden. Eén methode blijft onveranderd. Weet je welke?
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.
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 Mensbegint bij 400 en voor eenKatbegint op 200. Bij iedere aanroep van de methodeupdatewordt de afteltimer 1 kleiner. Als de afteltimer 0 is, wordt het attribuutisBesmetweer opfalsegezet. Vraag jezelf hiervoor het volgende af:- in welke klasse definieer je besmettelijkheidsTeller?
- hoe zorg je dat besmettelijkheidsTellerwordt ingesteld wanneer er een besmetting plaatsvindt? Tip: maak een methodebesmet()dieisBesmetoptruezet EN debesmettelijkheidsTellerinstelt.
- hoe maak je het verschil in gedrag tussen MensenKat? 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 besmettelijkheidsTelleralsupdatewordt aangeroepen en de actor is niet besmet?
- wat gebeurt er met de besmettelijkheidsTellerals deze aan het aflopen is en er opnieuw contact is met een andere, besmette, actor?
 
- in welke klasse definieer je 
Speel gerust eens met de waarden van de besmettelijkheidsTeller of het aantal dokters om te zien wat er in je simulatie gebeurt.
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.jsetc.
- 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:
 voor ieder bestand nieuwe regel toe zoals:<script id="canvas" src="script.js"></script><script src="actor.js"></script>
- we maken voor iedere klasse een apart bestand aan, zoals 
- Maak zelf een heel nieuwe actor voor de simulatie. Je mag zelf weten of het een directe subklasse van Actor,Mens,KatofDokteris, 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.