Een slagenspel is een kaartspel dat gespeeld wordt met vier spelers die rond een tafel zitten. Ze worden in wijzerzin aangeduid met de letters N (north, noord), E (east, oost), S (south, zuid) en W (west).

Het aantal kaarten waarmee gespeeld wordt is een veelvoud van vier. Eén van de spelers is de deler. Bij aanvang van het spel verdeelt hij de kaarten één voor één in wijzerzin over de spelers, te beginnen bij zichzelf. Daarna kiest hij één van de vier kaartkleuren als troef, of kiest hij ervoor om zonder troef te spelen.
De kaarten die een speler op een bepaald moment vasthoudt, worden de kaarten op de hand van de speler genoemd. Het spel verloopt in rondes die slagen genoemd worden. Per slag spelen de spelers in wijzerzin elk één kaart op hun hand weg op tafel: bij de eerste slag speelt de deler als eerste een kaart weg, en bij elke volgende slag speelt de winnaar van de vorige slag als eerste een kaart weg.
Om de winnende kaart van een slag te bepalen, moet je weten dat een standaard kaartspel uit 52 verschillende kaarten bestaat. Ze worden onderverdeeld in vier kleuren van elk 13 kaarten: 13 schoppen (♠), 13 harten (♥), 13 ruiten (♦) en 13 klaveren (♣). Klaveren en schoppen zijn zwart, ruiten en harten zijn rood, maar het zijn niet deze fysieke kleuren, maar de soorten die met de term kleur aangeduid worden. Van elke kleur zijn er telkens kaarten met een rang van 2 tot en met 10, een boer, een vrouw, een heer en een aas. Dit is meteen ook de volgorde van de kaarten binnen elke kleur: een 2 is de laagste kaart en een aas is de hoogste kaart.
Als er in een slag troefkaarten gespeeld werden, dan wint de hoogste troefkaart. Als er zonder troef gespeeld wordt, of als er geen troefkaarten gespeeld werden, dan wint de hoogste kaart in de kleur van de eerst gespeelde kaart. Stel bijvoorbeeld dat in een slag achtereenvolgens speler N schoppentien (♠10) speelt, speler E schoppenheer (♠K), speler S ruitenboer (♦J) en speler W hartenzeven (♥7). Als er zonder troef gespeeld wordt of als schoppen of klaveren troef is, wint speler E met schoppenheer (♠K). Als ruiten troef is, wint speler S met ruitenboer (♦J). Als harten troef is, wint speler W met hartenzeven (♥7).

