Een rangeerterrein is een stelplaats waar goederentreinen in delen gesplitst en opnieuw samengesteld kunnen worden. Dergelijke rangeerterreinen vind je doorgaans in de buurt van spoorwegknooppunten, industriegebieden en havens.

rangeerterrein
Rangeerterrein aan het station van Godorf (Keulen, Duitsland).

Het goederenvervoer per spoor onderging sinds de jaren zestig een schaalvergroting. Waar vroeger slechts één of enkele goederenwagons voldoende waren voor een levering, rijden bloktreinen tegenwoordig in hun geheel van herkomst naar bestemming. Daardoor is rangeren onderweg niet meer nodig. Samen met een algemene daling van goederenvervoer per spoor heeft dit wereldwijd geleid tot de sluiting van veel rangeerterreinen.

Opgave

We modelleren een rangeerterrein naar het beeld van onderstaande figuur. Aan de linkerkant van het terrein bevindt zich een rangeerzone met een maximale capaciteit van $$c$$ rijtuigen. Uiterst links op het spoor van de rangeerzone staat altijd een locomotief, waarachter tot $$c - 1$$ wagons kunnen geplaatst worden. Aan de rechterkant van het terrein bevinden er zich twee of meer standplaatsen. De sporen van die standplaatsen worden van boven naar onder genummerd vanaf nul. Het spoor van elke standplaats heeft een maximale capaciteit van $$c$$ rijtuigen. Wagons worden altijd tegen elkaar geparkeerd aan de rechterkant van een standplaats. De rangeerzone wordt met elke standplaats verbonden via een systeem van wissels, die kunnen gebruikt worden om de samenstelling van de wagons achter de locomotief te wijzigen.

rangeerterrein
Model van een rangeerterrein. Aan de linkerkant van het terrein bevindt zich een rangeerzone met een maximale capaciteit van $$c$$ rijtuigen. Uiterst links op het spoor van de rangeerzone staat altijd een locomotief, waarachter tot $$c - 1$$ wagons kunnen geplaatst worden. Aan de rechterkant van het terrein bevinden er zich twee of meer standplaatsen. De sporen van die standplaatsen worden van boven naar onder genummerd worden vanaf nul. Het spoor van elke standplaats heeft een maximale capaciteit van $$c$$ rijtuigen. Wagons worden altijd tegen elkaar geparkeerd aan de rechterkant van een standplaats. De rangeerzone wordt met elke standplaats verbonden via een systeem van wissels. Die wissels kunnen gebruikt worden om de samenstelling van de wagons achter de locomotief te wijzigen.

Via de wissels kan men $$n$$ wagons ophalen vanaf een bepaalde standplaats $$i$$. Daarbij worden de eerste $$n$$ wagons (aan de linkerkant) van de standplaats verplaatst naar de achterkant (aan de rechterkant) van rangeerzone, waarbij de volgorde van de wagons niet wijzigt. Uiteraard kan het aantal wagons dat opgehaald wordt niet groter zijn dan het aantal wagons dat op standplaats $$i$$ geparkeerd stond. Ook de maximale capaciteit $$c$$ van de rangeerzone mag niet overschreden worden, rekening houdend met het feit dat daar al een locomotief en eventueel ook wagons stonden.

Via de wissels kan men ook $$n$$ wagons wegzetten naar een bepaalde standplaats $$i$$. Daarbij worden de laatste $$n$$ wagons (aan de rechterkant) van de rangeerzone verplaatst naar de voorkant (aan de linkerkant) van standplaats $$i$$, waarbij de volgorde van de wagons niet wijzigt. Uiteraard kan het aantal wagons dat weggezet wordt niet groter zijn dan het aantal wagons dat op de rangeerzone staat. De locomotief kan niet weggezet worden. Ook de maximale capaciteit $$c$$ van standplaats $$i$$ mag niet overschreden worden, rekening houdend met het feit dat daar eventueel al wagons geparkeerd stonden.

Definieer een klasse Rangeerterrein waarmee de samenstelling van de wagons achter een locomotief kan gewijzigd worden op een rangeerterrein naar bovenstaand model. Bij het aanmaken van een nieuw rangeerterrein (Rangeerterrein) moet een lijst (list) doorgegeven worden met de wagons die op de standplaatsen van het terrein geparkeerd staan. Daarbij worden de standplaatsen van boven naar onder opgelijst, en geeft de lengte van de lijst meteen ook aan hoeveel standplaatsen er zijn. Het aantal wagons dat op een standplaats geparkeerd staat — en hun volgorde — wordt voorgesteld als een string (str) van hoofdletters. Daarbij stelt elke hoofdletter een wagon voor. Het is mogelijk dat meerdere wagons op het terrein door dezelfde hoofdletter voorgesteld worden. Er is ook een optionele parameter locomotief waaraan een string (str) kan doorgegeven worden die op dezelfde manier aangeeft hoeveel — en in welke volgorde — wagons er op de rangeerzone achter de locomotief staan. Als er niet expliciet een waarde wordt doorgegeven aan deze parameter, dan staan er geen wagons achter de locomotief. Er is ook een optionele parameter capaciteit waarmee de maximale capaciteit $$c$$ (int; standaardwaarde: 10) van de rangeerzone en van de standplaatsen kan ingesteld worden. Als het nieuw aangemaakte rangeerterrein minder dan twee standplaatsen zou hebben, of als de capaciteit van de rangeerzone of één van de standplaatsen zou overschreden worden, dan moet een AssertionError opgeworpen worden met de boodschap ongeldige configuratie.

