Rummikub is een gezelschapsspel dat oorspronkelijk werd gespeeld met twee sets kaarten. Omdat daarvoor vrij veel ruimte op de tafel nodig was, zijn de kaarten in moderne versies van het spel vervangen door 106 kleinere stenen: twee sets van de getallen 1 tot en met 13 in de kleuren rood-geel-blauw-zwart en twee jokers ($$2 \times 13 \times 4 + 2 = 106$$).
Bij aanvang van het spel worden alle stenen op hun kop op tafel gelegd, zodat hun waarde niet zichtbaar is. Deze stenen vormen de pot. Daarna neemt iedere speler 14 stenen uit de pot, en zet ze op zijn rekje. Om te bepalen wie mag beginnen, pakt elke speler een extra steen uit de pot en legt die zichtbaar op tafel. De speler wiens steen de hoogste waarde heeft mag beginnen.
Het doel van het spel is om als eerste al je stenen op tafel te leggen door nieuwe rijtjes te vormen en open op tafel uit te leggen, of door rijtjes die open op tafel liggen aan te vullen. Hiervoor moeten de spelers tijdens het spel mogelijks bijkomende stenen uit de pot nemen en op hun rekje plaatsen.
In deze opgave stellen we een steen van het spel Rummikub voor als een string. Deze string begint met een natuurlijk getal uit het interval $$[1, 13]$$ die de waarde van de steen voorstelt, gevolgd door één enkele hoofdletter die de kleur van de steen voorstelt: R (rood), G (geel), B (blauw) of Z (zwart).
Een groep stenen omschrijft bijvoorbeeld alle stenen die een speler op zijn rekje heeft staan, of alle stenen die een speler in één beurt uitlegt vanop zijn rekje naar de tafel. We gebruiken twee manieren om een groep stenen voor te stellen: als een reeks (lijst of tuple) of als een dictionary.
De eerste manier stelt een groep stenen voor als een reeks (een lijst of een tuple) van stenen. Omdat eenzelfde steen meerdere keren in een groep kan voorkomen — we laten hierbij zelfs toe dat eenzelfde steen meer dan twee keer voorkomt — kan het dus voorkomen dat dezelfde string meerdere keren voorkomt in de reeks die de groep stenen voorstelt.
De tweede manier stelt een groep stenen voor als een dictionary die stenen afbeeldt op het aantal voorkomens van die steen in de groep. De stringvoorstelling van de stenen wordt dus gebruikt als sleutel voor de dictionary, en het aantal voorkomens als de bijhorende waarde. Hierbij geldt steeds dat het aantal voorkomens minstens 1 is. Stenen die niet voorkomen in de groep worden nooit als sleutel gebruikt in de dictionary. Gevraagd wordt:
Schrijf een functie groep waaraan een reeks (een lijst of een tuple) van strings moet doorgegeven worden die een groep stenen voorstelt. De functie moet een dictionary teruggeven die de gegeven groep stenen voorstelt.
Schrijf een functie uitleggen waaraan twee dictionaries moeten doorgegeven worden. De eerste stelt een rijtje stenen voor die een speler wil uitleggen. De tweede stelt de stenen voor die de speler op zijn rekje heeft staan. De functie moet een Booleaanse waarde teruggeven die aangeeft of de speler het gegeven rijtje stenen kan uitleggen. Dat is het geval als alle stenen van het rijtje wel degelijk op het gegeven rekje staan, rekening houdend met het aantal keer dat de stenen voorkomen in het rijtje en op het rekje. Indien de speler het gegeven rijtje kan uitleggen, dan moet de functie er ook voor zorgen dat die stenen weggehaald worden uit de dictionary die de stenen op het rekje voorstelt. Indien de speler het gegeven rijtje niet kan uitleggen, dan mag de functie de gegeven dictionary die de stenen op het rekje voorstelt niet wijzigen.
>>> groep(['1G', '7G', '8G', '12G', '12B', '13B', '13B', '13Z', '13G', '2Z', '3Z', '4Z', '11Z', '11Z', '4R', '5R'])
{'4R': 1, '8G': 1, '5R': 1, '11Z': 2, '4Z': 1, '12G': 1, '13G': 1, '13Z': 1, '1G': 1, '2Z': 1, '13B': 2, '7G': 1, '3Z': 1, '12B': 1}
>>> groep(['9G', '7R', '9G', '7R', '9G', '7R', '9G'])
{'9G': 4, '7R': 3}
>>> rijtje = groep(['13B', '13Z', '13G'])
>>> rekje = groep(['1G', '7G', '8G', '12G', '12B', '13B', '13B', '13Z', '13G', '2Z', '3Z', '4Z', '11Z', '11Z', '4R', '5R'])
>>> uitleggen(rijtje, rekje)
True
>>> rijtje
{'13B': 1, '13G': 1, '13Z': 1}
>>> rekje
{'8G': 1, '3Z': 1, '12G': 1, '7G': 1, '12B': 1, '2Z': 1, '11Z': 2, '1G': 1, '4Z': 1, '4R': 1, '5R': 1, '13B': 1}
>>> rijtje = groep(['12B', '12Z', '12G'])
>>> uitleggen(rijtje, rekje)
False
>>> rekje
{'8G': 1, '3Z': 1, '12G': 1, '7G': 1, '12B': 1, '2Z': 1, '11Z': 2, '1G': 1, '4Z': 1, '4R': 1, '5R': 1, '13B': 1}