from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import random author = '' doc = """ Word Encryption with Double Randomization """ class Constants(BaseConstants): name_in_url = 'word_encryption_v5' players_per_group = None num_rounds = 500 # じゅうぶん大きければ任意 letter = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] # 全体の制限時間(分) t = 20 # これについては、pages.pyの30行目あたりを参照 pre_time = 0 # ここでゲームするかしないか画面に移動するのに必要な経過時間を設定 # 〇×ゲーム終了時点もしくはゲームしないと選択時点 task_interval = 100 WINNING = [ {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6}, {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6} ] SYMBOLS = ('x', 'o') EMPTY = '.' class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # game_num保存用 game_num = models.IntegerField(initial=0) # 〇×ゲームでさぼった時間(多分単位は秒) wasted_time = models.FloatField() # トータルの〇×ゲームの total_wasted_time = models.FloatField(initial=0) # タスクをこなしている時間 task_time = models.FloatField() # トータルのタスクタイム total_task_time = models.FloatField(initial=0) # 回答欄(被験者が入力) ans1 = models.IntegerField(max=999, blank=True) ans2 = models.IntegerField(max=999, blank=True) ans3 = models.IntegerField(max=999, blank=True) # 正解 corr_ans1 = models.IntegerField(max=999) corr_ans2 = models.IntegerField(max=999) corr_ans3 = models.IntegerField(max=999) # 合計利得 total_payoff = models.CurrencyField() # 利得計算用関数 def score_calc(self): # ラウンドの利得を計算 if self.corr_ans1 == self.ans1: self.payoff += 1 if self.corr_ans2 == self.ans2: self.payoff += 1 if self.corr_ans3 == self.ans3: self.payoff += 1 # ラウンドの利得を合計利得に足し算 self.total_payoff = sum( [self.in_round(i).payoff for i in range(1, self.round_number+1)] ) # この部分は以下と同義 # lst = [] # for i in range(1, self.round_number + 1): # lst.append(self.in_round(i).payoff) # self.total_payoff = sum(lst) ''' ここから下は〇×ゲーム関係 ''' # ゲームをするかしないか聞く will_play = models.StringField( label='', choices = [ ['する','する'], ['しない','しない'] ], widget = widgets.RadioSelectHorizontal, initial='しない' ) # ゲームに必要な変数定義 ai_plays = models.StringField(initial='o') ai_class = models.StringField(initial='dumb') move_count = models.IntegerField(initial=0) board = models.StringField(initial='.........') turn = models.StringField(initial='x') winner = models.StringField() symbol = models.StringField(initial='x') win = models.BooleanField() # この関数でJavaScriptの関数からのデータを受け取る def handle_message(self, message): kind = message['type'] print("jsから来たデータ") print(message) print("player_ID") print(self.id_in_group) # それぞれの状況に応じて処理を場合分け if kind == 'move': print("move") return self.handle_move(message['place']) elif kind == 'ai': print("ai") return self.handle_aimove() elif kind == 'start': print("start") return self.handle_start() else: raise ValueError("Invalid message", kind) # JavaScriptに返す用のメッセージを作成 def reply(self, message): print("message") print(message) return {self.id_in_group: message} # メッセージいろいろ def game_message(self): return dict(type='game', board=self.board, turn=self.turn) def gameover_message(self, winner, pattern): msg = self.game_message() msg.update(type='gameover', winner=winner, pattern=pattern) return msg def error_message(self, error): return dict(type='error', error=error) # ゲームを始めたときに最初に走る処理 def handle_start(self): return self.reply(self.game_message()) # プレイヤーの動きについての処理 def handle_move(self, place): try: completed, winner, pattern = self.play(place) if completed: return self.reply(self.gameover_message(winner, pattern)) else: return self.reply(self.game_message()) except GameError as e: print("error補足(プレイヤー)") return self.reply(self.error_message(str(e))) # 敵の動きについての処理 def handle_aimove(self): try: completed, winner, pattern = self.play_ai() if completed: return self.reply(self.gameover_message(winner, pattern)) else: return self.reply(self.game_message()) except GameError as e: print("error補足(敵)") return self.reply(self.error_message(str(e))) # 具体的な敵の動きの処理 def play_ai(self): if self.ai_plays != self.turn: raise GameError("Wrong turn") move = random.choice(self.moves()) self.move(move) completed, winner, pattern = self.completed() if completed: self.winner = winner self.gameover(winner) self.move_count += 1 return completed, winner, pattern # 具体的なプレイヤーの動きの処理 def play(self, move): if self.symbol != self.turn: raise GameError("Wrong turn") self.move(move) completed, winner, pattern = self.completed() if completed: self.winner = winner self.gameover(winner) self.move_count += 1 return completed, winner, pattern def gameover(self, winner): if winner is None: self.win = None else: self.win = winner == self.symbol # 以下ゲームのロジック def opponent(self, sym): """Return opponent symbol for given one""" return Constants.SYMBOLS[(Constants.SYMBOLS.index(sym) + 1) % 2] def places(self, sym): """Return indexes of cells containing given sym""" return tuple(i for i in range(len(self.board)) if self.board[i] == sym) def moves(self): """Returns possible moves""" return self.places(Constants.EMPTY) def move(self, place): """Makes a move and changes state""" if self.board[place] != Constants.EMPTY: raise GameError("Wrong move") self.board = self.board[:place] + self.turn + self.board[place+1:] self.turn = self.opponent(self.turn) def completed(self): """Checks if the game is completed and who is the winner Returns: bool, winner symbol, winning pattern """ def win(pos): return list(filter(lambda win: pos >= win, Constants.WINNING)) p1_win = win(set(self.places(Constants.SYMBOLS[0]))) p2_win = win(set(self.places(Constants.SYMBOLS[1]))) if p1_win: return True, Constants.SYMBOLS[0], [list(p) for p in p1_win] if p2_win: return True, Constants.SYMBOLS[1], [list(p) for p in p2_win] if len(self.places(Constants.EMPTY)) == 0: return True, None, None else: return False, None, None # 例外キャッチ用 class GameError(Exception): pass