Drop hier links of afbeeldingen om ze aan de editor toe te voegen.

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).

slagenspel

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).

slag

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.

Opgave

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:

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 (|):

  1. 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

  2. het aantal slagen dat de speler al gewonnen heeft in spel $$s$$, weergegeven met twee cijfers door voorloopnullen toe te voegen waar nodig

  3. 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:

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.

Voorbeeld

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|