from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) from random import shuffle from numpy.random import choice from itertools import chain author = '슬아' doc = """ 사슴사냥 3인용 연습 """ class Constants(BaseConstants): name_in_url = 'deer_hunting3' players_per_group = 3 num_rounds = 15 class Subsession(BaseSubsession): def matrix_suffle(self, matrix): matrix = list(chain.from_iterable(matrix)) #flatten the list shuffle(matrix) new_matrix = [matrix[i:i+3] for i in range(int(len(matrix)/3))] #nested list again return new_matrix def creating_session(self): players = self.get_players() if self.round_number ==1: #최초 아이템 분배 for p in players: if p.id_in_group == 1: p.endowment = "활 1개" p.item = "활 1개" else: p.endowment = "화살 1개" p.item = "화살 1개" p.payoff = c(600) def creating_new_rounds(self): groups = self.get_groups() fixed_groups = [] if self.round_number >1: #pages.py에서 다시 call for g in groups: if g.in_round(self.round_number-1).is_finished == 0: #거래 안 끝난 그룹 -> no update fixed_groups.append(g.get_players()) groups.remove(g) players = g.get_players() for p in players: #거래 끝낸 플레이어 다음거래에 참가X if p.in_round(self.round_number-1).is_playing ==0: p.is_playing =0 matrix = [g.get_players() for g in groups] #끝난 그룹 -> 다시 그룹핑, 아이템 분배 matrix = self.matrix_suffle(matrix) matrix.extend(fixed_groups) #combine the two groups of groups to set group matrix self.set_group_matrix(matrix) groups = self.get_groups() for g in groups: g.renew_endowment() class Group(BaseGroup): two_players_remain = models.IntegerField(initial=0) deer_remain = models.IntegerField(initial=1) is_finished = models.IntegerField(initial=0) def set_proposer(self): #제안자 뽑고, 타겟 플레이어 변수에도 1 줌 players = self.get_players() #if 3 players remain if self.two_players_remain==0: selected = choice(players, 1, p=[1/3, 1/3, 1/3])[0] selected.is_proposer = 1 if selected.choose_target == "그룹멤버A": selected.get_playerA().is_target =1 elif selected.choose_target == "그룹멤버B": selected.get_playerB().is_target =1 #if 2 players remain (한 사람이 활1개 다른 한 사람이 화살2개 가지고 있는 경우밖에 없음) else: #players 가져옴 player_w_1bow = [p for p in players if p.item =="활 1개"] player_w_2arrows = [p for p in players if p.item =="화살 2개"] player_w_1bow.extend(player_w_2arrows) remaining_players = player_w_1bow selected = choice(remaining_players, 1, p=[1/3, 2/3])[0] selected.is_proposer = 1 target = [p for p in selected.get_others_in_group() if p.is_playing==1][0] #creating session할 때 0을 안 받은 플레이어 데려옴 target.is_target = 1 #타겟을 제안자가 아닌 멤버로 자동으로 설정 selected.choose_target = ["그룹멤버A" if selected.get_playerA().is_target ==1 else "그룹멤버B"][0] for p in players: p.proposer_name() #페이지에서 보여주려고 이름 설정함 def item_update(self): self.session.vars = {"활 1개": 10, "화살 1개": 1, "화살 2개": 2, "활 1개와 화살 1개": 11, "활 1개와 화살 2개": 12, #"None": 0 } p = self.get_player_by_id(1) proposer = p.get_proposer() target = p.get_target() if target.accept ==1: item_code = self.session.vars[proposer.item]+self.session.vars[target.item] #제안자 아이템 코드 for k, v in self.session.vars.items(): if item_code == v: proposer.item = k target.item = "None" target.is_playing = 0 if item_code >10: #사냥준비 됨 self.is_finished =1 elif item_code == 2: #화살 2개 됨 self.two_players_remain =1 def deer_random(self): self.deer_remain = choice([0, 1], 1, p=[0.05, 0.95])[0] if self.deer_remain ==0: self.is_finished =1 def set_payoffs(self): p = self.get_player_by_id(1) proposer = p.get_proposer() target = p.get_target() nontarget = p.get_nontarget() if self.round_number ==1: if target.accept == 1: proposer.payoff = c(600) - c(proposer.offer_amount) + c(600) target.payoff = c(600) + c(proposer.offer_amount) nontarget.payoff = c(600) elif target.accept == 0: for p in self.get_players(): p.payoff = c(600) else: if self.in_round(self.round_number-1).is_finished ==1: if target.accept ==1: proposer.payoff = c(600) - c(proposer.offer_amount) + c(600) target.payoff = c(600) + c(proposer.offer_amount) nontarget.payoff = c(600) elif target.accept ==0: for p in self.get_players(): p.payoff = c(600) else: if target.accept ==1: proposer.payoff = proposer.in_round(self.round_number-1).payoff -c(proposer.offer_amount) + c(600) target.payoff = target.in_round(self.round_number-1).payoff + c(proposer.offer_amount) nontarget.payoff = nontarget.in_round(self.round_number-1).payoff elif target.accept ==0: for p in self.get_players(): p.payoff = p.in_round(self.round_number-1).payoff def renew_endowment(self): #round숫자도 여기서 업데이트 p1 = self.get_player_by_id(1) p2 = self.get_player_by_id(2) p3 = self.get_player_by_id(3) if self.in_round(self.round_number-1).is_finished ==1: p1.endowment = "활 1개" p1.item = "활 1개" p2.endowment = "화살 1개" p2.item = "화살 1개" p3.endowment = "화살 1개" p3.item = "화살 1개" p1.round_played = p1.in_round(self.round_number - 1).round_played + 1 p2.round_played = p1.in_round(self.round_number - 1).round_played + 1 p3.round_played = p1.in_round(self.round_number - 1).round_played + 1 else: if self.in_round(self.round_number-1).two_players_remain ==1: self.two_players_remain =1 for p in self.get_players(): p.endowment = p.in_round(self.round_number-1).item p.item = p.in_round(self.round_number-1).item p.round_played = p.in_round(self.round_number - 1).round_played for p in self.get_players(): if p.round_played >3: p.is_playing =0 class Player(BasePlayer): # 아이템 상태 경우의 수 # 1bow 1arrow 1arrow=>거래 # 1bow 2arrow none=>거래 # 1bow1arrow 1arrow none=>winner # 1bow2arrows none none=>winner round_played = models.IntegerField(initial=1) endowment = models.StringField() item = models.StringField() offer_amount = models.IntegerField(min=c(0), max=c(600)) choose_target = models.StringField(choices=["그룹멤버A", "그룹멤버B"], widget=widgets.RadioSelect, ) is_proposer = models.IntegerField(initial=0) is_target = models.IntegerField(initial=None) accept = models.IntegerField(initial=None) proposer = models.StringField() #제안자 아닌 사람 입장에서 제안자 누구인지(page에서 보여주기 위함) tar_name = models.StringField() #타겟 아닐때 타겟 누군지(page에서 보여주기 위함) is_playing = models.IntegerField(initial=1) ############################# getting other players def get_playerA(self): return self.get_others_in_group()[0] def get_playerB(self): return self.get_others_in_group()[1] def get_proposer(self): if self.is_proposer ==1: return self else: if self.get_playerA().is_proposer ==1: return self.get_playerA() elif self.get_playerB().is_proposer ==1: return self.get_playerB() def get_target(self): proposer = self.get_proposer() if proposer.choose_target =="그룹멤버A": return proposer.get_playerA() elif proposer.choose_target =="그룹멤버B": return proposer.get_playerB() def get_nontarget(self): proposer = self.get_proposer() if proposer.choose_target =="그룹멤버A": return proposer.get_playerB() elif proposer.choose_target =="그룹멤버B": return proposer.get_playerA() #################################################### def proposer_name(self): if self.is_proposer == 0: if self.get_playerA().is_proposer == 1: self.proposer = "그룹멤버A" if not self.is_target ==1: self.tar_name = "그룹멤버B" elif self.get_playerB().is_proposer == 1: self.proposer = "그룹멤버B" if not self.is_target == 1: self.tar_name = "그룹멤버A"