Een bekend speltheoretisch probleem is het “Iterated Prisoner’s Dilemma,” in het Nederlands officieel halfslachtig vertaald als het “geïtereerde dilemma van de gevangene.” In dit probleem spelen twee strategieën tegen elkaar over meerdere rondes. Iedere ronde kan iedere strategie kiezen tussen twee mogelijkheden (zonder daarbij te weten wat de andere strategie kiest): “Coöperatie” (C) of “Defectie” (D) (vrij vertaald: “samenwerken” of “tegenwerken”). Als beide strategieën C spelen, krijgen ze allebei 3 punten. Als ze beide D spelen, krijgen ze allebei 1 punt. Als één strategie C speelt en één strategie D, dan krijgt de strategie die C speelt 0 punten, en de strategie die D speelt 6 punten. Het doel van iedere strategie is zoveel mogelijk punten te verdienen over de gehele duur van het spel.

Hieronder is een eenvoudige versie van het “Iterated Prisoner’s Dilemma” gecodeerd. Een strategie om het spel te spelen is gedefinieerd door de class Strategie. Het hoofdprogramma laat twee strategieën tegen elkaar spelen over 100 rondes (het is niet moeilijk om in het hoofdprogramma meer dan twee strategieën tegen elkaar te laten spelen in paren, maar dat maakt de code een stuk langer en is niet van belang voor de opgave). De class Strategie heeft geen implementatie voor de methode keuze(). Om een strategie te creëren, leid je een nieuwe class van Strategie af, en vul je op zijn minst de keuze() methode in. Optioneel mag je ook de laatstezet() methode invullen, en de __init__() methode uitbreiden.

Implementeer de volgende strategieën:

Als je nog meer strategieën wilt implementeren, mag dat natuurlijk. Test sommige strategieën uit tegen elkaar door ze in te vullen bij de toekenningen aan strategie1 en strategie2 (vergeet niet om ze een naam te geven tussen de haakjes).

Merk op dat de manier waarop ik de score telling heb gecodeerd (met een statement als 3 if c1 == COOPERATIE else 1) een verkorte manier is om met Python een eenvoudige conditie te schrijven, die lijkt op list comprehension (zie hoofdstuk 13). Dat heb ik alleen gedaan om ruimte te besparen en leesbaarheid te verhogen; je mag dit natuurlijk ook doen met de 4 regels code die nodig zijn om dit in een if-statement te zetten.

COOPERATIE = 'C'
DEFECTIE = 'D'
RONDES = 100

class Strategie:
    def __init__( self, name="" ):
        self.name = name
        self.score = 0
    def keuze( self ):
        # Moet COOPERATIE of DEFECTIE retourneren
        return NotImplemented
    def laatstezet( self, mijnzet, opponentzet ):
        # Krijgt de laatste zet die gemaakt is, na keuze()
        pass
    def plusscore( self, n ):
        self.score += n

strategie1 = Strategie()
strategie2 = Strategie()

for i in range( RONDES ):
    c1 = strategie1.keuze()
    c2 = strategie2.keuze()
    if c1 == c2:
        strategie1.plusscore( 3 if c1 == COOPERATIE else 1 )
        strategie2.plusscore( 3 if c2 == COOPERATIE else 1 )
    else:
        strategie1.plusscore( 0 if c1 == COOPERATIE else 6 )
        strategie2.plusscore( 0 if c2 == COOPERATIE else 6 )
    strategie1.laatstezet( c1, c2 )
    strategie2.laatstezet( c2, c1 )

print( "Eind score", strategie1.name, "is", strategie1.score )
print( "Eind score", strategie2.name, "is", strategie2.score )