forked from carykh/PrisonersDilemmaTournament
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
1,414 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,7 @@ code/results.json | |
code/results.html | ||
edward/ | ||
comp/ | ||
/code/cache | ||
/code/cache-wal | ||
/code/cache-shm | ||
/code/cache.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from decimal import Decimal | ||
import random | ||
|
||
import numpy as np | ||
|
||
def strategy(history, memory): | ||
|
||
# A finite state machine detective. | ||
# It tries to figure out what the oponent is thinking, | ||
# and if it cant, it becomes a tit-for-tat | ||
# | ||
# TODO list | ||
# [X] Finite state machine | ||
# [X] Behave like a tft while detecting | ||
# [X] Handle randoms | ||
# [ ] Break out of D/D loops | ||
# [ ] Detect fibbonachi (ahh how do you spell that) | ||
# [ ] Maybe swap tft for another variant, unsure as of now | ||
# [ ] Submit | ||
# | ||
# Also, cary if you're reading this a few things: | ||
# 1. I'd love to see another version if this contest | ||
# with a chance of misscomunication, | ||
# as well as some other highly requested features | ||
# | ||
# 2. Although I doubt i'll win, if I do then I want to explain | ||
# more about this strategy. *please* contact me so i can | ||
# explain it to you in more details than I can include in this | ||
# simple readme. | ||
# | ||
# 3. Thanks for hosting such an amazing contest! | ||
# I met so many cool people though this and the atmosphere | ||
# inside the discord, with so many wonderful minds working | ||
# together is truly phenominal. I'm not exagerating when I say | ||
# that this week has truly changed my life. | ||
# | ||
# Thank you. | ||
|
||
num_rounds = history.shape[1] # number of rounds completed | ||
max_defection_threshold = Decimal(1) / Decimal(2) # do not forgive high defections | ||
small_defection_window = 20 | ||
max_local_unprovoked_defections = 5 # too many unprovoked defections? random | ||
window_start = max(0, num_rounds - small_defection_window) # Set start of detection window | ||
window_end = num_rounds # end on our current round | ||
opponents_recent_moves = history[1, window_start + 1 : window_end] #get opponents recent moves | ||
our_recent_moves = history[0, window_start : window_end - 1] #get our recent moves | ||
defections = opponents_recent_moves - our_recent_moves # subtract the moves from eachother to get a total number of defections | ||
opponents_recent_defections = np.count_nonzero(defections == 1) # count the number of defections | ||
|
||
if memory == None: | ||
if num_rounds == 5 or memory == "undecided": | ||
# Time to choose something. | ||
opponent_moves = history[1] | ||
opponent_stats = dict(zip(*np.unique(opponent_moves, return_counts=True))) | ||
if opponents_recent_defections > max_local_unprovoked_defections: | ||
# Random Detected | ||
choice = "defect" | ||
memory = "alwaysDefect" | ||
elif opponent_stats.get(0, 0) < 1: | ||
# they never defected, take advantage of them | ||
choice = "defect" | ||
memory = "alwaysDefect" | ||
elif opponent_stats.get(0, 0) == 5: | ||
# they always defect | ||
choice = "defect" | ||
memory = "alwaysDefect" | ||
elif opponent_moves[2] == 1 and opponent_moves[3] == 0: | ||
# ftft detected | ||
choice = "cooperate" | ||
memory = "alternate" | ||
else: | ||
choice = "cooperate" | ||
memory = "tft" | ||
elif num_rounds >= 5: | ||
# The game has gone on for longer than the testing schedule and we dont have a choice yet, choose tft | ||
memory = "tft" | ||
else: | ||
# We havent picked something yet. We are in testing. | ||
choice = "cooperate" | ||
memory = "tft" | ||
else: | ||
# We have a chosen state. | ||
if memory == "tft": | ||
#do tft | ||
choice = "cooperate" | ||
if history.shape[1] >= 1 and history[1,-1] == 0: | ||
# Choose to defect if and only if the opponent just defected. | ||
choice = "defect" | ||
elif memory == "alternate": | ||
#alternate | ||
our_last_move = history[0, -1] if num_rounds > 0 else 1 | ||
choice = 0 if our_last_move else 1 | ||
elif memory == "alwaysDefect": | ||
if history[1, -1] == "0": | ||
choice = "cooperate" | ||
memory = "undecided" | ||
#always defect | ||
choice = "defect" | ||
else: | ||
print("choice: " + choice) | ||
print("memory: " + memory) | ||
choice = "cooperate" | ||
|
||
return choice, memory |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
from decimal import Decimal | ||
import random | ||
|
||
import numpy as np | ||
|
||
|
||
# Detective, except: | ||
# - use nprtt instead of tit-for-tat for the forgiveness heuristic | ||
# - detect random and spam DDDD since defection is optimal with random | ||
# - detect ftft and spam DCDCDCDCDC to take advantage of it | ||
# - detect alwaysCooperate and spam DDDDD to take advantage of it, at the cost of the | ||
# grimTrigger | ||
def strategy(history, memory): | ||
""" | ||
:history: 2d numpy array of our and opponent past moves | ||
:memory: mode string, which may be None, 'tit-for-tat', 'alternate', 'defect', or | ||
'defect_assuming_cooperative' | ||
""" | ||
num_rounds = history.shape[1] | ||
testing_schedule = [1, 0, 0, 1, 1] | ||
max_defection_threshold = Decimal(1) / Decimal(2) # do not forgive high defections | ||
small_defection_window = 20 | ||
max_local_unprovoked_defections = 5 # too many unprovoked defections? random | ||
|
||
if num_rounds < len(testing_schedule): # intitial testing phase | ||
choice = testing_schedule[num_rounds] | ||
elif num_rounds == len(testing_schedule): # time to transition to our modes | ||
opponent_moves = history[1] | ||
opponent_stats = dict(zip(*np.unique(opponent_moves, return_counts=True))) | ||
if opponent_stats.get(0, 0) < 1: # they never defected, take advantage of them | ||
choice = 0 | ||
memory = "defect_assuming_cooperative" | ||
elif opponent_stats.get(0, 0) == len(testing_schedule): # they always defect | ||
choice = 0 | ||
memory = "defect" | ||
elif opponent_moves[2] == 1 and opponent_moves[3] == 0: # ftft detected | ||
choice = 0 | ||
memory = "alternate" | ||
else: | ||
choice = 1 | ||
memory = "tit-for-tat" | ||
else: # num_rounds > len(testing_schedule) | ||
if memory == "defect": | ||
# break out of defection if they cooperated twice in a row | ||
last_two_opponent_moves = history[1, -2:] | ||
if np.count_nonzero(last_two_opponent_moves) == 0: | ||
choice = 1 | ||
memory = "tit-for-tat" | ||
else: | ||
choice = 0 | ||
memory = "defect" | ||
elif memory == "defect_assuming_cooperative": | ||
if history[1, -1] == 0: # uh oh, we predicted wrong! | ||
choice = 0 | ||
memory = "tit-for-tat" | ||
else: | ||
choice = 0 | ||
memory = "defect_assuming_cooperative" | ||
elif memory == "alternate": | ||
our_last_move = history[0, -1] if num_rounds > 0 else 1 | ||
choice = 0 if our_last_move else 1 | ||
memory = "alternate" | ||
else: # nprtt or None | ||
# first check whether we've detected a random | ||
window_start = max(0, num_rounds - small_defection_window) | ||
window_end = num_rounds | ||
opponents_recent_moves = history[1, window_start + 1 : window_end] | ||
our_recent_moves = history[0, window_start : window_end - 1] | ||
defections = opponents_recent_moves - our_recent_moves | ||
opponents_recent_defections = np.count_nonzero(defections == 1) | ||
if opponents_recent_defections > max_local_unprovoked_defections: | ||
choice = 0 | ||
memory = "defect" | ||
|
||
else: | ||
opponents_last_move = history[1, -1] if num_rounds >= 1 else 1 | ||
our_second_last_move = history[0, -2] if num_rounds >= 2 else 1 | ||
opponent_history = history[1, 0:num_rounds] | ||
opponent_stats = dict( | ||
zip(*np.unique(opponent_history, return_counts=True)) | ||
) | ||
opponent_defection_rate = Decimal( | ||
int(opponent_stats.get(0, 0)) | ||
) / Decimal(num_rounds) | ||
|
||
be_patient = opponent_defection_rate <= max_defection_threshold | ||
|
||
choice = ( | ||
1 | ||
if ( | ||
opponents_last_move == 1 | ||
or (be_patient and our_second_last_move == 0) | ||
) | ||
else 0 | ||
) | ||
memory = "tit-for-tat" | ||
|
||
return choice, memory |
File renamed without changes.
Oops, something went wrong.