Maak een stapel met evenveel rode als zwarte kaarten. Schud de kaarten willekeurig door elkaar. Deel de kaarten door telkens de twee bovenste kaarten van de stapel te trekken. Als de twee kaarten rood zijn dan leg je ze bovenop de rode stapel. Als de twee kaarten zwart zijn dan leg je ze bovenop de zwarte stapel. Als er één rode en één zwarte kaart is (volgorde speelt geen rol) dan gooi je ze weg.
Als je alle kaarten van de stapel gedeeld hebt dan zal je merken dat de rode stapel altijd evenveel kaarten bevat als de zwarte stapel. Kan je dit verklaren?
Een standaard kaartspel bestaat uit 52 verschillende kaarten die onderverdeeld worden in vier soorten van elk 13 kaarten: 13 klaveren (♣), 13 ruiten (♦), 13 harten (♥) en 13 schoppen (♠). Klaveren en schoppen zijn zwart, ruiten en harten zijn rood. Van elke soort zijn er telkens kaarten met een rang van 2 tot en met 10, een boer, een vrouw, een heer en een aas. Daarnaast bevat een spel soms twee of drie jokers, maar die laten we hier even buiten beschouwing.
Elke kaart van een standaard kaartspel wordt voorgesteld als een string (str) die bestaat uit de rang van de kaart, gevolgd door de soort van de kaart:
rangen: 2, 3, 4, 5, 6, 7, 8, 9, 10, J (boer), Q (vrouw), K (heer) en A (aas)
soorten: C (klaveren; ♣), D (ruiten; ♦), H (harten; ♥) en S (schoppen; ♠)
Zo stelt AS bijvoorbeeld schoppenaas voor, 10H hartentien en KC klaverenheer.
Een reeksvoorstelling van een stapel kaarten bestaat uit een lijst (list) of een tuple (tuple) met de voorstellingen van de opeenvolgende kaarten uit de stapel, waarbij de bovenste kaart van de stapel het eerste element is. Een stapel hoeft niet noodzakelijk alle 52 kaarten van een kaartspel te bevatten, maar elke kaart kan hoogstens één keer in de stapel voorkomen.
Definieer een klasse Stapel die kan gebruikt worden om stapels kaarten voor te stellen. Bij het instantiëren van objecten van de klasse Stapel moet de reeksvoorstelling van een stapel kaarten doorgegeven worden. Hierbij moet expliciet gecontroleerd worden dat de gegeven stapel voldoet aan de volgende voorwaarden:
de stapel wordt voorgesteld als een lijst (list) of een tuple (tuple)
elk element van de stapel is een geldige stringvoorstelling (str) van een kaart
elke kaart zit hoogstens één keer in de stapel
Als de gegeven stapel niet aan deze voorwaarden voldoet dan moet een AssertionError opgeworpen worden met de boodschap ongeldige stapel.
Als er een object van de klasse Stapel wordt doorgegeven aan de ingebouwde functie len dan moet het aantal kaarten in de stapel (int) teruggegeven worden. Als er een object van de klasse Stapel wordt doorgegeven aan de ingebouwde functie str dan moet een string (str) teruggegeven worden die bestaat uit de stringvoorstelling van de individuele kaarten in de stapel, opgelijst van boven naar beneden en telkens van elkaar gescheiden door een spatie. Als er een object van de klasse Stapel wordt doorgegeven aan de ingebouwde functie repr dan moet een string (str) teruggegeven worden met een Python expressie die een nieuw object van de klasse Stapel aanmaakt met dezelfde toestand als die van het gegeven object. Hierbij moet de stapel kaarten voorgesteld worden als een lijst (list). Voorts moet de klasse Stapel minstens de volgende methoden ondersteunen:
Een methode trekken waaraan een getal $$n \in \mathbb{N}$$ (int) moet doorgegeven worden. Hierbij mag $$n$$ niet groter zijn dan het aantal kaarten in de stapel. Als dat toch het geval is dan moet een AssertionError opgeworpen worden met de boodschap ongeldig aantal kaarten. Anders moet de methode de bovenste $$n$$ kaarten van de stapel verwijderen en die als een nieuwe stapel (Stapel) teruggeven. De kaarten van die nieuwe stapel moeten in dezelfde volgorde liggen als in de oorspronkelijke stapel.
Een methode delen waaraan geen argumenten moeten doorgegeven worden. Als het aantal kaarten in de stapel oneven is dan moet een AssertionError opgeworpen worden met de boodschap oneven aantal kaarten. Anders moet de methode een tuple (tuple) teruggeven met de rode stapel (Stapel) en de zwarte stapel (Stapel) die men bekomt door de oorspronkelijke stapel kaarten te delen zoals uiteengezet in de inleiding. Hierbij moeten de twee kaarten die van de oorspronkelijke stapel getrokken worden telkens in hun oorspronkelijke volgorde bovenop de rode/zwarte stapel gelegd worden.
Na het delen mogen er in de oorspronkelijke stapel geen kaarten meer liggen.
Zorg er ook voor dat de + operator kan gebruikt worden om twee stapels (Stapel) samen te voegen. Het resultaat is een nieuwe stapel (Stapel) waarbij de kaarten van de eerste stapel (het linkerlid van de + operator) bovenop de kaarten van de tweede stapel (het rechterlid van de + operator) liggen. De + operator mag de samenstelling van de oorspronkelijke stapels niet wijzigen.
>>> stapel = Stapel(('5S', 'QC', '8S', 'QD', 'JC', '10C', '4H', '4S', '2D', '7S', '3S', '3C', '4D', '7H', '3H', '5H', 'KD', '6C', '2S', '9C'))
>>> len(stapel)
20
>>> stapel.trekken(3)
Stapel(['5S', 'QC', '8S'])
>>> stapel
Stapel(['QD', 'JC', '10C', '4H', '4S', '2D', '7S', '3S', '3C', '4D', '7H', '3H', '5H', 'KD', '6C', '2S', '9C'])
>>> len(stapel)
17
>>> stapel.trekken(5)
Stapel(['QD', 'JC', '10C', '4H', '4S'])
>>> print(stapel)
2D 7S 3S 3C 4D 7H 3H 5H KD 6C 2S 9C
>>> len(stapel)
12
>>> stapel.trekken(42)
Traceback (most recent call last):
AssertionError: ongeldig aantal kaarten
>>> rode_stapel, zwarte_stapel = stapel.delen()
>>> rode_stapel
Stapel(['3H', '5H', '4D', '7H'])
>>> zwarte_stapel
Stapel(['2S', '9C', '3S', '3C'])
>>> stapel
Stapel([])
>>> len(rode_stapel) == len(zwarte_stapel)
True
>>> rode_stapel + zwarte_stapel
Stapel(['3H', '5H', '4D', '7H', '2S', '9C', '3S', '3C'])
>>> rode_stapel + rode_stapel
Traceback (most recent call last):
AssertionError: ongeldige stapel
Als je nog steeds aan het nadenken bent waarom er altijd evenveel kaarten zijn in de rode en de zwarte stapel, dan kun je het op de volgende manier bekijken. Omdat er altijd evenveel rode en zwarte kaarten opzij gelegd worden (er wordt telkens één rode en één zwarte kaart opzij gelegd), moeten de resterende kaarten ook evenredig verdeeld zijn over rood en zwart. Als alle kaarten gedeeld zijn, moeten er dus wel evenveel kaarten in de rode en de zwarte stapel liggen.
Dezelfde redenering geeft je het antwoord op het volgende alcoholprobleem. Vul een glas met wijn en een glas met water. Breng een koffielepel wijn over van het eerste naar het tweede glas. Breng daarna een koffielepel van het mengsel in het tweede glas over naar het eerste glas. Is er dan meer wijn in het water of meer water in de wijn?
De meeste mensen denken het eerste, maar in feit zijn de verhoudingen altijd hetzelfde. Zie je waarom?