囚徒困境的奇怪结果

dan*_*yag 2 python game-theory

我尝试用 Python 实现囚徒困境,但我的结果并没有表明针锋相对是更好的解决方案,而是表明叛逃会带来更好的结果。

有人可以看看我的代码,并告诉我我在这里做错了什么吗?

import random
from colorama import Fore, Style
import numpy as np
# Define the actions
COOPERATE = 'cooperate'
DEFECT = 'defect'

# Define the strategies
def always_cooperate(history):
    return COOPERATE

def always_defect(history):
    return DEFECT

def random_choice_cooperate(history):
    return COOPERATE if random.random() < 0.75 else DEFECT

def random_choice_defect(history):
    return COOPERATE if random.random() < 0.25 else DEFECT

def random_choice_neutral(history):
    return COOPERATE if random.random() < 0.5 else DEFECT

def tit_for_tat(history):
    if not history:  # If it's the first round, cooperate
        return COOPERATE
    opponent_last_move = history[-1][1]  # Get the opponent's last move
    return opponent_last_move  # Mimic the opponent's last move

def tat_for_tit(history):
    if not history:  # If it's the first round, cooperate
        return DEFECT
    opponent_last_move = history[-1][1]  # Get the opponent's last move
    return opponent_last_move  # Mimic the opponent's last move

def tit_for_two_tats(history):
    if len(history) < 2:  # If it's the first or second round, cooperate
        return COOPERATE
    opponent_last_two_moves = history[-2:]  # Get the opponent's last two moves
    if all(move[1] == DEFECT for move in opponent_last_two_moves):  # If the opponent defected in the last two rounds
        return DEFECT
    return COOPERATE

# Define the payoff matrix
payoff_matrix = {
    (COOPERATE, COOPERATE): (3, 3),
    (COOPERATE, DEFECT): (0, 5),
    (DEFECT, COOPERATE): (5, 0),
    (DEFECT, DEFECT): (1, 1)
}


# Define the players
players = [always_cooperate, always_defect, random_choice_defect, tit_for_tat, tit_for_two_tats, random_choice_cooperate, tat_for_tit, random_choice_neutral]

# Assign a unique color to each player
player_colors = {
    'always_cooperate': Fore.GREEN,
    'always_defect': Fore.RED,
    'tit_for_tat': Fore.BLUE,
    'random_choice_cooperate': Fore.MAGENTA,
    'random_choice_defect': Fore.LIGHTRED_EX,
    'tat_for_tit': Fore.LIGHTYELLOW_EX,
    'random_choice_neutral': Fore.WHITE,
    'tit_for_two_tats': Fore.LIGHTBLACK_EX,
}


def tournament(players, rounds=100):
    total_scores = {player.__name__: 0 for player in players}
    for i in range(len(players)):
        for j in range(i+1, len(players)):
            player1 = players[i]
            player2 = players[j]
            history1 = []
            history2 = []
            match_scores = {player1.__name__: 0, player2.__name__: 0}
            # print(f"\n{player1.__name__} vs {player2.__name__}")
            for round in range(rounds):
                move1 = player1(history1)
                move2 = player2(history2)
                score1, score2 = payoff_matrix[(move1, move2)]
                match_scores[player1.__name__] += score1
                match_scores[player2.__name__] += score2
                total_scores[player1.__name__] += score1
                total_scores[player2.__name__] += score2
                history1.append((move1, move2))
                history2.append((move2, move1))
            # print(f"{player1.__name__} moves: {''.join([Fore.GREEN+'O'+Style.RESET_ALL if move[0]==COOPERATE else Fore.RED+'X'+Style.RESET_ALL for move in history1])}")
            # print(f"{player2.__name__} moves: {''.join([Fore.GREEN+'O'+Style.RESET_ALL if move[0]==COOPERATE else Fore.RED+'X'+Style.RESET_ALL for move in history2])}")
            # print(f"Match scores: {player1.__name__} {match_scores[player1.__name__]}, {player2.__name__} {match_scores[player2.__name__]}")  
    sorted_scores = sorted(total_scores.items(), key=lambda item: item[1], reverse=True)
    return sorted_scores

# Run the tournament
# for player, score in tournament(players):
#     print(f'\nFinal score: {player}: {score}')

num_tournaments = 1000
results = {player.__name__: [] for player in players}

for _ in range(num_tournaments):
    for player, score in tournament(players):
        results[player].append(score)

# Calculate the median score for each player and store them in a list of tuples
medians = [(player, np.median(scores)) for player, scores in results.items()]

# Sort the list of tuples based on the median score
sorted_medians = sorted(medians, key=lambda x: x[1])

num_players = len(sorted_medians)

# Print the sorted median scores with gradient color
for i, (player, median_score) in enumerate(sorted_medians):
    # Calculate the ratio of green and red based on the player's position
    green_ratio = i / (num_players - 1)
    red_ratio = 1 - green_ratio

    # Calculate the green and red components of the color
    green = int(green_ratio * 255)
    red = int(red_ratio * 255)

    # Create the color code
    color_code = f'\033[38;2;{red};{green};0m'
    player_color = player_colors.get(player, Fore.RESET)
    # Print the player name and median score with the color
    print(f'{player_color}{player}: {median_score} coins')
Run Code Online (Sandbox Code Playgroud)

代码本身会创建 100 轮的匹配。但随后它会迭代 1000 次以获得多次迭代的中值分数。

这是结果的输出

always_cooperate: 1347.024 coins
random_choice_cooperate: 1535.651 coins
tit_for_two_tats: 1561.442 coins
tit_for_tat: 1609.444 coins
tat_for_tit: 1619.43 coins
random_choice_neutral: 1663.855 coins
always_defect: 1711.764 coins
random_choice_defect: 1726.992 coins
Run Code Online (Sandbox Code Playgroud)

最新的 Veritasium 视频中,奖励矩阵呈现了困境,但“一报还一报”被认为是最有效的解决方案。我无法复制这个结果,因此我提出这个问题。

小智 5

我认为问题在于你们的锦标赛的设置。它的设置方式是always_defect永远不必对抗always_defect。因此,任何类型的玩家都不会与相同类型的玩家对抗。

always_defect成为小组中唯一的人似乎是一种优势。

修改线条

for i in range(len(players)):
    for j in range(i+1, len(players)):
Run Code Online (Sandbox Code Playgroud)

for i in range(len(players)):
    for j in range(i, len(players)):
Run Code Online (Sandbox Code Playgroud)

使得 analways_defect也必须与 an 比赛always_defect,这改变了情况。

但是,我不能 100% 确定在玩家类型与相同类型的玩家进行比赛的情况下,会计处理是否正确。