Als er een rangeerterrein $$r$$ (Rangeerterrein) wordt doorgegeven aan de ingebouwde functie repr, dan moet die een string (str) teruggeven die leest als een expressie waarmee een nieuw rangeerterrein (Rangeerterrein) aangemaakt wordt met dezelfde configuratie als de huidige configuratie van rangeerterrein $$r$$. Daarbij worden expliciet waarden doorgegeven aan de benoemde parameters locomotief en capaciteit.

Als er een rangeerterrein $$r$$ (Rangeerterrein) wordt doorgegeven aan de ingebouwde functie str, dan moet die een stringvoorstelling (str) teruggeven van rangeerterrein $$r$$. Het spoorsegment waarop de locomotief staat wordt aangeduid met een zwart vierkantje (■), een spoorsegment waarop een wagon staat door de hoofdletter die de wagon voorstelt, en een leeg spoorsegment (met de lengte van een rijtuig) van de rangeerzone of een standplaats door een horizontale streep (━). Er worden specifieke voorstellingen gebruikt voor de wissel ter hoogte van de bovenste standplaats (┳), de wissel ter hoogte van de onderste standplaats (┗) en de wissels ter hoogte van de tussenliggende standplaatsen (┣). De lege zone links van de standplaatsen 1, 2, … wordt ingevuld met spaties.

Als er een rangeerterrein $$r$$ (Rangeerterrein) wordt doorgegeven aan de ingebouwde functie len, dan moet die het aantal wagons (int) teruggeven die op de standplaatsen van rangeerterrein $$r$$ geparkeerd staan. De wagons die op de rangeerzone achter de locomotief staan, moeten daarbij dus niet meegeteld worden.

Voorts moet je op een rangeerterrein $$r$$ (Rangeerterrein) minstens de volgende methoden kunnen aanroepen:

Voorbeeld

>>> terrein = Rangeerterrein(['OACHF', 'HJN', 'XGWCU', 'DF'], 'CMP')
>>> terrein
Rangeerterrein(['OACHF', 'HJN', 'XGWCU', 'DF'], locomotief='CMP', capaciteit=10)
>>> print(terrein)
■CMP━━━━━━┳━━━━━OACHF
          ┣━━━━━━━HJN
          ┣━━━━━XGWCU
          ┗━━━━━━━━DF
>>> len(terrein)
15
>>> terrein.ophalen(3, 6)
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> terrein.ophalen(3, 2)
Rangeerterrein(['OACHF', 'HJN', 'CU', 'DF'], locomotief='CMPXGW', capaciteit=10)
>>> print(terrein)
■CMPXGW━━━┳━━━━━OACHF
          ┣━━━━━━━HJN
          ┣━━━━━━━━CU
          ┗━━━━━━━━DF
>>> len(terrein)
12
>>> terrein.ophalen(4, 0)
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> terrein.ophalen(3, 0)
Rangeerterrein(['HF', 'HJN', 'CU', 'DF'], locomotief='CMPXGWOAC', capaciteit=10)
>>> print(terrein)
■CMPXGWOAC┳━━━━━━━━HF
          ┣━━━━━━━HJN
          ┣━━━━━━━━CU
          ┗━━━━━━━━DF
>>> len(terrein)
9
>>> terrein.wegzetten(8, 1)
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> terrein.wegzetten(7, 1)
Rangeerterrein(['HF', 'PXGWOACHJN', 'CU', 'DF'], locomotief='CM', capaciteit=10)
>>> print(terrein)
■CM━━━━━━━┳━━━━━━━━HF
          ┣PXGWOACHJN
          ┣━━━━━━━━CU
          ┗━━━━━━━━DF
>>> len(terrein)
16
>>> terrein.wegzetten(3, 3)
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> terrein.ophalen(4, 1).wegzetten(2, 3).wegzetten(3, 2).ophalen(4, 1)
Rangeerterrein(['HF', 'JN', 'MPXCU', 'GWDF'], locomotief='COACH', capaciteit=10)
>>> print(terrein)
■COACH━━━━┳━━━━━━━━HF
          ┣━━━━━━━━JN
          ┣━━━━━MPXCU
          ┗━━━━━━GWDF
>>> len(terrein)
13

>>> Rangeerterrein(['ABC', 'DEF'])
Rangeerterrein(['ABC', 'DEF'], locomotief='', capaciteit=10)
>>> Rangeerterrein(['ABC'])
Traceback (most recent call last):
AssertionError: ongeldige configuratie
>>> Rangeerterrein(['ABC', 'DEFGHI'], capaciteit=4)
Traceback (most recent call last):
AssertionError: ongeldige configuratie
>>> Rangeerterrein(['ABC', 'DEF'], locomotief='GHIJ', capaciteit=4)
Traceback (most recent call last):
AssertionError: ongeldige configuratie