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% 确定在玩家类型与相同类型的玩家进行比赛的情况下,会计处理是否正确。