def ai_vs_ai(decorator1, decorator2, nr_of_games=100, karteninfos=karteninfoliste, shuffle=True): """function for simulating, evaluating and logging AI Battles based one determinized card lists :param decorator1: the decorator function of the first AI :param decorator2: the decorator function of the first AI :param nr_of_games: the number of games that will be played, should be an even number, since after half the games have been played, the beginning player is changed :param karteninfos: list of card_informations for the game, the cardlist will be created from that list which has the following form: ['WWSWK', 'WWSS', 'OOSSOOT', ...] :param shuffle: boolean which ensures that the cardlist is beeing shuffled if True :return: None """ player1 = Player(1) player2 = Player(2) # dictionaries, um die Hyperparameter in die log-Dateien schreiben zu koennen dic1 = {} dic2 = {} func1 = decorator1(select_to_decorator[decorator1.__name__], dic1) func2 = decorator2(select_to_decorator[decorator2.__name__], dic2) next_player_to_player = {player1: player2, player2: player1} decorator_to_player = {player1: decorator1, player2: decorator2} function_to_player = {player1: func1, player2: func2} # allg_log_werte: first_half_1 = 0 first_half_2 = 0 second_half_1 = 0 second_half_2 = 0 first_half_draws = 0 second_half_draws = 0 p1_ort_meeples = 0 p1_strasse_meeples = 0 p1_wiese_meeple = 0 p1_kloster_meeples = 0 p2_ort_meeples = 0 p2_strasse_meeples = 0 p2_wiese_meeple = 0 p2_kloster_meeples = 0 allg_p1_orts_points = 0 allg_p1_strassen_points = 0 allg_p1_wiesen_points = 0 allg_p1_kloester_points = 0 allg_p2_orts_points = 0 allg_p2_strassen_points = 0 allg_p2_wiesen_points = 0 allg_p2_kloester_points = 0 p1_meeples_list_kloester = [] p1_meeples_list_orte = [] p1_meeples_list_strassen = [] p1_meeples_list_wiesen = [] p1_punkte_list_kloester = [] p1_punkte_list_orte = [] p1_punkte_list_strassen = [] p1_punkte_list_wiesen = [] p2_meeples_list_kloester = [] p2_meeples_list_orte = [] p2_meeples_list_strassen = [] p2_meeples_list_wiesen = [] p2_punkte_list_kloester = [] p2_punkte_list_orte = [] p2_punkte_list_strassen = [] p2_punkte_list_wiesen = [] p1_punkte = [] p2_punkte = [] allg_log = open('../simulations/auswertung', 'w+') allg_log.write( 'Player1 spielt nach der {}-Taktik mit den Hyperparametern {} und Player2 nach der {}-Taktik mit den Hyperparametern {}.\n\n' .format(name_to_method[decorator1.__name__], dic1, name_to_method[decorator2.__name__], dic2)) i = 0 while i < nr_of_games: game_log = open('../simulations/game{}'.format(i), 'w+') # reset for new game player1.meeples = 7 player2.meeples = 7 player1.punkte = 0 player2.punkte = 0 player1.meeples_per_kloster = 0 player1.meeples_per_wiese = 0 player1.meeples_per_strasse = 0 player1.meeples_per_ort = 0 player2.meeples_per_kloster = 0 player2.meeples_per_wiese = 0 player2.meeples_per_strasse = 0 player2.meeples_per_ort = 0 player1.kloster_points = 0 player1.wiesen_points = 0 player1.strassen_points = 0 player1.ort_points = 0 player2.kloster_points = 0 player2.wiesen_points = 0 player2.strassen_points = 0 player2.ort_points = 0 # erstellt gemischte Kartenliste cardlist = create_kartenliste(karteninfos, shuffle) l = [c.info for c in cardlist] print(l) #cardlist = create_kartenliste(mcts_list, False) spiel = Spiel(cardlist, player1, player2) # starting player turn = player1 if i < int(nr_of_games / 2) else player2 # root-nodes # falls beide Spieler UCT-Spieler sind, benoetigen beide eine root-node root_nodes = {} if decorator1.__name__ == 'uct_decorator': root_nodes.update({player1: Node(True, None, turn.nummer)}) if decorator2.__name__ == 'uct_decorator': root_nodes.update({player2: Node(True, None, turn.nummer)}) # falls kein Spieler ein UCT-Spieler ist, wird keine root-Node benoetigt, falls einer ein UCT-Spieler ist, wird # dessen root-Node als allgemeine root-node festgelegt if len(root_nodes) == 0: root_node = None elif len(root_nodes) == 1: root_node = list(root_nodes.values())[0] game_log.write( 'Player1 spielt nach der {}-Taktik mit den Hyperparametern {} und Player2 nach der {}-Taktik mit den Hyperparametern {}.\n\n' .format(name_to_method[decorator1.__name__], dic1, name_to_method[decorator2.__name__], dic2)) game_log.write('Player{} beginnt das Spiel.\n\n'.format(turn.nummer)) while len(spiel.cards_left) > 0: next_card = spiel.cards_left.pop(0) game_log.write('Neuer Zug:\n\n') game_log.write( 'Aktuell hat Player1 {} Punkte und Player2 {} Punkte.\n\n'. format(player1.punkte, player2.punkte)) game_log.write( 'Player{0} zieht die Karte [{1}, {2}, {3}, {4}, {5}, {6}]'. format(turn.nummer, next_card.info[0], next_card.info[1], next_card.info[2], next_card.info[3], next_card.mitte, next_card.schild)) game_log.write( '\nSie enthaelt folgende moegliche Meeplepositionen:') game_log.write('\nOrte: ') for o in next_card.orte: game_log.write("{}: {} ".format(o.name, o.kanten)) game_log.write('\nStrassen: ') for s in next_card.strassen: game_log.write("{}: {} ".format(s.name, s.kanten)) game_log.write('\nWiesen: ') for w in next_card.wiesen: game_log.write("{}: {} ".format(w.name, w.ecken)) pos = spiel.calculate_possible_actions(next_card, turn) if pos: # calculate next move according to the selection function (random/MC/MCTS) if len(root_nodes) < 2: action, root_node = function_to_player[turn]( spiel, next_card, turn, pos, next_player_to_player, root_node) else: action, root_nodes[turn] = function_to_player[turn]( spiel, next_card, turn, pos, next_player_to_player, root_nodes[turn]) # root_node updaten # falls ueberhaupt ein mcts-spieler mitspielt if len(root_nodes) > 0: # falls der turn-spieler kein mcts spieler ist if decorator_to_player[turn].__name__ != 'uct_decorator': # waehle die entprechend naechste Node als neue root_node if root_node.children: for child in root_node.children: # wenn die action von der child-node der gespielten entspricht if action[3] == None: if child.action == (action[0], action[1], action[2], None, None): ### root_node = child root_node.parent = None break elif action[3] == 'k': if child.action == (action[0], action[1], action[2], 'k', 1): ### root_node = child root_node.parent = None break else: if child.action == (action[0], action[1], action[2], action[3].id, action[3].name): ### root_node = child root_node.parent = None break # another player made the first move of the game, or the node has no visits yet else: p_num = 1 if turn.nummer == 2 else 2 if action[3] == None: mcts_action = (action[0], action[1], action[2], None, None) elif action[3] == 'k': mcts_action = (action[0], action[1], action[2], 'k', 1) else: mcts_action = (action[0], action[1], action[2], action[3].id, action[3].name) root_node = Node(True, mcts_action, p_num, None) else: # falls es genau zwei uct-Spieler gibt, muss der Gegner updaten. Gibt es nur einen UCT-Spieler, # ansonsten hat der UCT-Spieler die root-Node bereits upgedatet if len(root_nodes) == 2: # der Gegner muss seine Node um die Aktion updaten, die der turn-Spieler gerade gespielt hat if root_nodes[ next_player_to_player[turn]].children: for child in root_nodes[ next_player_to_player[turn]].children: # wenn die action von der child-node der gespielten entspricht if action[3] == None: mcts_action = (action[0], action[1], action[2], None, None) elif action[3] == 'k': mcts_action = (action[0], action[1], action[2], 'k', 1) else: mcts_action = (action[0], action[1], action[2], action[3].id, action[3].name) if child.action == mcts_action: ### root_nodes[next_player_to_player[ turn]] = child break # another player made the first move of the game, or the node has no visits yet else: p_num = 1 if turn.nummer == 2 else 2 if action[3] == None: mcts_action = (action[0], action[1], action[2], None, None) elif action[3] == 'k': mcts_action = (action[0], action[1], action[2], 'k', 1) else: mcts_action = (action[0], action[1], action[2], action[3].id, action[3].name) root_nodes[next_player_to_player[turn]] = Node( True, mcts_action, p_num, None) spiel.make_action(turn, next_card, action[0], action[1], action[2], action[3]) if action[3] is not None and action[3] != 'k': # action_ausgabe = 'k' if mcts.root.action[2] == 'k' else mcts.root.action[2] game_log.write( "\n\nPlayer{} setzt einen Meeple auf {}{}.".format( turn.nummer, action[3].id, action[3].name)) elif action[3] == 'k': game_log.write( "\nPlayer{} setzt einem Meeple auf das Kloster.". format(turn.nummer)) else: game_log.write("\nPlayer{} setzt keinen Meeple.".format( turn.nummer)) game_log.write( "\nPlayer{} setzt die Karte an ({}, {}) und rotiert sie {} mal\n\n" .format(turn.nummer, action[0], action[1], action[2])) turn = next_player_to_player[turn] else: game_log.write( '\nEs gibt fuer diese Kerte keine Anlegestellt.\n\n') print(i, 'Es gibt in diesem Spiel mal keine Anlegemoeglichkeit') continue spiel.final_evaluate() p1_punkte.append(player1.punkte) p2_punkte.append(player2.punkte) game_log.write( 'Das Spiel ist vorbei. Player1 hat {} und Player2 {} Punkte.'. format(player1.punkte, player2.punkte)) game_log.write( '\n\nDie Punkte von Player1 verteilen sich dabei wie folgt:\n\n{} Kloester:\t{}\n\n{} Orte:\t\t{}\n\n{} Strassen:\t{}\n\n{} Wiesen:\t{}' .format(player1.meeples_per_kloster, player1.kloster_points, player1.meeples_per_ort, player1.ort_points, player1.meeples_per_strasse, player1.strassen_points, player1.meeples_per_wiese, player1.wiesen_points)) game_log.write( '\n\nDie Punkte von Player2 verteilen sich dabei wie folgt:\n\n{} Kloester:\t{}\n\n{} Orte:\t\t{}\n\n{} Strassen:\t{}\n\n{} Wiesen:\t{}' .format(player2.meeples_per_kloster, player2.kloster_points, player2.meeples_per_ort, player2.ort_points, player2.meeples_per_strasse, player2.strassen_points, player2.meeples_per_wiese, player2.wiesen_points)) game_log.close() # allg log: allg_log.write( f'\n\nSpiel {i}: Spieler1 hat {player1.punkte} und Spieler2 hat {player2.punkte} Punkte.' ) allg_log.write( '\n\nDie Punkte von Player1 verteilen sich dabei wie folgt:\n\n{} Kloester:\t{}\n\n{} Orte:\t\t{}\n\n{} Strassen:\t{}\n\n{} Wiesen:\t{}' .format(player1.meeples_per_kloster, player1.kloster_points, player1.meeples_per_ort, player1.ort_points, player1.meeples_per_strasse, player1.strassen_points, player1.meeples_per_wiese, player1.wiesen_points)) allg_log.write( '\n\nDie Punkte von Player2 verteilen sich dabei wie folgt:\n\n{} Kloester:\t{}\n\n{} Orte:\t\t{}\n\n{} Strassen:\t{}\n\n{} Wiesen:\t{}' .format(player2.meeples_per_kloster, player2.kloster_points, player2.meeples_per_ort, player2.ort_points, player2.meeples_per_strasse, player2.strassen_points, player2.meeples_per_wiese, player2.wiesen_points)) allg_log_werte = 0 if i < int(nr_of_games / 2): if player1.punkte > player2.punkte: first_half_1 += 1 elif player2.punkte > player1.punkte: first_half_2 += 1 else: first_half_draws += 1 else: if player1.punkte > player2.punkte: second_half_1 += 1 elif player2.punkte > player1.punkte: second_half_2 += 1 else: second_half_draws += 1 # allg daten #meeples #player1 p1_ort_meeples += player1.meeples_per_ort p1_meeples_list_orte.append(player1.meeples_per_ort) p1_strasse_meeples += player1.meeples_per_strasse p1_meeples_list_strassen.append(player1.meeples_per_strasse) p1_wiese_meeple += player1.meeples_per_wiese p1_meeples_list_wiesen.append(player1.meeples_per_wiese) p1_kloster_meeples += player1.meeples_per_kloster p1_meeples_list_kloester.append(player1.meeples_per_kloster) #player2 p2_ort_meeples += player2.meeples_per_ort p2_meeples_list_orte.append(player2.meeples_per_ort) p2_strasse_meeples += player2.meeples_per_strasse p2_meeples_list_strassen.append(player2.meeples_per_strasse) p2_wiese_meeple += player2.meeples_per_wiese p2_meeples_list_wiesen.append(player2.meeples_per_wiese) p2_kloster_meeples += player2.meeples_per_kloster p2_meeples_list_kloester.append(player2.meeples_per_kloster) #punkte #player1 allg_p1_orts_points += player1.ort_points p1_punkte_list_orte.append(player1.ort_points) allg_p1_strassen_points += player1.strassen_points p1_punkte_list_strassen.append(player1.strassen_points) allg_p1_wiesen_points += player1.wiesen_points p1_punkte_list_wiesen.append(player1.wiesen_points) allg_p1_kloester_points += player1.kloster_points p1_punkte_list_kloester.append(player1.kloster_points) #player2 allg_p2_orts_points += player2.ort_points p2_punkte_list_orte.append(player2.ort_points) allg_p2_strassen_points += player2.strassen_points p2_punkte_list_strassen.append(player2.strassen_points) allg_p2_wiesen_points += player2.wiesen_points p2_punkte_list_wiesen.append(player2.wiesen_points) allg_p2_kloester_points += player2.kloster_points p2_punkte_list_kloester.append(player2.kloster_points) i += 1 allg_log.write('\n\n\nAllgemeine Auswertung:\n\n\n') allg_log.write( f'Spieler1 hat in der ersten Haelfte {first_half_1} Spiele gewonnen, Player2 {first_half_2} und {first_half_draws} Spiele endeten Unentschieden.' ) allg_log.write( f'Spieler1 hat in der zweiten Haelfte {second_half_1} Spiele gewonnen, Player2 {second_half_2} und {second_half_draws} Spiele endeten Unentschieden.' ) allg_log.write( '\n\nPlayer1 hat durchschnittlich folgende Zahl von Meeples auf die folgenden Gebiete gesetzt:\n\n' ) allg_log.write(f'Orte:\t\t{p1_ort_meeples/nr_of_games}\n') allg_log.write(f'Strassen:\t{p1_strasse_meeples/nr_of_games}\n') allg_log.write(f'Kloester:\t{p1_kloster_meeples/nr_of_games}\n') allg_log.write(f'Wiesen:\t\t{p1_wiese_meeple/nr_of_games}\n\n') allg_log.write( 'Player2 hat durchschnittlich folgende Zahl von Meeples auf die folgenden Gebiete gesetzt:\n\n' ) allg_log.write(f'Orte:\t\t{p2_ort_meeples/nr_of_games}\n') allg_log.write(f'Strassen:\t{p2_strasse_meeples/nr_of_games}\n') allg_log.write(f'Kloester:\t{p2_kloster_meeples/nr_of_games}\n') allg_log.write(f'Wiesen:\t\t{p2_wiese_meeple/nr_of_games}\n\n') allg_log.write( 'Player1 hat in den Spielen durchschnittlich folgende Punktzahlen mit den folgenden Gebieten gemacht:\n\n' ) allg_log.write(f'Orte:\t\t{allg_p1_orts_points/nr_of_games}\n') allg_log.write(f'Strassen:\t{allg_p1_strassen_points/nr_of_games}\n') allg_log.write(f'Kloester:\t{allg_p1_kloester_points/nr_of_games}\n') allg_log.write(f'Wiesen:\t\t{allg_p1_wiesen_points/nr_of_games}\n\n') allg_log.write( 'Player2 hat in den Spielen durchschnittlich folgende Punktzahlen mit den folgenden Gebieten gemacht:\n\n' ) allg_log.write(f'Orte:\t\t{allg_p2_orts_points/nr_of_games}\n') allg_log.write(f'Strassen:\t{allg_p2_strassen_points/nr_of_games}\n') allg_log.write(f'Kloester:\t{allg_p2_kloester_points/nr_of_games}\n') allg_log.write(f'Wiesen:\t\t{allg_p2_wiesen_points/nr_of_games}\n') try: allg_log.write( '\nDas entspricht den folgenden Durchschnittswerten fuer Punkte pro feature-meeple:\n' ) allg_log.write('\nPlayer1:\n\n') allg_log.write( f'{allg_p1_orts_points/p1_ort_meeples} Punkte pro Orts-Meeple\n') allg_log.write( f'{allg_p1_strassen_points/p1_strasse_meeples} Punkte pro Strassen-Meeple\n' ) allg_log.write( f'{allg_p1_wiesen_points/p1_wiese_meeple} Punkte pro Wiesen-Meeple\n' ) allg_log.write( f'{allg_p1_kloester_points/p1_kloster_meeples} Punkte pro Kloster-Meeple\n\n' ) allg_log.write('Player2:\n\n') allg_log.write( f'{allg_p2_orts_points/p2_ort_meeples} Punkte pro Orts-Meeple\n') allg_log.write( f'{allg_p2_strassen_points/p2_strasse_meeples} Punkte pro Strassen-Meeple\n' ) allg_log.write( f'{allg_p2_wiesen_points/p2_wiese_meeple} Punkte pro Wiesen-Meeple\n' ) allg_log.write( f'{allg_p2_kloester_points/p2_kloster_meeples} Punkte pro Kloster-Meeple\n' ) except ZeroDivisionError: print("Error: Division durch 0") allg_log.write('\nDie einzelnen Spielwerte noch mal in Listen:\n') allg_log.write( 'Die von Player1 gesetzen Meeples auf die jeweiligen Gebiete:\n\n') allg_log.write(f'Orte1 = {p1_meeples_list_orte}\n') allg_log.write(f'Strassen1 = {p1_meeples_list_strassen}\n') allg_log.write(f'Wiesen1 = {p1_meeples_list_wiesen}\n') allg_log.write(f'Kloester1 = {p1_meeples_list_kloester}\n\n') allg_log.write( 'Die von Player2 gesetzen Meeples auf die jeweiligen Gebiete:\n\n') allg_log.write(f'Orte2 = {p2_meeples_list_orte}\n') allg_log.write(f'Strassen2 = {p2_meeples_list_strassen}\n') allg_log.write(f'Wiesen2 = {p2_meeples_list_wiesen}\n') allg_log.write(f'Kloester2 = {p2_meeples_list_kloester}\n\n') allg_log.write('Die von Player1 bekommenen Punkte mit den Gebieten:\n\n') allg_log.write(f'Orte1_punkte = {p1_punkte_list_orte}\n') allg_log.write(f'Strassen1_punkte = {p1_punkte_list_strassen}\n') allg_log.write(f'Wiesen1_punkte = {p1_punkte_list_wiesen}\n') allg_log.write(f'Kloester1_punkte = {p1_punkte_list_kloester}\n\n') allg_log.write('Die von Player2 bekommenen Punkte mit den Gebieten:\n\n') allg_log.write(f'Orte2_punkte = {p2_punkte_list_orte}\n') allg_log.write(f'Strassen2_punkte = {p2_punkte_list_strassen}\n') allg_log.write(f'Wiesen2_punkte = {p2_punkte_list_wiesen}\n') allg_log.write(f'Kloester2_punkte = {p2_punkte_list_kloester}\n\n') allg_log.write(f'Player1_ergebnisse = {p1_punkte}') allg_log.write(f'\nPlayer2_ergebnisse = {p2_punkte}') allg_log.close()
def test1(self): spiel = Spiel_class.Spiel(Kartenliste) player1 = Player(1) player2 = Player(2) k1 = Card('O', 'W', 'W', 'O', 'O') spiel.make_action(player2, k1, 1, 0, 0, k1.orte[0]) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 0) self.assertEqual(player2.punkte, 2) player1.punkte, player2.punkte = x, y k2 = Card('O', 'W', 'W', 'W') spiel.make_action(player1, k2, 2, 0, 1, k2.orte[0]) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 1) self.assertEqual(player2.punkte, 2) player1.punkte, player2.punkte = x, y k3 = Card('O', 'O', 'S', 'O', 'O', True) spiel.make_action(player2, k3, 1, 1, 2, k3.strassen[0]) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 1) self.assertEqual(player2.punkte, 5) player1.punkte, player2.punkte = x, y k4 = Card('S', 'O', 'S', 'S', 'G') wiese = None for w in k4.wiesen: if w.ecken == [5, 6]: wiese = w break spiel.make_action(player1, k4, 3, 0, 2, wiese) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 7) self.assertEqual(player2.punkte, 5) player1.punkte, player2.punkte = x, y k5 = Card('O', 'W', 'W', 'O', 'O') spiel.make_action(player2, k5, 2, 1, 0, k5.wiesen[0]) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 7) self.assertEqual(player2.punkte, 9) player1.punkte, player2.punkte = x, y #display_spielbrett_dict(spiel.cards_set) k6 = Card('W', 'W', 'S', 'S') spiel.make_action(player1, k6, 3, 1, 3, k6.strassen[0]) x, y = player1.punkte, player2.punkte spiel.final_evaluate() self.assertEqual(player1.punkte, 9) self.assertEqual(player2.punkte, 9) player1.punkte, player2.punkte = x, y