Kaarten die weggespeeld worden doen niet meer mee: de speler die een slag gewonnen heeft neemt de weggespeelde kaarten van tafel, legt ze gedekt voor zich neer, en speelt in de volgende slag als eerste een kaart op zijn hand weg. Het spel eindigt als alle kaarten weggespeeld zijn.
We stellen elk van de 52 kaarten van een standaard kaartspel voor als een string (str) die bestaat uit de kleur van de kaart
| naam | schoppen | harten | ruiten | klaveren |
|---|---|---|---|---|
| kleur | ♠ | ♥ | ♦ | ♣ |
gevolgd door de rang van de kaart
| naam | twee | drie | vier | vijf | zes | zeven | acht | negen | tien | boer | dame | heer | aas |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| rang | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | J | Q | K | A |
Merk op dat de kleur van een kaart altijd voorgesteld wordt door één karakter. Zo stelt ♠A bijvoorbeeld schoppenaas voor, ♥10 hartentien en ♣K klaverenheer. Een kaartkleur wordt voorgesteld met zijn corresponderende karakter (str; ♠, ♥, ♦ of ♣). Een speler wordt voorgesteld met zijn corresponderende letter (str; N, S, E of W).
De volgorde waarin we hierboven de kleuren en de rangen opgelijst hebben, bepaalt ook de canonieke volgorde waarin de kaarten op de hand van een speler opgelijst worden. Eerst worden de schoppen opgelijst, gevolgd door de harten, de ruiten en de klaveren. Kaarten met dezelfde kleur worden volgens dalende rang opgelijst: eerst de aas, gevolgd door heer, dame, boer, 10, 9, …, 2.
Definieer een klasse Slagenspel waarmee het verloop van een slagenspel kan gesimuleerd worden. Bij het aanmaken van een nieuw spel (Slagenspel) wordt de deler vastgelegd, worden de kaarten onder de spelers verdeeld, wordt de troef vastgelegd en begint elke speler met nul slagen. Aan de eerste parameter moet de locatie (str) doorgegeven worden van een tekstbestand met de volgorde waarin de kaarten gedeeld worden, één kaart per regel. Aan de tweede parameter deler moet de deler (str) doorgegeven worden. Er is ook nog een optionele derde parameter troef waaraan de troef (str) kan doorgegeven worden. Als er niet expliciet een troef wordt doorgegeven, dan wordt er zonder troef gespeeld.
Op een spel $$s$$ (Slagenspel) moet je deze methoden kunnen aanroepen:
Een methode eerste_speler waaraan geen argumenten moeten doorgegeven worden. De methode moet de speler (str) teruggeven die als eerste een kaart moet wegspelen bij de volgende slag van spel $$s$$.
Een methode volgorde_spelers waaraan geen argumenten moeten doorgegeven worden. De methode moet een string (str) met vier letters teruggeven, die aangeven in welke volgorde de spelers een kaart moeten wegspelen bij de volgende slag van spel $$s$$.
Een methode hand waaraan een speler (str) moet doorgegeven worden. De methode moet een lijst (list) teruggeven met de kaarten (str) die de speler momenteel op zijn hand heeft in spel $$s$$, opgelijst in hun canonieke volgorde.
Een methode slagen waaraan een speler (str) moet doorgegeven worden. De methode moet teruggeven hoeveel slagen (int) de speler al gewonnen heeft in spel $$s$$.
Gebruik bovenstaande methoden om te zorgen dat de ingebouwde functie str een stringvoorstelling (str) teruggeeft die de toestand van spel $$s$$ (Slagenspel) beschrijft als spel $$s$$ er wordt aan doorgegeven. Die voorstelling heeft voor elke speler (vaste volgorde N, E, S, W) een regel met drie informatievelden die van elkaar gescheiden worden door een verticale streep (|):
de letter waarmee de speler aangeduid wordt, gevolgd door een sterretje (*) bij de speler die bij de volgende slag als eerste een kaart moet wegspelen in spel $$s$$ of een spatie bij de andere spelers
het aantal slagen dat de speler al gewonnen heeft in spel $$s$$, weergegeven met twee cijfers door voorloopnullen toe te voegen waar nodig
de kaarten op de hand van de speler in spel $$s$$, opgelijst in hun canonieke volgorde en gescheiden door komma's
Om het uitvoeren van een slag te simuleren, moet je op een spel $$s$$ (Slagenspel) ook nog deze methoden kunnen aanroepen:
Een methode heeft_kaart waaraan twee argumenten moeten doorgegeven worden: i) een speler (str) en ii) een kaart (str). De methode moet een Booleaanse waarde (bool) teruggeven, die aangeeft of de speler momenteel de kaart op zijn hand heeft in spel $$s$$.
Een methode hoogste_kaart waaraan twee argumenten moeten doorgegeven worden: i) een kaartkleur (str) en ii) een collectie (list, tuple of set) met kaarten (str). Als de collectie geen kaarten met de gegeven kleur bevat, dan moet de waarde None teruggegeven worden. Anders moet de hoogste kaart (str) met de gegeven kleur uit de collectie teruggegeven worden.
Een methode winnende_kaart waaraan een reeks (list of tuple) moet doorgegeven worden met de vier kaarten (str) die bij een volgende slag zouden kunnen weggespeeld worden in spel $$s$$ (in de volgorde waarin ze weggespeeld worden). De methode moet de winnende kaart (str) van die slag teruggeven (zonder evenwel de slag zelf te spelen).
Een methode winnende_speler waaraan een reeks (list of tuple) moet doorgegeven worden met de vier kaarten (str) die bij een volgende slag zouden kunnen weggespeeld worden in spel $$s$$ (in de volgorde waarin ze weggespeeld worden). De methode moet de winnende speler (str) van die slag teruggeven (zonder evenwel de slag zelf te spelen).
Een methode slag waaraan een reeks (list of tuple) moet doorgegeven worden met de vier kaarten (str) die bij de volgende slag weggespeeld worden in spel $$s$$ (in de volgorde waarin ze weggespeeld worden). De methode moet de slag spelen in spel $$s$$: de spelers spelen de kaarten uit hun hand weg, de winnende speler haalt de slag binnen en komt als eerste aan de beurt bij de volgende slag. De methode moet een verwijzing naar spel $$s$$ teruggeven.
Als er bij de methoden winnende_kaart, winnende_speler of slag vier kaarten doorgegeven worden die bij een volgende slag niet in die volgorde kunnen weggespeeld worden in spel $$s$$ — omdat de speler die een kaart moet wegspelen de kaart niet op zijn hand heeft — dan moet er een AssertionError opgeworpen worden met de boodschap ongeldige slag. In dat geval mag de methode slag de toestand van spel $$s$$ ook niet wijzigen.
In deze interactieve sessie gaan we ervan uit dat de huidige directory het tekstbestand kaarten.txt bevat.
>>> spel = Slagenspel('kaarten.txt', deler='W', troef='♠')
>>> spel.eerste_speler()
'W'
>>> spel.volgorde_spelers()
'WNES'
>>> spel.hand('N')
['♠K', '♠9', '♠3', '♥6', '♥2', '♦K', '♦J', '♦9', '♦8', '♦6', '♦3', '♣9', '♣5']
>>> spel.hand('E')
['♠10', '♠8', '♠6', '♥A', '♥K', '♥Q', '♥9', '♥7', '♥5', '♦A', '♣A', '♣K', '♣4']
>>> spel.hand('S')
['♠A', '♠Q', '♠J', '♠7', '♠4', '♥10', '♦Q', '♦7', '♦2', '♣J', '♣8', '♣3', '♣2']
>>> spel.hand('W')
['♠5', '♠2', '♥J', '♥8', '♥4', '♥3', '♦10', '♦5', '♦4', '♣Q', '♣10', '♣7', '♣6']
>>> spel.slagen('N')
0
>>> spel.slagen('E')
0
>>> spel.slagen('S')
0
>>> spel.slagen('W')
0
>>> print(spel)
N |00|♠K,♠9,♠3,♥6,♥2,♦K,♦J,♦9,♦8,♦6,♦3,♣9,♣5
E |00|♠10,♠8,♠6,♥A,♥K,♥Q,♥9,♥7,♥5,♦A,♣A,♣K,♣4
S |00|♠A,♠Q,♠J,♠7,♠4,♥10,♦Q,♦7,♦2,♣J,♣8,♣3,♣2
W*|00|♠5,♠2,♥J,♥8,♥4,♥3,♦10,♦5,♦4,♣Q,♣10,♣7,♣6
>>> spel.heeft_kaart('W', '♥4')
True
>>> spel.heeft_kaart('N', '♥2')
True
>>> spel.heeft_kaart('E', '♥Q')
True
>>> spel.heeft_kaart('S', '♥10')
True
>>> spel.hoogste_kaart('♥', {'♠6', '♣6', '♦7', '♦9', '♣7', '♣3', '♣K', '♥9', '♥6', '♣9', '♠Q', '♦Q', '♥A'})
'♥A'
>>> spel.hoogste_kaart('♦', {'♠6', '♣6', '♦7', '♦9', '♣7', '♣3', '♣K', '♥9', '♥6', '♣9', '♠Q', '♦Q', '♥A'})
'♦Q'
>>> spel.winnende_kaart(['♥4', '♥2', '♥Q', '♥10'])
'♥Q'
>>> spel.winnende_speler(['♥4', '♥2', '♥Q', '♥10'])
'E'
>>> print(spel.slag(['♥4', '♥2', '♥Q', '♥10']))
N |00|♠K,♠9,♠3,♥6,♦K,♦J,♦9,♦8,♦6,♦3,♣9,♣5
E*|01|♠10,♠8,♠6,♥A,♥K,♥9,♥7,♥5,♦A,♣A,♣K,♣4
S |00|♠A,♠Q,♠J,♠7,♠4,♦Q,♦7,♦2,♣J,♣8,♣3,♣2
W |00|♠5,♠2,♥J,♥8,♥3,♦10,♦5,♦4,♣Q,♣10,♣7,♣6
>>> spel.volgorde_spelers()
'ESWN'
>>> spel.heeft_kaart('W', '♥4')
False
>>> spel.heeft_kaart('N', '♥2')
False
>>> spel.heeft_kaart('E', '♥Q')
False
>>> spel.heeft_kaart('S', '♥10')
False
>>> spel.hand('N')
['♠K', '♠9', '♠3', '♥6', '♦K', '♦J', '♦9', '♦8', '♦6', '♦3', '♣9', '♣5']
>>> spel.hand('E')
['♠10', '♠8', '♠6', '♥A', '♥K', '♥9', '♥7', '♥5', '♦A', '♣A', '♣K', '♣4']
>>> spel.hand('S')
['♠A', '♠Q', '♠J', '♠7', '♠4', '♦Q', '♦7', '♦2', '♣J', '♣8', '♣3', '♣2']
>>> spel.hand('W')
['♠5', '♠2', '♥J', '♥8', '♥3', '♦10', '♦5', '♦4', '♣Q', '♣10', '♣7', '♣6']
>>> spel.slagen('N')
0
>>> spel.slagen('E')
1
>>> spel.slagen('S')
0
>>> spel.slagen('W')
0
>>> spel.slag(['♥4', '♥2', '♥Q', '♥10'])
Traceback (most recent call last):
AssertionError: ongeldige slag
>>> print(spel.slag(['♣A', '♣2', '♣7', '♣5']))
N |00|♠K,♠9,♠3,♥6,♦K,♦J,♦9,♦8,♦6,♦3,♣9
E*|02|♠10,♠8,♠6,♥A,♥K,♥9,♥7,♥5,♦A,♣K,♣4
S |00|♠A,♠Q,♠J,♠7,♠4,♦Q,♦7,♦2,♣J,♣8,♣3
W |00|♠5,♠2,♥J,♥8,♥3,♦10,♦5,♦4,♣Q,♣10,♣6
>>> print(spel.slag(['♦A', '♦2', '♦4', '♦3']))
N |00|♠K,♠9,♠3,♥6,♦K,♦J,♦9,♦8,♦6,♣9
E*|03|♠10,♠8,♠6,♥A,♥K,♥9,♥7,♥5,♣K,♣4
S |00|♠A,♠Q,♠J,♠7,♠4,♦Q,♦7,♣J,♣8,♣3
W |00|♠5,♠2,♥J,♥8,♥3,♦10,♦5,♣Q,♣10,♣6
>>> print(spel.slag(['♣K', '♣3', '♣6', '♣9']))
N |00|♠K,♠9,♠3,♥6,♦K,♦J,♦9,♦8,♦6
E*|04|♠10,♠8,♠6,♥A,♥K,♥9,♥7,♥5,♣4
S |00|♠A,♠Q,♠J,♠7,♠4,♦Q,♦7,♣J,♣8
W |00|♠5,♠2,♥J,♥8,♥3,♦10,♦5,♣Q,♣10
>>> print(spel.slag(['♥A', '♠4', '♥3', '♥6']))
N |00|♠K,♠9,♠3,♦K,♦J,♦9,♦8,♦6
E |04|♠10,♠8,♠6,♥K,♥9,♥7,♥5,♣4
S*|01|♠A,♠Q,♠J,♠7,♦Q,♦7,♣J,♣8
W |00|♠5,♠2,♥J,♥8,♦10,♦5,♣Q,♣10
>>> print(spel.slag(['♠7', '♠5', '♠K', '♠6']))
N*|01|♠9,♠3,♦K,♦J,♦9,♦8,♦6
E |04|♠10,♠8,♥K,♥9,♥7,♥5,♣4
S |01|♠A,♠Q,♠J,♦Q,♦7,♣J,♣8
W |00|♠2,♥J,♥8,♦10,♦5,♣Q,♣10
>>> print(spel.slag(['♠3', '♠8', '♠A', '♠2']))
N |01|♠9,♦K,♦J,♦9,♦8,♦6
E |04|♠10,♥K,♥9,♥7,♥5,♣4
S*|02|♠Q,♠J,♦Q,♦7,♣J,♣8
W |00|♥J,♥8,♦10,♦5,♣Q,♣10
>>> print(spel.slag(['♠Q', '♥8', '♠9', '♠10']))
N |01|♦K,♦J,♦9,♦8,♦6
E |04|♥K,♥9,♥7,♥5,♣4
S*|03|♠J,♦Q,♦7,♣J,♣8
W |00|♥J,♦10,♦5,♣Q,♣10
>>> print(spel.slag(['♦Q', '♦5', '♦6', '♥5']))
N |01|♦K,♦J,♦9,♦8
E |04|♥K,♥9,♥7,♣4
S*|04|♠J,♦7,♣J,♣8
W |00|♥J,♦10,♣Q,♣10
>>> print(spel.slag(['♦7', '♦10', '♦J', '♥7']))
N*|02|♦K,♦9,♦8
E |04|♥K,♥9,♣4
S |04|♠J,♣J,♣8
W |00|♥J,♣Q,♣10
>>> print(spel.slag(['♦K', '♥9', '♣8', '♣10']))
N*|03|♦9,♦8
E |04|♥K,♣4
S |04|♠J,♣J
W |00|♥J,♣Q
>>> print(spel.slag(['♦9', '♣4', '♣J', '♣Q']))
N*|04|♦8
E |04|♥K
S |04|♠J
W |00|♥J
>>> print(spel.slag(['♦8', '♥K', '♠J', '♥J']))
N |04|
E |04|
S*|05|
W |00|