|  | @@ -1,3 +1,4 @@
 | 
	
		
			
				|  |  | +import re
 | 
	
		
			
				|  |  |  import time
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import chess
 | 
	
	
		
			
				|  | @@ -21,6 +22,22 @@ class ChessSession:
 | 
	
		
			
				|  |  |          self.ts = time.time()
 | 
	
		
			
				|  |  |          self.move_ts = time.time()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    def parse_move(self, move):
 | 
	
		
			
				|  |  | +        move = move.strip()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            if move.startswith(":"):
 | 
	
		
			
				|  |  | +                move = self.board.parse_san(move[1:])
 | 
	
		
			
				|  |  | +            else:
 | 
	
		
			
				|  |  | +                move = self.board.parse_uci(move)
 | 
	
		
			
				|  |  | +        except chess.InvalidMoveError:
 | 
	
		
			
				|  |  | +            raise IllegalMove(move)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if move != chess.Move.null() and move not in self.board.legal_moves:
 | 
	
		
			
				|  |  | +            raise IllegalMove(move)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return move
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  |      def check_game_over(self):
 | 
	
		
			
				|  |  |          outcome = self.board.outcome(claim_draw=True)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -35,13 +52,7 @@ class ChessSession:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      async def move(self, move=None):
 | 
	
		
			
				|  |  |          if move is not None:
 | 
	
		
			
				|  |  | -            try:
 | 
	
		
			
				|  |  | -                move = chess.Move.from_uci(move)
 | 
	
		
			
				|  |  | -            except chess.InvalidMoveError:
 | 
	
		
			
				|  |  | -                raise IllegalMove(move)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if move not in self.board.legal_moves:
 | 
	
		
			
				|  |  | -                raise IllegalMove(move)
 | 
	
		
			
				|  |  | +            move = self.parse_move(move)
 | 
	
		
			
				|  |  |          else:
 | 
	
		
			
				|  |  |              move = await self.engine.play(self.board, chess.engine.Limit(nodes=1))
 | 
	
		
			
				|  |  |              move = move.move
 | 
	
	
		
			
				|  | @@ -51,7 +62,7 @@ class ChessSession:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          self.check_game_over()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def from_moves(self, moves):
 | 
	
		
			
				|  |  | +    def from_moves(self, moves, san=False):
 | 
	
		
			
				|  |  |          self.board.reset()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          moves = moves.strip().split(" ")
 | 
	
	
		
			
				|  | @@ -59,12 +70,9 @@ class ChessSession:
 | 
	
		
			
				|  |  |              raise IllegalMove
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          for i, move in zip(range(len(moves)), moves):
 | 
	
		
			
				|  |  | -            try:
 | 
	
		
			
				|  |  | -                move = chess.Move.from_uci(move)
 | 
	
		
			
				|  |  | -            except chess.InvalidMoveError:
 | 
	
		
			
				|  |  | -                raise IllegalMove(move)
 | 
	
		
			
				|  |  | +            move = self.parse_move(move)
 | 
	
		
			
				|  |  |   
 | 
	
		
			
				|  |  | -            if move not in self.board.legal_moves and not (move == chess.Move.null() and i % 2 == 0):
 | 
	
		
			
				|  |  | +            if move == chess.Move.null() and i % 2 != 0:
 | 
	
		
			
				|  |  |                  raise IllegalMove(move)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              self.board.push(move)
 |