def mutate(self, num_undo_attempts=10):
    backup_nodes = list(self.road.control_nodes)
    attempted_genes = set()
    n = (len(self.road.control_nodes) - 2)
    seglength = 3
    candidate_length = (n - (2 * seglength))
    assert (candidate_length > 0)

    def next_gene_index() -> int:
        if (len(attempted_genes) == candidate_length):
            return (- 1)
        i = None
        condition = False
        while (not condition):
            i = random.randint(seglength, (n - seglength))
            if (i not in attempted_genes):
                condition = True
        assert (i is not None)
        assert (seglength <= i <= (n - seglength))
        attempted_genes.add(i)
        return i
    gene_index = next_gene_index()
    while (gene_index != (- 1)):
        (c, mut_value) = self.mutate_gene(gene_index)
        attempt = 0
        is_valid = self.road.is_valid()
        while ((not is_valid) and (attempt < num_undo_attempts)):
            self.undo_mutation(gene_index, c, mut_value)
            (c, mut_value) = self.mutate_gene(gene_index)
            attempt += 1
            is_valid = self.road.is_valid()
        if is_valid:
            break
        else:
            gene_index = next_gene_index()
    if (gene_index == (- 1)):
        raise ValueError('No gene can be mutated')
    assert self.road.is_valid()
    assert (self.road.control_nodes != backup_nodes)
def mutate(self, num_undo_attempts=10):
    backup_nodes = list(self.road.control_nodes)
    attempted_genes = set()
    n = (len(self.road.control_nodes) - 2)
    seglength = 3
    candidate_length = (n - (2 * seglength))
    assert (candidate_length > 0)

    def next_gene_index() -> int:
        if (len(attempted_genes) == candidate_length):
            return (- 1)
        i = None
        condition = False
        while (not condition):
            i = random.randint(seglength, (n - seglength))
            if (i not in attempted_genes):
                condition = True
        assert (i is not None)
        assert (seglength <= i <= (n - seglength))
        attempted_genes.add(i)
        return i
    gene_index = next_gene_index()
    while (gene_index != (- 1)):
        (c, mut_value) = self.mutate_gene(gene_index)
        attempt = 0
        is_valid = self.road.is_valid()
        while ((not is_valid) and (attempt < num_undo_attempts)):
            self.undo_mutation(gene_index, c, mut_value)
            (c, mut_value) = self.mutate_gene(gene_index)
            attempt += 1
            is_valid = self.road.is_valid()
        if is_valid:
            break
        else:
            gene_index = next_gene_index()
    if (gene_index == (- 1)):
        raise ValueError('No gene can be mutated')
    assert self.road.is_valid()
    assert (self.road.control_nodes != backup_nodes)