Files
Pacman-Project/snake-wpo/adt-level.rkt
joren cd70055bc7 Refactor(English): Rename all files and identifiers from Dutch to English
Renamed files: constanten→constants, adt-positie→adt-position,
adt-doolhof→adt-maze, adt-sleutel→adt-key, adt-tijdslimiet→adt-timer,
adt-teken→adt-draw, adt-spel→adt-game. All message names, variables,
comments, and tests converted to English.

Also fixed counter location bug (time-label x/y were swapped).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 11:06:32 +01:00

183 lines
6.8 KiB
Racket

#lang r7rs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Level ADT ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-library ()
(import (scheme base)
(snake-wpo adt-appel)
(snake-wpo adt-positie)
(snake-wpo adt-slang)
(snake-wpo hulp-procedures)
(snake-wpo constanten))
(export maak-level)
(begin
;; Dit voorbeeldspel bestaat uit slechts 1 level. We zouden de appel en slang
;; rechtstreeks in het Spel ADT kunnen geïmplementeerd hebben. Maar, als we
;; later echter zouden beslissen om een nieuw soort level toe te voegen dan moet
;; niet heel het Spel ADT aangepast worden. Door deze opsplitsing te maken moet
;; alleen de implementatie van het Level ADT aangepast worden.
;; maak-level :: number, number -> level
(define (maak-level aantal-cellen-breedte aantal-cellen-hoogte)
(let* ((slang-start-positie
(maak-positie (quotient aantal-cellen-breedte 2)
(quotient aantal-cellen-hoogte 2)))
(slang-object (maak-slang slang-start-positie))
(appel-object #f)
(appel-tijd 0)
(slang-tijd 0))
;;
;; Hulpprocedures
;;
;; Deze procedures genereren een random positie in de spelwereld.
;; In dit eenvoudig spel is er geen check om te controleren of er al een
;; object op de gegenereerde locatie is.
;; random-x-waarde :: / -> number
(define (random-x-waarde)
(random aantal-cellen-breedte))
;; random-y-waarde :: / -> number
(define (random-y-waarde)
(random aantal-cellen-hoogte))
;;
;; Logica Appel
;;
;; Deze is hier geïmplementeerd omdat voor een appel op een nieuwe positie
;; te zetten, de afmetingen van het spelbord geweten moeten worden.
;; Als dit geïmplementeerd zou zijn in het Appel ADT, dan zou het Appel ADT
;; ook afhankelijk zijn van het Level ADT. Om deze afhankelijkheid te
;; vermijden is deze logica hier geïmplementeerd.
;; random-positie :: / -> positie
(define (random-positie)
(let ((x (random-x-waarde))
(y (random-y-waarde)))
(maak-positie x y)))
;; randomise-appel! :: / -> /
(define (randomise-appel!)
(if appel-object
(let ((nieuwe-positie (random-positie))
(appel-positie (appel-object 'positie)))
;; Verplaats de appel naar een nieuwe positie!
((appel-positie 'x!) (nieuwe-positie 'x))
((appel-positie 'y!) (nieuwe-positie 'y))
;; Reset de timer
(set! appel-tijd 0))))
;; nieuwe-appel! :: / -> /
(define (nieuwe-appel!)
(set! appel-object (maak-appel (random-positie)))
;; Vergeet ook niet om de `adt-appel`-library te importeren (zie bovenaan).
;; Alternatieve oplossing:
;; Je kan ook in de `let*` bovenaan (lijn 17) de `appel-object` variabele
;; initialiseren met `(maak-appel (maak-positie 2 2))`. Merk op dat
;; de `(random-positie)` procedure hier nog niet gedefinieërd is en je deze
;; dus elders moet implementeren.
(set! appel-tijd 0))
;; beweeg-appel! :: / -> /
(define (beweeg-appel! delta-tijd)
(set! appel-tijd (+ appel-tijd delta-tijd))
(if (> appel-tijd appel-refresh-rate)
(randomise-appel!)))
;;
;; Logica Slang
;;
;; We hebben ervoor gekozen om alle logica dat te maken heeft met het
;; bewegen van de slang in het Level ADT zelf te implementeren. Dit omdat
;; een deel van de logica voor het bewegen afhankelijk is van de positie
;; van de appel. We zouden er ook voor gekozen kunnen hebben om deze in het
;; Slang ADT zelf te implementeren, maar dan moet het Slang ADT toegang
;; krijgen tot informatie dat bij het level hoort.
;; Het voordeel van dit hier te implementeren is dat we geen complexiteit
;; toevoegen om die data te delen. Het nadeel is dat een deel van de logica
;; die conceptueel bij het Slang ADT zou moeten horen, niet in het Slang ADT
;; geïmplementeerd is.
;; Bepaal in je eigen project wanneer je welke methode toepast! Je gemaakte
;; keuzes moeten zorgen tot een goede codekwaliteit.
;; beweeg-slang! :: / -> /
(define (beweeg-slang!)
(if (> slang-tijd slang-snelheid)
(begin
;; Laat de slang 1 eenheid "vooruit" bewegen
(slang-object 'beweeg!)
;; Kijk of de slang botst met de appel.
(if appel-object
(let* ((appel-positie (appel-object 'positie))
(overlappingen ((slang-object 'voor-alle-stukken)
(lambda (stuk)
((appel-positie 'vergelijk?) (stuk 'positie))))))
(if (member #t overlappingen)
(begin (slang-object 'verleng!)
(nieuwe-appel!)))))
;; Reset de timer.
(set! slang-tijd 0))))
;; draai-slang! :: symbol -> /
(define (draai-slang! toets)
(cond
((eq? toets 'right)
((slang-object 'richting!) 'rechts))
((eq? toets 'left)
((slang-object 'richting!) 'links))
((eq? toets 'up)
((slang-object 'richting!) 'omhoog))
((eq? toets 'down)
((slang-object 'richting!) 'omlaag))))
;;
;; Algemene Logica
;;
;; update! :: number -> /
(define (update! delta-tijd)
(set! slang-tijd (+ slang-tijd delta-tijd))
(beweeg-appel! delta-tijd)
(beweeg-slang!))
;; toets :: any -> /
(define (toets! toets)
(draai-slang! toets))
;;
;; Initialisatie
;;
(nieuwe-appel!)
;;
;; Dispatch
;;
(define (dispatch-level msg)
(cond ((eq? msg 'update!) update!)
((eq? msg 'toets!) toets!)
((eq? msg 'appel) appel-object)
((eq? msg 'slang) slang-object)
(else (error "Level ADT -- Onbekend bericht:" msg))))
dispatch-level))))