######################################################################################################################## # Imports. ######################################################################################################################## from otree.api import * import itertools import random ######################################################################################################################## # -. ######################################################################################################################## doc = """ Author: Felipe Montealegre. """ ######################################################################################################################## # TODOs. ######################################################################################################################## # In this commit: # The master instructions and the code match. #TODO: Incorporate changes for baseline and network in the screenshots. # TODO: Create app that displays the final results. # TODO: Add the other 3 blocks. Group composition should be shuffled. # Other ToDos: # TODO: Extend all functions to 16 players (see if it can be changed to variable number of players). # TODO: Identity in a group is changed every period, thus participant labels must be somehow dynamic. # TODO: Manually test the permanent link severance feature (i.e. rounds 4 and onward). ######################################################################################################################## # Constants. ######################################################################################################################## class C(BaseConstants): NAME_IN_URL = 'money_memory' PLAYERS_PER_GROUP = 8 NUM_ROUNDS = 50 MIN_NUM_ROUNDS = 10 STOP_PROBABILITY = 0.1 ENDOWMENT = 40 BLUE_IF_RED_HELPS = 20 BLUE_IF_RED_NOHELPS = -10 RED_OPEN_NOHELP = 10 TOKENS = PLAYERS_PER_GROUP / 2 ######################################################################################################################## # Subsession. ######################################################################################################################## # =====================================================================================================================# # Subsession developer's defined functions. # =====================================================================================================================# def creating_session(subsession): for p in subsession.get_players(): p.treatment = subsession.session.config['treatment'] p.participant.finished_rounds = False role_assignment(subsession) if subsession.round_number == 1: initial_links_on(subsession) elif subsession.round_number == 2: initial_links_on(subsession) def role_assignment(subsession): # Initial assignment of roles: sides = itertools.cycle(['blue', 'red']) reversed_sides = itertools.cycle(reversed(['blue', 'red'])) if subsession.round_number % 2 != 0: for p in subsession.get_players(): p.side = next(sides) elif subsession.round_number % 2 == 0: for p in subsession.get_players(): p.side = next(reversed_sides) def initial_links_on(subsession): odd_players = subsession.get_players()[::2] even_players = subsession.get_players()[1::2] for p in odd_players: if p.round_number == 1: p.links_to_evens = "".join([str(1) for p in even_players]) p.links_severed_to_evens = "".join([str(0) for p in even_players]) p.tokens_available = int(C.TOKENS) print("------------ links_to_evens:", p.links_to_evens) print("------------ links_severed_to_evens:", p.links_severed_to_evens) print("------------ tokens_available:", p.tokens_available) for p in even_players: if p.round_number == 1: p.tokens_available = 0 if p.round_number == 2: p.links_severed_to_odds = "".join([str(0) for p in odd_players]) print("------------ links_severed_to_odds:", p.links_severed_to_odds) def stringer(lista): stringed = ",".join(map(str, lista)) return stringed def enlister(stringa, mode): # mode=0 for 1111; mode=1 for 1,1,1,1 if mode == 0: enlisted = [int(i) for i in stringa] elif mode == 1: enlisted = [int(i) for i in stringa.split(",")] return enlisted # =====================================================================================================================# # Subsession class. # =====================================================================================================================# class Subsession(BaseSubsession): pass ######################################################################################################################## # Group. ######################################################################################################################## # =====================================================================================================================# # Group developer's defined functions. # =====================================================================================================================# # Function defining the entire interaction. def player_packager(group): # [(p1.current,p1.old), (p2.current,p2.old),...] odd_players = group.get_players()[::2] even_players = group.get_players()[1::2] if group.round_number == 1: past_odd_players = [] for i in odd_players: past_odd_players.append(None) past_even_players = [] for j in even_players: past_even_players.append(None) elif group.round_number >= 2: past_odd_players = [] for i in odd_players: past_odd_players.append(i.in_round(i.round_number - 1)) past_even_players = [] for j in even_players: past_even_players.append(j.in_round(j.round_number - 1)) odd_players_package = list(map(list, zip(past_odd_players, odd_players))) # Returns a list of lists. Each list is a player. Each sublist contains two elements (i.e. the first element [0] is the past player and the second element [1] is the current player. even_players_package = list(map(list, zip(past_even_players, even_players))) return odd_players_package, even_players_package def payoff_round_1_t0(group): # in interaction() this works for t0 and t1 odd_players_package, even_players_package = player_packager(group) for i in odd_players_package: string_list = "".join(i[1].links_to_evens) # for this round it is i[1]. Notice that for the others that use this code is i[0] (i.e. past players) odds_links_to_evens = [int(x) for x in string_list] i[1].links_tofrom_others = stringer(odds_links_to_evens) # This is only for vars_for_template. Not used in payoff payon_accumulator = [40] counter_j = 0 for j in even_players_package: if j[1].help_others == 1: payon_accumulator.append(odds_links_to_evens[counter_j] * j[1].help_others * C.BLUE_IF_RED_HELPS) elif j[1].help_others == 0: payon_accumulator.append(odds_links_to_evens[counter_j] * (not j[1].help_others) * C.BLUE_IF_RED_NOHELPS) counter_j += 1 i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) counter_j = 0 for j in even_players_package: # A beautiful story: For j in eve_players_package... links_from_odds = [] # I need an empty list to be filled with the decision of each of the odd players to connect or not to this j player... for i in odd_players_package: # To fill this list I loop over each zip_odd and get a complete list of each odd_player decision to connect to each even_player (not exactly what I want). links_to_evens = list(map(int, i[1].links_to_evens)) # This is the result from above. The list that I want is obtained by appending to my empty list above the decision of each odd player to my specific j player. links_from_odds.append(links_to_evens[counter_j]) # How? By taking the element (i.e. the j) that I need from each of the links_to_evens and appending it to my empty list (by means of a counter instead of the raw j). The end. j[1].links_tofrom_others = stringer(links_from_odds) # This line is only to pass information to the html (not used for payoff calculation). payon_accumulator = [40] for x in links_from_odds: payon_accumulator.append(x * (not j[1].help_others) * C.RED_OPEN_NOHELP) # I only need to extract from my links_from_odds list the consecutive for they payoff function (see commit cdbeb7a to understand the logic). j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) counter_j += 1 def payoff_round_even_t0(group): # in interaction() this works for t0 and t1 odd_players_package, even_players_package = player_packager(group) counter_j = 0 for j in even_players_package: # A beautiful story: For j in eve_players_package... links_from_odds = [] # I need an empty list to be filled with the decision of each of the odd players to connect or not to this j player... for i in odd_players_package: # To fill this list I loop over each zip_odd and get a complete list of each odd_player decision to connect to each even_player (not exactly what I want). links_to_evens = list(map(int, i[0].links_to_evens)) # This is the result from above. The list that I want is obtained by appending to my empty list above the decision of each odd player to my specific j player. links_from_odds.append(links_to_evens[counter_j]) # How? By taking the element (i.e. the j) that I need from each of the links_to_evens and appending it to my empty list (by means of a counter instead of the raw j). The end. j[1].links_tofrom_others = stringer(links_from_odds) payon_accumulator = [40] for x, i in zip(links_from_odds, odd_players_package): # This iterator rocks! Finally I need to loop over two different iterators (x and i, because the i loop was closed before). if i[1].help_others == 1: payon_accumulator.append(x * i[1].help_others * C.BLUE_IF_RED_HELPS) elif i[1].help_others == 0: payon_accumulator.append(x * (not i[1].help_others) * C.BLUE_IF_RED_NOHELPS) j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) counter_j += 1 for i in odd_players_package: string_list = "".join(i[0].links_to_evens) # for this round it is i[0]. odds_links_to_evens = [int(x) for x in string_list] i[1].links_tofrom_others = stringer(odds_links_to_evens) payon_accumulator = [40] for x in odds_links_to_evens: payon_accumulator.append((x * (not i[1].help_others) * C.RED_OPEN_NOHELP)) i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) def payoff_round_odd_t0(group): # in interaction() this works for t0 and t1 odd_players_package, even_players_package = player_packager(group) counter_i = 0 for i in odd_players_package: links_from_evens = [] for j in even_players_package: links_to_odds = list(map(int, j[0].links_to_odds)) links_from_evens.append(links_to_odds[counter_i]) i[1].links_tofrom_others = stringer(links_from_evens) payon_accumulator = [40] for x, j in zip(links_from_evens, even_players_package): if j[1].help_others == 1: payon_accumulator.append(x * j[1].help_others * C.BLUE_IF_RED_HELPS) elif j[1].help_others == 0: payon_accumulator.append(x * (not j[1].help_others) * C.BLUE_IF_RED_NOHELPS) i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) counter_i += 1 for j in even_players_package: string_list = "".join(j[0].links_to_odds) evens_links_to_odds = [int(x) for x in string_list] j[1].links_tofrom_others = stringer(evens_links_to_odds) payon_accumulator = [40] for x in evens_links_to_odds: payon_accumulator.append((x * (not j[1].help_others) * C.RED_OPEN_NOHELP)) j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) def caronte_accountant(tokens_available): if tokens_available >= 1: return 1 elif tokens_available < 1: return 0 def help_or_trade(player): if player.help_others == 2: return 1 elif player.help_others == 0 or player.help_others == 1: return 0 def payoff_round_1_t2(group): odd_players_package, even_players_package = player_packager(group) for i in odd_players_package: print("--- ODD PLAYER") string_list = "".join(i[1].links_to_evens) # for this round it is i[1]. Notice that for the others that use this code is i[0] (i.e. past players) odds_links_to_evens = [int(x) for x in string_list] i[1].links_tofrom_others = stringer(odds_links_to_evens) # This is only for vars_for_template. Not used in payoff payon_accumulator = [40] counter_j = 0 tokens_available_i = i[1].tokens_available print("------------- tokens_available_i initial", tokens_available_i) tokens_available_account_post = [] # obolos_available_account_post = [] tokens_available_i_pre = i[1].tokens_available print("------------- tokens_available_i_pre initial", tokens_available_i_pre) obolos_available_account_pre = [] # Pre-transaction. This list allows me to pass info on how i spends its money for the payoff function of j (even). caronte_obolos = caronte_accountant(tokens_available_i) for j in even_players_package: print("------ EVEN PLAYER") if j[1].help_others == 1: payon_accumulator.append(odds_links_to_evens[counter_j] * j[1].help_others * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_i no_trade", tokens_available_i) elif j[1].help_others == 0: payon_accumulator.append(odds_links_to_evens[counter_j] * (not j[1].help_others) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_i no_trade", tokens_available_i) elif j[1].help_others == 2 and odds_links_to_evens[counter_j] == 1 and caronte_obolos == 1: payon_accumulator.append(odds_links_to_evens[counter_j] * (help_or_trade(j[1]) * caronte_obolos) * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_i Trade BEFORE", tokens_available_i) tokens_available_i = tokens_available_i - 1 print("------------- tokens_available_i Trade AFTER", tokens_available_i) tokens_available_i_pre = tokens_available_i + 1 caronte_obolos = caronte_accountant(tokens_available_i) elif j[1].help_others == 2 and (odds_links_to_evens[counter_j] == 0 or caronte_obolos == 0): payon_accumulator.append(odds_links_to_evens[counter_j] * ((help_or_trade(j[1])) * (not caronte_obolos)) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_i Trade(not possible) BEFORE", tokens_available_i) tokens_available_i = tokens_available_i print("------------- tokens_available_i Trade(not possible) AFTER", tokens_available_i) tokens_available_i_pre = tokens_available_i caronte_obolos = caronte_accountant(tokens_available_i) tokens_available_account_post.append(tokens_available_i) # obolos_available_account_post.append(caronte_accountant(tokens_available_i)) obolos_available_account_pre.append(caronte_accountant(tokens_available_i_pre)) counter_j += 1 i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) i[1].tokens_future = tokens_available_i i[1].tokens_available_account = "".join(map(str, tokens_available_account_post)) # Gives me the even player that took i's coin. (e.g. if i has 1 coin and (1000) it tells that p4 but not p2 took it). # i[1].obolos_available_account = "".join(map(str, obolos_available_account_post)) i[1].obolos_available_account_pre = "".join(map(str, obolos_available_account_pre)) counter_j = 0 for j in even_players_package: print("### player ###") links_from_odds = [] list_obolos_from_odds = [] # This is a list that contains for each i player if this i player has or not as caronte's obolos (ready to be "re"spent in the code below) tokens_future = 0 for i in odd_players_package: links_to_evens = list(map(int, i[1].links_to_evens)) links_from_odds.append(links_to_evens[counter_j]) obolos_available_account_pre = list(map(int, i[1].obolos_available_account_pre)) list_obolos_from_odds.append(caronte_accountant(obolos_available_account_pre[counter_j])) j[1].links_tofrom_others = stringer(links_from_odds) # This line is only to pass information to the html (not used for payoff calculation). print("============= list_obolos_from_odds initial", list_obolos_from_odds) payon_accumulator = [40] for x, y in zip(links_from_odds, list_obolos_from_odds): print("------------------ ############# links_from_odds, list_obolos_from_odds, help_others", x, y, j[1].help_others) # Read row by row gives if a transaction is made (e.g. 1,1,2 = transaction) if j[1].help_others == 0 or j[1].help_others == 1: payon_accumulator.append(x * (not j[1].help_others) * C.RED_OPEN_NOHELP) elif j[1].help_others == 2: payon_accumulator.append(x * help_or_trade(j[1]) * (not y) * C.RED_OPEN_NOHELP) if x == 1 and y == 1: tokens_future = tokens_future + 1 elif x == 1 and y == 0: tokens_future = tokens_future j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) j[1].tokens_future = tokens_future counter_j += 1 def payoff_round_even_t2(group): odd_players_package, even_players_package = player_packager(group) counter_j = 0 for j in even_players_package: # A beautiful story: For j in eve_players_package... print("--- EVEN PLAYER") links_from_odds = [] # I need an empty list to be filled with the decision of each of the odd players to connect or not to this j player... tokens_available_j = j[0].tokens_future print("------------- tokens_available_j initial", tokens_available_j) tokens_available_account_post = [] # obolos_available_account_post = [] tokens_available_j_pre = j[0].tokens_future print("------------- tokens_available_j_pre initial", tokens_available_j_pre) obolos_available_account_pre = [] # Pre-transaction. This list allows me to pass info on how i spends its money for the payoff function of j (even). caronte_obolos = caronte_accountant(tokens_available_j) for i in odd_players_package: links_to_evens = list(map(int, i[0].links_to_evens)) links_from_odds.append(links_to_evens[counter_j]) j[1].links_tofrom_others = stringer(links_from_odds) payon_accumulator = [40] for x, i in zip(links_from_odds, odd_players_package): print("------ ODD PLAYER") if i[1].help_others == 1: payon_accumulator.append(x * i[1].help_others * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_j no_trade", tokens_available_j) elif i[1].help_others == 0: payon_accumulator.append((not i[1].help_others) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_j no_trade", tokens_available_j) elif i[1].help_others == 2 and x == 1 and caronte_obolos == 1: payon_accumulator.append(x * (help_or_trade(i[1]) * caronte_obolos) * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_j Trade BEFORE", tokens_available_j) tokens_available_j = tokens_available_j - 1 print("------------- tokens_available_j Trade AFTER", tokens_available_j) tokens_available_j_pre = tokens_available_j + 1 caronte_obolos = caronte_accountant(tokens_available_j) elif i[1].help_others == 2 and (x == 0 or caronte_obolos == 0): payon_accumulator.append(x * ((help_or_trade(i[1])) * (not caronte_obolos)) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_j Trade(not possible) BEFORE", tokens_available_j) tokens_available_j = tokens_available_j print("------------- tokens_available_j Trade(not possible) AFTER", tokens_available_j) tokens_available_j_pre = tokens_available_j caronte_obolos = caronte_accountant(tokens_available_j) tokens_available_account_post.append(tokens_available_j) # obolos_available_account_post.append(caronte_accountant(tokens_available_i)) obolos_available_account_pre.append(caronte_accountant(tokens_available_j_pre)) j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) j[1].tokens_future = tokens_available_j j[1].tokens_available_account = "".join(map(str, tokens_available_account_post)) # Gives me the even player that took i's coin. (e.g. if i has 1 coin and (1000) it tells that p4 but not p2 took it). # j[1].obolos_available_account = "".join(map(str, obolos_available_account_post)) j[1].obolos_available_account_pre = "".join(map(str, obolos_available_account_pre)) counter_j += 1 counter_i = 0 for i in odd_players_package: print("--- ODD PLAYER") string_list = "".join(i[0].links_to_evens) # for this round it is i[0]. odds_links_to_evens = [int(x) for x in string_list] i[1].links_tofrom_others = stringer(odds_links_to_evens) list_obolos_from_evens = [] # This is a list that contains for each j player if this j player has or not a caronte's obolos (ready to be "re"spent in the code below) tokens_future = 0 for j in even_players_package: obolos_available_account_pre = list(map(int, j[1].obolos_available_account_pre)) list_obolos_from_evens.append(caronte_accountant(obolos_available_account_pre[counter_i])) print("============= list_obolos_from_evens initial", list_obolos_from_evens) payon_accumulator = [40] for x, y in zip(odds_links_to_evens, list_obolos_from_evens): print("------------------ ############# odds_links_to_evens, list_obolos_from_evens, help_others", x, y, i[1].help_others) # Read row by row gives if a transaction is made (e.g. 1,1,2 = transaction) if i[1].help_others == 0 or i[1].help_others == 1: payon_accumulator.append(x * (not i[1].help_others) * C.RED_OPEN_NOHELP) elif i[1].help_others == 2: payon_accumulator.append(x * help_or_trade(i[1]) * (not y) * C.RED_OPEN_NOHELP) if x == 1 and y == 1: tokens_future = tokens_future + 1 elif x == 1 and y == 0: tokens_future = tokens_future i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) i[1].tokens_future = tokens_future counter_i += 1 def payoff_round_odd_t2(group): odd_players_package, even_players_package = player_packager(group) counter_i = 0 for i in odd_players_package: print("--- ODD PLAYER") links_from_evens = [] tokens_available_i = i[0].tokens_future print("------------- tokens_available_i initial", tokens_available_i) tokens_available_account_post = [] # obolos_available_account_post = [] tokens_available_i_pre = i[0].tokens_future print("------------- tokens_available_i_pre initial", tokens_available_i_pre) obolos_available_account_pre = [] # Pre-transaction. This list allows me to pass info on how i spends its money for the payoff function of j (even). caronte_obolos = caronte_accountant(tokens_available_i) for j in even_players_package: links_to_odds = list(map(int, j[0].links_to_odds)) links_from_evens.append(links_to_odds[counter_i]) i[1].links_tofrom_others = stringer(links_from_evens) payon_accumulator = [40] for x, j in zip(links_from_evens, even_players_package): print("------ EVEN PLAYER") if j[1].help_others == 1: payon_accumulator.append(x * j[1].help_others * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_i no_trade", tokens_available_i) elif j[1].help_others == 0: payon_accumulator.append((not j[1].help_others) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_i no_trade", tokens_available_i) elif j[1].help_others == 2 and x == 1 and caronte_obolos == 1: payon_accumulator.append(x * (help_or_trade(j[1]) * caronte_obolos) * C.BLUE_IF_RED_HELPS) print("------------- tokens_available_i Trade BEFORE", tokens_available_i) tokens_available_i = tokens_available_i - 1 print("------------- tokens_available_i Trade AFTER", tokens_available_i) tokens_available_i_pre = tokens_available_i + 1 caronte_obolos = caronte_accountant(tokens_available_i) elif j[1].help_others == 2 and (x == 0 or caronte_obolos == 0): payon_accumulator.append(x * ((help_or_trade(j[1])) * (not caronte_obolos)) * C.BLUE_IF_RED_NOHELPS) print("------------- tokens_available_i Trade(not possible) BEFORE", tokens_available_i) tokens_available_i = tokens_available_i print("------------- tokens_available_i Trade(not possible) AFTER", tokens_available_i) tokens_available_i_pre = tokens_available_i caronte_obolos = caronte_accountant(tokens_available_i) tokens_available_account_post.append(tokens_available_i) # obolos_available_account_post.append(caronte_accountant(tokens_available_i)) obolos_available_account_pre.append(caronte_accountant(tokens_available_i_pre)) i[1].payon = sum(payon_accumulator) i[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", i[1].payon_accumulator, "Type:", type(i[1].payon_accumulator)) i[1].tokens_future = tokens_available_i i[1].tokens_available_account = "".join(map(str, tokens_available_account_post)) # Gives me the even player that took i's coin. (e.g. if i has 1 coin and (1000) it tells that p4 but not p2 took it). # j[1].obolos_available_account = "".join(map(str, obolos_available_account_post)) i[1].obolos_available_account_pre = "".join(map(str, obolos_available_account_pre)) counter_i += 1 counter_j = 0 for j in even_players_package: print("--- EVEN PLAYER") string_list = "".join(j[0].links_to_odds) evens_links_to_odds = [int(x) for x in string_list] j[1].links_tofrom_others = stringer(evens_links_to_odds) list_obolos_from_odds = [] tokens_future = 0 for i in odd_players_package: obolos_available_account_pre = list(map(int, i[1].obolos_available_account_pre)) list_obolos_from_odds.append(caronte_accountant(obolos_available_account_pre[counter_j])) print("============= list_obolos_from_odds initial", list_obolos_from_odds) payon_accumulator = [40] for x, y in zip(evens_links_to_odds, list_obolos_from_odds): print("------------------ ############# odds_links_to_evens, list_obolos_from_evens, help_others", x, y, j[1].help_others) # Read row by row gives if a transaction is made (e.g. 1,1,2 = transaction) if j[1].help_others == 0 or j[1].help_others == 1: payon_accumulator.append(x * (not j[1].help_others) * C.RED_OPEN_NOHELP) elif j[1].help_others == 2: payon_accumulator.append(x * help_or_trade(j[1]) * (not y) * C.RED_OPEN_NOHELP) if x == 1 and y == 1: tokens_future = tokens_future + 1 elif x == 1 and y == 0: tokens_future = tokens_future j[1].payon = sum(payon_accumulator) j[1].payon_accumulator = stringer(payon_accumulator) print("$$$ PAYON list:", payon_accumulator, "Type:", type(payon_accumulator)) print("$$$ PAYON list:", j[1].payon_accumulator, "Type:", type(j[1].payon_accumulator)) j[1].tokens_future = tokens_future counter_j += 1 def block_payoff(group): for player in group.get_players(): if player.round_number == 1: player.accumulated_block_payoff = player.payon elif player.round_number > 1: player.accumulated_block_payoff = player.payon + player.in_round(player.round_number - 1).accumulated_block_payoff print("%%%%%%%%%%%%%%%%%%%%%%%%%", "/player.payon:", player.payon, "player.in_round(player.round_number - 1).accumulated_block_payoff:", player.in_round(player.round_number - 1).accumulated_block_payoff, "/player.accumulated_block_payoff", player.accumulated_block_payoff) def interaction(group): if group.session.config['treatment'] == 0 or group.session.config['treatment'] == 1: if group.round_number == 1: # Odd players are blue; Even players are red. payoff_round_1_t0(group) print("------------Interaction in round:", group.round_number) elif group.round_number % 2 == 0: # Odd players are red; Even players are blue. payoff_round_even_t0(group) print("------------Interaction in round:", group.round_number) elif group.round_number != 1 and group.round_number % 2 != 0: # Odd players are blue; Even players are red. payoff_round_odd_t0(group) print("------------Interaction in round:", group.round_number) elif group.session.config['treatment'] == 2: if group.round_number == 1: # Odd players are blue; Even players are red. payoff_round_1_t2(group) print("------------Interaction in round:", group.round_number) elif group.round_number % 2 == 0: # Odd players are red; Even players are blue. payoff_round_even_t2(group) print("------------Interaction in round:", group.round_number) elif group.round_number != 1 and group.round_number % 2 != 0: # Odd players are blue; Even players are red. payoff_round_odd_t2(group) print("------------Interaction in round:", group.round_number) block_payoff(group) # =====================================================================================================================# # Group class. # =====================================================================================================================# class Group(BaseGroup): pass ######################################################################################################################## # Player. ######################################################################################################################## # =====================================================================================================================# # Player developer's defined functions. # =====================================================================================================================# def make_link_to(label): return models.IntegerField( label=label, choices=[ [0, "No"], [1, "Yes"], ], widget=widgets.RadioSelect, ) def make_severance_to(label): return models.IntegerField( label=label, choices=[ [0, "No"], [1, "Yes"], ], widget=widgets.RadioSelect, ) def help_others_choices(player): if player.session.config['treatment'] == 0 or player.session.config['treatment'] == 1: choices = [ [0, "No"], [1, "Yes"], ] elif player.session.config['treatment'] == 2: choices=[ [0, "No"], [1, "Yes"], [2, "Trade"] ] return choices # =====================================================================================================================# # Player class. # =====================================================================================================================# class Player(BasePlayer): # For all players: treatment = models.IntegerField() side = models.StringField() # role() is already taken by oTree. tokens_available = models.IntegerField() tokens_available_account = models.StringField() # obolos_available_account = models.StringField() obolos_available_account_pre = models.StringField() tokens_future = models.IntegerField() # help_others is a dummy for the red player that is 1 if she decided to # help the others. help_others = models.IntegerField( label="Do you want to help the other players?", widget=widgets.RadioSelect ) # trade = models.IntegerField() links_to_odds = models.StringField(blank=True) links_to_evens = models.StringField(blank=True) links_severed_to_odds = models.StringField(blank=True) links_severed_to_evens = models.StringField(blank=True) # TODO: If I delete the blank=True should it still work? links_tofrom_others = models.StringField() payon_accumulator = models.StringField() payon = models.IntegerField() # payoff() is already taken by oTree. accumulated_block_payoff = models.IntegerField() link_to_p1 = make_link_to("Do you want to connect to Player 1 in the next round?") link_to_p2 = make_link_to("Do you want to connect to Player 2 in the next round?") link_to_p3 = make_link_to("Do you want to connect to Player 3 in the next round?") link_to_p4 = make_link_to("Do you want to connect to Player 4 in the next round?") link_to_p5 = make_link_to("Do you want to connect to Player 5 in the next round?") link_to_p6 = make_link_to("Do you want to connect to Player 6 in the next round?") link_to_p7 = make_link_to("Do you want to connect to Player 7 in the next round?") link_to_p8 = make_link_to("Do you want to connect to Player 8 in the next round?") link_to_p9 = make_link_to("Do you want to connect to Player 9 in the next round?") link_to_p10 = make_link_to("Do you want to connect to Player 10 in the next round?") link_to_p11 = make_link_to("Do you want to connect to Player 11 in the next round?") link_to_p12 = make_link_to("Do you want to connect to Player 12 in the next round?") link_to_p13 = make_link_to("Do you want to connect to Player 13 in the next round?") link_to_p14 = make_link_to("Do you want to connect to Player 14 in the next round?") link_to_p15 = make_link_to("Do you want to connect to Player 15 in the next round?") link_to_p16 = make_link_to("Do you want to connect to Player 16 in the next round?") link_severed_to_p1 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 1?") link_severed_to_p2 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 2?") link_severed_to_p3 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 3?") link_severed_to_p4 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 4?") link_severed_to_p5 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 5?") link_severed_to_p6 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 6?") link_severed_to_p7 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 7?") link_severed_to_p8 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 8?") link_severed_to_p9 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 9?") link_severed_to_p10 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 10?") link_severed_to_p11 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 11?") link_severed_to_p12 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 12?") link_severed_to_p13 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 13?") link_severed_to_p14 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 14?") link_severed_to_p15 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 15?") link_severed_to_p16 = make_severance_to("Do you want to PERMANENTLY delete the link to Player 16?") def link_to_string_maker(player): if C.PLAYERS_PER_GROUP == 8: if player.round_number % 2 != 0: link_to_evens_asalist_8 = [player.field_maybe_none('link_to_p2'), player.field_maybe_none('link_to_p4'), player.field_maybe_none('link_to_p6'), player.field_maybe_none('link_to_p8')] # A link_to_px can get here NUll. SO create a list replacing the NULL by a 0. link_to_evens_asalist_8 = [i if i is not None else 0 for i in link_to_evens_asalist_8] # Together with the field_maybe_none() this None to 0 list comprehension rocks. link_to_evens_asalist = link_to_evens_asalist_8 links_to_evens = "".join(map(str, link_to_evens_asalist)) player.links_to_evens = links_to_evens return links_to_evens elif player.round_number % 2 == 0: link_to_odds_asalist_8 = [player.field_maybe_none('link_to_p1'), player.field_maybe_none('link_to_p3'), player.field_maybe_none('link_to_p5'), player.field_maybe_none('link_to_p7')] link_to_odds_asalist_8 = [i if i is not None else 0 for i in link_to_odds_asalist_8] link_to_odds_asalist = link_to_odds_asalist_8 links_to_odds = "".join(map(str, link_to_odds_asalist)) player.links_to_odds = links_to_odds return links_to_odds def link_severed_to_string_maker(player): if player.session.config['treatment'] == 1: if C.PLAYERS_PER_GROUP == 8: if player.round_number % 2 != 0: link_severed_to_evens_asalist_8 = [player.field_maybe_none('link_severed_to_p2'), player.field_maybe_none('link_severed_to_p4'), player.field_maybe_none('link_severed_to_p6'), player.field_maybe_none('link_severed_to_p8')] link_severed_to_evens_asalist_8 = [i if i is not None else 0 for i in link_severed_to_evens_asalist_8] # Together with the field_maybe_none() this None to 0 list comprehension rocks. link_severed_to_evens_asalist = link_severed_to_evens_asalist_8 links_severed_to_evens = "".join(map(str, link_severed_to_evens_asalist)) player.links_severed_to_evens = links_severed_to_evens return links_severed_to_evens elif player.round_number % 2 == 0: link_severed_to_odds_asalist_8 = [player.field_maybe_none('link_severed_to_p1'), player.field_maybe_none('link_severed_to_p3'), player.field_maybe_none('link_severed_to_p5'), player.field_maybe_none('link_severed_to_p7')] link_severed_to_odds_asalist_8 = [i if i is not None else 0 for i in link_severed_to_odds_asalist_8] link_severed_to_odds_asalist = link_severed_to_odds_asalist_8 links_severed_to_odds = "".join(map(str, link_severed_to_odds_asalist)) player.links_severed_to_odds = links_severed_to_odds return links_severed_to_odds elif player.session.config['treatment'] == 0 or player.session.config['treatment'] == 2: if C.PLAYERS_PER_GROUP == 8: if player.round_number % 2 != 0: link_to_evens = player.links_to_evens link_to_evens = [int(i) for i in link_to_evens] links_severed_to_evens = [1 if i == 0 else 0 for i in link_to_evens] links_severed_to_evens = "".join(map(str, links_severed_to_evens)) player.links_severed_to_evens = links_severed_to_evens return links_severed_to_evens elif player.round_number % 2 == 0: link_to_odds = player.links_to_odds link_to_odds = [int(i) for i in link_to_odds] links_severed_to_odds = [1 if i == 0 else 0 for i in link_to_odds] links_severed_to_odds = "".join(map(str, links_severed_to_odds)) player.links_severed_to_odds = links_severed_to_odds return links_severed_to_odds ######################################################################################################################## # Pages. ######################################################################################################################## # The page sequence is as follows: # 0) Initial condition: in round 1, blue has all links open. # 1) Red decides to help or not to help. # 2) Payoff page taking into account red decision in time t and blue decision # in time t-1. # 3) blue decides to change links. class RedChooses(Page): form_model = 'player' form_fields = ['help_others'] @staticmethod def is_displayed(player): if player.side == 'red': return True class Interaction(WaitPage): @staticmethod def after_all_players_arrive(group: Group): interaction(group) def get_form_fields_blue_t0(player): players = [i+1 for i in range(C.PLAYERS_PER_GROUP)] odd_players = [i for i in players if i % 2 != 0] even_players = [i for i in players if i % 2 == 0] counter_list = list(range(1, len(even_players) + 1)) # even_players or odd_players. It does not matter. if player.round_number == 1: links_severed_to_evens = [int(i) for i in player.links_severed_to_evens] form_fields = ['links_to_evens'] base_link_to = ['link_to_p'] for i, j, k in zip(even_players, links_severed_to_evens, counter_list): if j == 0: base_link_to.append(str(even_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number == 2: links_severed_to_odds = [int(i) for i in player.links_severed_to_odds] form_fields = ['links_to_odds'] base_link_to = ['link_to_p'] for i, j, k in zip(odd_players, links_severed_to_odds, counter_list): if j == 0: base_link_to.append(str(odd_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number >= 3 and player.round_number % 2 != 0: links_severed_to_evens = [int(i) for i in player.in_round(player.round_number - 2).links_severed_to_evens] form_fields = ['links_to_evens'] base_link_to = ['link_to_p'] for i, j, k in zip(even_players, links_severed_to_evens, counter_list): if j == 0: base_link_to.append(str(even_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number >= 4 and player.round_number % 2 == 0: links_severed_to_odds = [int(i) for i in player.in_round(player.round_number - 2).links_severed_to_odds] form_fields = ['links_to_odds'] base_link_to = ['link_to_p'] for i, j, k in zip(odd_players, links_severed_to_odds, counter_list): if j == 0: base_link_to.append(str(odd_players[k - 1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] return form_fields def get_form_fields_blue_t1(player): players = [i+1 for i in range(C.PLAYERS_PER_GROUP)] odd_players = [i for i in players if i % 2 != 0] even_players = [i for i in players if i % 2 == 0] counter_list = list(range(1, len(even_players) + 1)) # even_players or odd_players. It does not matter. if player.round_number == 1: links_severed_to_evens = [int(i) for i in player.links_severed_to_evens] form_fields = ['links_to_evens', 'links_severed_to_evens'] base_link_to = ['link_to_p'] base_link_severed_to = ['link_severed_to_p'] for i, j, k in zip(even_players, links_severed_to_evens, counter_list): if j == 0: base_link_severed_to.append(str(even_players[k-1])) base_link_severed_to = "".join(base_link_severed_to) form_fields.append(base_link_severed_to) base_link_severed_to = ['link_severed_to_p'] base_link_to.append(str(even_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number == 2: links_severed_to_odds = [int(i) for i in player.links_severed_to_odds] form_fields = ['links_to_odds', 'links_severed_to_odds'] base_link_to = ['link_to_p'] base_link_severed_to = ['link_severed_to_p'] for i, j, k in zip(odd_players, links_severed_to_odds, counter_list): if j == 0: base_link_severed_to.append(str(odd_players[k-1])) base_link_severed_to = "".join(base_link_severed_to) form_fields.append(base_link_severed_to) base_link_severed_to = ['link_severed_to_p'] base_link_to.append(str(odd_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number >= 3 and player.round_number % 2 != 0: links_severed_to_evens = [int(i) for i in player.in_round(player.round_number - 2).links_severed_to_evens] form_fields = ['links_to_evens', 'links_severed_to_evens'] base_link_to = ['link_to_p'] base_link_severed_to = ['link_severed_to_p'] for i, j, k in zip(even_players, links_severed_to_evens, counter_list): if j == 0: base_link_severed_to.append(str(even_players[k-1])) base_link_severed_to = "".join(base_link_severed_to) form_fields.append(base_link_severed_to) base_link_severed_to = ['link_severed_to_p'] base_link_to.append(str(even_players[k-1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] elif player.round_number >= 4 and player.round_number % 2 == 0: links_severed_to_odds = [int(i) for i in player.in_round(player.round_number - 2).links_severed_to_odds] form_fields = ['links_to_odds', 'links_severed_to_odds'] base_link_to = ['link_to_p'] base_link_severed_to = ['link_severed_to_p'] for i, j, k in zip(odd_players, links_severed_to_odds, counter_list): if j == 0: base_link_severed_to.append(str(odd_players[k - 1])) base_link_severed_to = "".join(base_link_severed_to) form_fields.append(base_link_severed_to) base_link_severed_to = ['link_severed_to_p'] base_link_to.append(str(odd_players[k - 1])) base_link_to = "".join(base_link_to) form_fields.append(base_link_to) base_link_to = ['link_to_p'] return form_fields class BlueChooses(Page): form_model = 'player' @staticmethod def get_form_fields(player): if player.session.config['treatment'] == 0 or player.session.config['treatment'] == 2: return get_form_fields_blue_t0(player) elif player.session.config['treatment'] == 1: return get_form_fields_blue_t1(player) @staticmethod def is_displayed(player): if player.side == 'blue': return True @staticmethod def before_next_page(player, timeout_happened): link_to_string_maker(player) link_severed_to_string_maker(player) @staticmethod def vars_for_template(player): print("######### FORMFIELDS:") ab_fields = None if player.session.config['treatment'] == 1: ab_fields = True form_fields = get_form_fields_blue_t1(player) base_fields = form_fields[0:2] print(base_fields) clean_fields = form_fields[2:] print(clean_fields) b_fields = clean_fields[0::2] print(b_fields) a_fields = clean_fields[1::2] print(a_fields) return dict(a_fields=a_fields, b_fields=b_fields, ab_fields=ab_fields) elif player.session.config['treatment'] == 0 or player.session.config['treatment'] == 2: ab_fields = False form_fields = get_form_fields_blue_t0(player) print(form_fields) base_fields = form_fields[0:1] print(base_fields) clean_fields = form_fields[1:] print(clean_fields) a_fields = clean_fields[0:] print(a_fields) return dict(a_fields=a_fields, ab_fields=ab_fields) def other_player_listmaker(player): if (player.round_number % 2 != 0 and player.side == "red") or (player.round_number % 2 == 0 and player.side == "blue"): other_players = ["p1", "p3", "p5", "p7"] elif (player.round_number % 2 != 0 and player.side == "blue") or (player.round_number % 2 == 0 and player.side == "red"): other_players = ["p2", "p4", "p6", "p8"] return other_players class Results(Page): @staticmethod def vars_for_template(player): if player.side == 'blue': return dict(other_players=other_player_listmaker(player), payon_accumulator=enlister(player.payon_accumulator, 1), links_tofrom_others=enlister(player.links_tofrom_others, 1), blue_player=True, red_player=False ) elif player.side == 'red': return dict(other_players=other_player_listmaker(player), payon_accumulator=enlister(player.payon_accumulator, 1), links_tofrom_others=enlister(player.links_tofrom_others, 1), blue_player=False, red_player=True ) class ShuffleWaitPage(WaitPage): @staticmethod def after_all_players_arrive(group): round_breaker = random.random() if round_breaker < C.STOP_PROBABILITY and group.round_number > C.MIN_NUM_ROUNDS: print("=============================================================== GAME OVER ===============================================================") print("Probability:", round_breaker, "Round number:", group.round_number) for p in group.get_players(): p.participant.finished_rounds = True print("--------------------------------------------------------------- ROUND OVER ---------------------------------------------------------------", "Round:", group.round_number) class BlockEnd(Page): @staticmethod def is_displayed(player: Player): participant = player.participant return participant.finished_rounds @staticmethod def vars_for_template(player: Player): player.participant.accum_payoff_block_1 = player.accumulated_block_payoff return dict(player_accumulated_block_payoff=player.accumulated_block_payoff, participant_accumulated_block_payoff=player.participant.accum_payoff_block_1 ) @staticmethod def app_after_this_page(player: Player, upcoming_apps): participant = player.participant if participant.finished_rounds: return upcoming_apps[0] class InstructionsBaselineNetwork(Page): @staticmethod def vars_for_template(player: Player): #TODO: Revert this. if player.id_in_group == 1: return dict(treatment=0, ) # return dict(treatment=player.session.config['treatment'], # ) elif player.id_in_group == 2: return dict(treatment=1, ) elif player.id_in_group == 3: return dict(treatment=2) page_sequence = [InstructionsBaselineNetwork, RedChooses, Interaction, Results, BlueChooses, ShuffleWaitPage, BlockEnd]