'Play stone at action=(x,y). If color is not specified, current_player is used
If it is a legal move, current_player switches to the opposite color
If not, an IllegalMove exception is raised'

def do_move(self, action, color=None):

    color = (color or self.current_player)
    reset_player = self.current_player
    self.current_player = color
    if self.is_legal(action):
        self.ko = None
        self.stone_ages[(self.stone_ages >= 0)] += 1
        if (action is not PASS_MOVE):
            (x, y) = action
            self.board[x][y] = color
            self._update_hash(action, color)
            self._update_neighbors(action)
            self.stone_ages[x][y] = 0
            for (nx, ny) in self._neighbors(action):
                if ((self.board[(nx, ny)] == (- color)) and (len(self.liberty_sets[nx][ny]) == 0)):
                    captured_group = self.group_sets[nx][ny]
                    num_captured = len(captured_group)
                    self._remove_group(captured_group)
                    if (color == BLACK):
                        self.num_white_prisoners += num_captured
                    else:
                        self.num_black_prisoners += num_captured
                    if (num_captured == 1):
                        would_recapture = (len(self.liberty_sets[x][y]) == 1)
                        recapture_size_is_1 = (len(self.group_sets[x][y]) == 1)
                        if (would_recapture and recapture_size_is_1):
                            self.ko = (nx, ny)
            self.previous_hashes.add(self.current_hash)
        else:
            if (color == BLACK):
                self.passes_black += 1
            if (color == WHITE):
                self.passes_white += 1
        self.current_player = (- color)
        self.history.append(action)
        self.__legal_move_cache = None
    else:
        self.current_player = reset_player
        raise IllegalMove(str(action))
    if (len(self.history) > 1):
        if ((self.history[(-1)] is PASS_MOVE) and (self.history[(-2)] is PASS_MOVE) and (self.current_player == WHITE)):
            self.is_end_of_game = True
    return self.is_end_of_game
