Der Einsatz evolutionärer Computermodelle bei der Untersuchung historischer und politischer Fragestellungen |
Inhalt |
Insgesamt nahmen 12 unterschiedliche Strategien an dem hier beschriebenen Computerturnier teil. Es lohnt sich nicht, alle Strategien einzeln zu beschreiben, zumal ihre Namen meist selbsterklärend sind (Random, Tit for Tat, Always friendly). Die drei Strategien GraciousTFT, Tester und Analyst sollen jedoch mit Hilfe von Quellcodebeispielen etwas näher erläutert werden. Die Beispiele aus dem Programmcode sind in der Programmiersprache Python geschrieben, einer Interpretersprache, die sich wegen ihrer Einfachheit und der guten Lesbarkeit des Programmcodes für solche Aufgaben empfiehlt.
Die Strategie GraciousTFT ist eine Variante von Tit for Tat, die jedoch längere Folgen gegenseitiger Bestrafungen erkennt und durch ein Friedensangebot zu beendigen versucht. Damit beseitigt GraciousTFT eine Schwäche, die Tit for Tat im Zusammentreffen mit böswilligen Varianten des eigenen Typs aufweist. Im folgenden Programmausschnitt steht ein Rückgabewert von 1 für Kooperation und ein Rückgabewert von 0 für eine Defektion.
def nextMove(self, round, myMoves, opMoves): if round == 1: return 1 # start friendly elif round > 6 and ((opMoves[-5:] == [0,0,0,0,0] and \ myMoves[-5:] == [0,0,0,0,0]) or \ (opMoves[-5:] == [0,1,0,1,0] and \ myMoves[-5:] == [1,0,1,0,1])): return 1 # peace offer else: if opMoves[-1] == 1: return 1 # play tit for tat else: return 0
Die Strategie Tester ist dem Buch von Axelrod entnommen. Sie versucht zunächst durch eine mutwillige Defektion festzustellen, ob sich der Gegner ausnutzen lässt. Wenn ja, dann defektiert sie bei jedem zweiten Zug. Wenn nicht, spielt sie Tit for Tat.
def nextMove(self, round, myMoves, opMoves): if round <= 2: return 0 elif round == 3: if opMoves[-1] == 0: self.state = "TFT" else: self.state = "Deceiver" return 1 elif round == 4: return 1 else: if self.state == "TFT": if opMoves[-1] == 1: return 1 else: return 0 else: if round % 2 == 1: return 0 else: return 1
Analyst schließlich analysiert jeweils die zehn letzten Spielzüge, um festzustellen, ob die gegnerische Strategie ausnutzbar oder böswillig ist. Erweist sie sich als ausnutzbar, so defektiert Analyst. Ist der Gegner böswillig, dann wehrt sich Analyst ebenfalls durch Defektion. Wenn beides nicht eindeutig feststellbar ist, dann spielt Analyst Tit for Tat. Die ersten zehn Züge werden zufällig gewählt.
def nextMove(self, round, myMoves, opMoves): if round <= 10: return whrandom.randint(0, 1) # play random at the beginning else: # analyse ex_attempt, ex_success = 0,0 opex_opportunity, opex_attempt = 0, 0 i = -9 while i <= -1: if myMoves[i-1] == 0: ex_attempt += 1 if opMoves[i] != 0: ex_success += 1 # opponent did # not punish exploit! else: opex_opportunity += 1 if opMoves[i] == 0: opex_attempt += 1 # opponnent played # defective without # reason i += 1 # and react accordingly ret = -1 if (ex_attempt > 0): if (float(ex_success) / float(ex_attempt)) >= 0.6: return 0 # keep exploiting else: ret = 1 # try to be friendly again if opex_opportunity > 0: if (float(opex_attempt) / float(opex_opportunity)) <= 0.4: return 1 # opponent isn't really bad else: return 0 # opponent tried to deceive to often else: if ret != -1: return ret # fallback else: if opMoves[-1] == 1: return 1 # play TFT if clueless else: return 0