2016-12-22 8 views
0

私はチックタックのつま先を再生することを学ぶ小さなpythonスクリプトを構築中です。私のプロセスは、ゲーム内で行われた各移動を保存し、それが勝利結果につながるかどうかに基づいてその移動を記録することです。最終的に私は多くのラウンドでこれを訓練しようとします。辞書のすべてのキー値のペアを変更するPythonメソッド

私の問題は、update_weights()の方法にあります。私はそれが格納された移動(ボードオブジェクトからアクセスされ、リスト[行、col]として表される)を取って、その移動リストを反復することを期待します。この方法は、ボードの記憶された重み((3,3)個の配列の辞書)を参照し、適切な移動のための対応する重みを更新するべきである。

勝利が発生したとします。勝利シーケンスでは、#2の移動がボード位置[0,1]にありました。メソッドは重みの辞書にアクセスし(キーは移動番号です)、配列[0,1]の位置に1.05の係数を掛けます。

問題は、私の方法が正しい移動#キーに関連付けられているだけでなく、体重辞書のすべての配列を変更しているということです。私はこれがどう起こっているのか理解できません。

import numpy as np 
import random 

    class ttt_board(): 

     def __init__(self): 
      self.board_state = np.array([[0,0,0],[0,0,0],[0,0,0]]) 
      self.board_weight = self.reset_board_weights() 
      self.moves = [] 

     def reset_board_weights(self): 
      board_weight_instance = np.zeros((3,3)) 
      board_weight_instance[board_weight_instance >= 0] = 0.5 

      board_weight = {0: board_weight_instance, 
          1: board_weight_instance, 
          2: board_weight_instance, 
          3: board_weight_instance, 
          4: board_weight_instance} 

      return board_weight 

     def reset_board(self): 
      self.board_state = np.array([[0,0,0],[0,0,0],[0,0,0]]) 

     def reset_moves(self): 
      self.moves = [] 

     def is_win(self): 
      board = self.board_state 
      if board.trace() == 3 or np.flipud(board).trace() == 3: 
       return True 
      for i in range(3): 
       if board.sum(axis=0)[i] == 3 or board.sum(axis=1)[i] == 3: 
        return True 
      else: 
       return False 

     def is_loss(self): 
      board = self.board_state 
      if board.trace() == 12 or np.flipud(board).trace() == 12: 
       return True 
      for i in range(3): 
       if board.sum(axis=0)[i] == 12 or board.sum(axis=1)[i] == 12: 
        return True 
      else: 
       return False 

     def is_tie(self): 
      board = self.board_state 
      board_full = True 
      for i in range(len(board)): 
       for k in range(len(board)): 
        if board[i][k] == 0: 
         board_full = False 
      if board_full and not self.is_win() and not self.is_loss(): 
       return True 
      else: 
       return False 

     def update_board(self,player,space): 
      #takes player as 1 or 4 
      #takes space as list [0,0] 
      self.board_state[space[0],space[1]] = player 

      if player == 1: 
       self.store_move(space) 
      return 

     def get_avail_spots(self): 
      avail_spots = [] 
      board = self.board_state 
      for i in range(len(board)): 
       for k in range(len(board)): 
        if board[i][k] == 0: 
         avail_spots.append([i,k]) 
      return avail_spots 

     def gen_next_move(self): 
      avail_spots = self.get_avail_spots() 
      move = random.randrange(len(avail_spots)) 
      return avail_spots[move] 

     def update_weights(self,win): 
      moves = self.moves 
      if win: 
       factor = 1.05 
      else: 
       factor= 0.95 
      for i in range(len(moves)): 
       row = moves[i][0] 
       col = moves[i][1] 
       old_weight = self.board_weight[i][row,col] 
       new_weight = old_weight*factor 
       self.board_weight[i][row,col] = new_weight 
      return 

     def store_move(self,move): 
      self.moves.append(move) 
      return 


    if __name__ == '__main__': 

     board = ttt_board() 

     while not board.is_win() and not board.is_loss() and not board.is_tie(): 
      try: 
       board.update_board(1,board.gen_next_move()) 
       board.update_board(4,board.gen_next_move()) 
      except ValueError: 
       break 

     if board.is_win(): 
      board.update_weights(1) 
      print('Player 1 wins: {w}'.format(w=board.is_win())) 
     elif board.is_loss(): 
      board.update_weights(0) 
      print('Player 2 wins: {l}'.format(l=board.is_loss())) 
     elif board.is_tie(): 
      print('Game ends in tie: {t}'.format(t=board.is_tie())) 

     print('Here is the final board') 
     print(board.board_state) 
     print(board.board_weight) 
     print(board.moves) 

スクリプトを実行することによって見ることができるように、単一のゲームの後に重みの印刷された辞書は、各キーの同じ配列の値を持っています。 それぞれの配列は、それが関連付けられているキーに対応する移動#だけにアクセスする必要があるため、1つの位置でのみ変更されると思います。

+2

それは、一般的に – martianwars

+0

が本当に関連していないhttp://stackoverflow.com/help/mcveが、このような使用して 'numpy'アレイはおそらく起こっているので、多くのコードを読み取ることは難しいです単純なPythonリストよりもパフォーマンスが悪くなります。 –

+1

@martianwarsは頭をアップしてくれてありがとう。コードを少なくして、問題を切り分けて更新します。 – regularGuy

答えて

2

問題は、私はヘルパーメソッドを使用して、各要素の新しい参照を作成、辞書理解でこれを行うだろうあなたは辞書

board_weight_instance = np.zeros((3,3)) 
board_weight_instance[board_weight_instance >= 0] = 0.5 

board_weight = {0: board_weight_instance, 
       1: board_weight_instance, 
       2: board_weight_instance, 
       3: board_weight_instance, 
       4: board_weight_instance} 

であなたのboard_weight_instanceアレイ上の同じ参照を共有することである。

ノーハッシュ、より高速な処理:

あなたのケースで
@staticmethod 
def create_element(): 
    board_weight_instance = np.zeros((3,3)) 
    board_weight_instance[:] = 0.5 # simpler than your method 
    return board_weight_instance 

board_weight = {i:self.create_element() for i in range(0,5)} 

は、でも辞書を使用してなぜあなたはlistを使用することができるとき

board_weight = [self.create_element() for _ in range(0,5)] 

あなたはそれを同じ方法でアクセスすることができ

関連する問題