Racetrack Playa is een schilderachtig opgedroogd meer in Death Valley National Park (Californië, VSA). Dit uitzonderlijk vlak en horizontaal meer ligt op 1130 m boven de zeespiegel en is aan de noordkant slechts 4 cm hoger dan aan de zuidkant. Tijdens perioden van zware regenval vloeit water uit de bergen naar Racetrack Playa, waar het kortstondig een ondiep meer vormt. De hete woestijnzon doet het dunne laagje water snel verdampen, waardoor een zachte gladde modderlaag overblijft. Bij het opdrogen krimpt en scheurt de modder tot een mozaïekpatroon van aaneengesloten veelhoeken.
Het meer is vooral bekend omwille van een mysterieus geologisch fenomeen van “zeilende rotsblokken” die bewegen zonder interventie van mensen of dieren en daarbij lange sporen in de zachte grond achterlaten. Rotsblokken met een ruwe onderkant laten rechte gegroefde sporen na, terwijl rotsen met een platte onderkant de neiging hebben om af te dwalen. Soms kantelen de rotsblokken en komen daarbij met een andere zijde op de grond te liggen, waardoor ze plots een ander spoor achterlaten. De sporen verschillen zowel in richting als in lengte. Rotsblokken die in elkaars buurt liggen, kunnen bijvoorbeeld eerst een tijdje parallel bewegen en daarna plotseling naar links of naar rechts uitwijken, of zelfs rechtsomkeer maken.
De sporen werden voor het eerst waargenomen en bestudeerd aan het begin van de twintigste eeuw. Daaruit bleek onder andere dat de rotsblokken eens om de twee à drie jaar bewegen en dat hun sporen doorgaans drie à vier jaar zichtbaar blijven. Er zijn in de loop der jaren heel wat uiteenlopende theorieën aangebracht om het bewegen van de rotsblokken te verklaren. Zo dacht men bijvoorbeeld dat de rotsblokken voortgedreven werden door sterke winterwinden (tot 145 kilometer per uur), door drijvende ijsschotsen die zich aan het wateroppervlak vormen of door ijskragen die rond de stenen groeien en als een soort parachute fungeren.
Tijdens de winter van 2013-2014 slaagden geologen van het Scripps Institute of Oceanography1 er uiteindelijk in om de bewegingen van de rotsblokken te registeren met behulp van GPS en time-lapse-fotografie2. Op 20 december 2013 konden ze minstens 60 bewegende rotsblokken waarnemen, waarvan sommige zich tussen december 2013 en januari 2014 tot 224 meter verplaatsten in verschillende fasen. Hun studie weerlegde eerdere hypothesen die de bewegingen toeschreven aan de wind of aan dikke ijslagen die rotsen voortstuwen. In plaats daarvan stelden ze vast dat de rotsblokken bewegen wanneer een ijslaag van slechts een paar millimeter dik begint te smelten tijdens perioden met lichte wind. Als deze flinterdunne ijsvliezen over het smeltwater schuiven, kunnen ze de rotsblokken meevoeren tot maximaal vijf meter per minuut. Hoe massieve rotsblokken van honderden kilogrammen bewegen en waarom er soms stenen ontbreken op het einde van een spoor blijft voorlopig een raadsel.
In deze opgave stellen we een rotsblok voor als een balkvormig object. Het blok ligt altijd op het grondvlak (XY-vlak) van een driedimensionale ruimte met een vast assenstelsel zoals aangegeven in onderstaande figuur. Het blok wordt steeds bekeken vanuit een standpunt langs de positieve X-as in de richting van het YZ-vlak. Het voorvlak van het blok ligt altijd parallel met het YZ-vlak. De afmetingen van het blok worden beschreven door zijn breedte \(B \in \mathbb{N}_0\) (gemeten langs de X-as), lengte \(L \in \mathbb{N}_0\) (gemeten langs de Y-as) en hoogte \(H \in \mathbb{N}_0\) (gemeten langs de Z-as). De positie van het blok wordt beschreven aan de hand van de positie van het hoekpunt \((x,y)\) linksonder in het voorvlak (in de figuur aangeduid met een zwarte stip), waarbij geldt dat \(x, y \in \mathbb{Z}\).
De oppervlakte \(A\) van het rotsblok wordt gegeven door: \(A = 2(L\cdot B + L\cdot H + H\cdot B)\)
Het volume \(V\) wordt gegeven door: \(V = L\cdot H\cdot B\)
De lengte van de binnendiagonale lijn \(d\) wordt gegeven door:\(d = \sqrt{L^2 + H^2 + B^2}\)
Er zijn twee manieren waarop het rotsblok kan bewegen: schuiven of kantelen. Het rotsblok kan over zijn volledige lengte naar links of naar rechts schuiven, of kan over zijn volledige breedte naar voor of naar achter schuiven. Dit wordt geïllustreerd in onderstaande figuren.
Het rotsblok kan ook naar links, rechts, voor of achter kantelen. Dit wordt geïllustreerd in onderstaande figuren.
Gevraagd wordt om een klasse Blok
te definiëren waarmee rotsblokken kunnen voorgesteld worden die afmetingen en een positie hebben zoals hierboven beschreven, en die ook op de twee aangegeven manieren kunnen bewegen. Deze klasse moet minstens de volgende methoden ondersteunen:
lengte
, hoogte
, breedte
waaraan gehele getallen moeten doorgegeven worden die respectievelijk de lengte, de hoogte en de breedte van het blok aangeven. De constructor heeft ook nog een optionele vierde parameter positie
waaraan een lijst van twee gehele getallen kan doorgegeven worden dat de positie aangeeft van het hoekpunt linksonder in het voorvlak. Indien geen vierde parameter wordt meegegeven, dan ligt dit hoekpunt in de oorsprong \((0,0)\) van het grondvlak.toObject
(zonder argumenten) die een object (Object) teruggeeft dat de lengte, hoogte, breedte en positie van het blok bevat.oppervlakte
(zonder argumenten) die de oppervlakte van het blok teruggeeft.volume
(zonder argumenten) die het volume van het blok teruggeeft.diagonaal
(zonder argumenten) die de lengte van de binnendiagonale lijn teruggeeft.schuif
waaraan een string moet doorgegeven worden die bestaat uit één enkele letter. Deze letter geeft de richting aan waarin de methode het blok moet verschuiven: links (L
), rechts (R
), voor (V
) of achter (A
). De methode moet een verwijzing teruggeven naar het Blok
-object waarop de methode wordt aangeroepen, zodat het aanroepen van methoden kan aaneengeschakeld worden. Indien aan de methode geen hoofdletter wordt doorgegeven die overeenkomt met één van de vier richtingen, dan moet de methode een AssertionError
opwerpen met de boodschap ongeldige richting
.kantel
waaraan een string moet doorgegeven worden die bestaat uit één enkele letter. Deze letter geeft de richting aan waarin de methode het blok moet kantelen: links (L
), rechts (R
), voor (V
) of achter (A
). De methode moet een verwijzing teruggeven naar het Blok
-object waarop de methode wordt aangeroepen, zodat het aanroepen van methoden kan aaneengeschakeld worden. Indien aan de methode geen hoofdletter wordt doorgegeven die overeenkomt met één van de vier richtingen, dan moet de methode een AssertionError
opwerpen met de boodschap ongeldige richting
.zeil
waaraan een string met even lengte moet doorgegeven worden. Deze string moet alternerend bestaan uit letters die een bepaalde beweging aangegeven (S
voor schuiven en K
voor kantelen) en letters die een bepaalde richting aangeven (L
voor links, R
voor rechts, V
voor voorwaarts en A
voor achterwaarts). Zo staat SA
bijvoorbeeld voor schuif naar achter, KR
voor kantel naar rechts, en SAKR
voor schuif eerst naar achter en kantel daarna naar rechts. De methode moet de omschreven bewegingen achter elkaar uitvoeren en een verwijzing teruggeven naar het Blok
-object waarop de methode wordt aangeroepen, zodat het aanroepen van methoden kan aaneengeschakeld worden. Indien de gegeven string op een even positie een karakter bevat dat niet overeenkomt met één van de hoofdletters die de bewegingen aanduiden, dan moet de methode een AssertionError
opwerpen met de boodschap ongeldige beweging
. Indien de gegeven string op een oneven positie een karakter bevat dat niet overeenkomt met één van de hoofdletters die de richtingen aanduiden, dan moet de methode een AssertionError
opwerpen met de boodschap ongeldige richting
.> const rots = new Blok(5, 2, 3);
> rots.toObject();
{ lengte: 5, hoogte: 2, breedte: 3, positie: [ 0, 0 ] }
> rots.oppervlakte();
62
> rots.volume();
30
> rots.diagonaal();
6.164414002968976
> const rots2 = rots.schuif('R');
> rots2.toObject();
{ lengte: 5, hoogte: 2, breedte: 3, positie: [ 0, 5 ] }
> rots.schuif('V').toObject();
{ lengte: 5, hoogte: 2, breedte: 3, positie: [ 3, 5 ] }
> rots.kantel('L').toObject();
{ lengte: 2, hoogte: 5, breedte: 3, positie: [ 3, 3 ] }
> rots.kantel('A').toObject();
{ lengte: 2, hoogte: 3, breedte: 5, positie: [ 0, 3 ] }
> rots.kantel('A').schuif('L').kantel('L').schuif('A').toObject();
{ lengte: 5, hoogte: 2, breedte: 3, positie: [ -8, -4 ] }
> rots.zeil('SA').toObject();
{ lengte: 5, hoogte: 2, breedte: 3, positie: [ -11, -4 ] }
> rots.zeil('KR').toObject();
{ lengte: 2, hoogte: 5, breedte: 3, positie: [ -11, 1 ] }
> rots.zeil('SVSVKLSLKAKASRSVKRKVKRKRSASV').toObject();
{ lengte: 2, hoogte: 3, breedte: 5, positie: [ -2, 6 ] }
> rots.kantel('X');
AssertionError: ongeldige richting
> rots.zeil('XY');
AssertionError: ongeldige beweging
> rots.zeil('KY');
AssertionError: ongeldige richting