text: # AUTOGENERATED! DO NOT EDIT! File to edit: 03_play.ipynb (unless otherwise specified).
  
  __all__ = ['Valuator', 'ClassicValuator', 'MAXVAL', 'explore_leaves', 'computer_move', 'move', 'computer_minimax']
  
  # Cell
  from .train import Net
  import torch
  
  
  class Valuator(object):
      """Valuates a given board state using a trained neural network"""
      def __init__(self):
          self.model = Net()
          self.param = torch.load("nets/value.pth", map_location=lambda storage, loc: storage)
          self.model.load_state_dict(self.param)
  
      def __call__(self, s):
          brd = s.serialize()[None]
          output = self.model(torch.tensor(brd).float())
          return float(output.data)
  
  # Cell
  import chess
  
  MAXVAL = 10_000
  class ClassicValuator(object):
      """A simple chess value function based on pieces"""
  
      def __init__(self):
           self.values = {chess.PAWN: 1,
                          chess.KNIGHT: 3,
                          chess.BISHOP: 3,
                          chess.ROOK: 5,
                          chess.QUEEN: 9,
                          chess.KING: 0}
  
      def __call__(self, s):
          # checks for variants for wins and losses
          if s.board.is_variant_win():
              return MAXVAL
          else:
              return -MAXVAL
          if s.board.is_variant_loss():
              return -MAXVAL
          else:
              return MAXVAL
  
          # calculate total value on the chess board
          tot_val = 0
          pm = s.board.piece_map()
          for x in pm:
              val = self.values[pm[x].piece_type]
              if pm[x].color == chess.WHITE:
                  tot_val += val
              else:
                  tot_val -= val
          return float(tot_val)
  
  # Cell
  def explore_leaves(s, v):
      ret = []
      # explore all possible moves and evaluates them from given position
      for mv in s.edges():
          s.board.push(mv)
          ret.append((computer_minimax(s, v), mv))
          s.board.pop()
      return ret
  
  def computer_move():
      moves = sorted(explore_leaves(s, v), key=lambda x: x[0], reverse=s.board.turn)
      print("Computer moves:", moves[0])
      s.board.push(moves[0][1])
  
  def move():
      if not s.board.is_game_over():
          human_move = input("Next move: ")
      if chess.Move.from_uci(human_move) in s.board.legal_moves:
          print("Human moves:", human_move)
          s.board.push_san(human_move)
          computer_move()
      else:
          print("Illegal Move, try again.")
  
  def computer_minimax(state, value, depth=5):
      if depth == 0 or s.board.is_game_over():
          return v(s)
      # white is maximizing player
      turn = s.board.turn
      if turn == chess.WHITE:
          ret = -MAXVAL
      else:
          ret = MAXVAL
  
      # go over moves and evalutate recursive
      for mv in s.edges():
          s.board.push(mv)
          val = computer_minimax(s, v, depth-1)
          if turn == chess.WHITE:
              ret = max(ret, val)
          else:
              ret = min(ret, val)
          # remove latest push
          s.board.pop()
          return ret
  
  