Example #1
0
def generate_slitherlink(height, width, symmetry=False, verbose=False):
    def no_neighboring_zero(problem):
        for y in range(height):
            for x in range(width):
                if problem[y][x] == 0:
                    for dy in range(-1, 2):
                        for dx in range(-1, 2):
                            y2 = y + dy
                            x2 = x + dx
                            if (dy, dx) != (
                                    0, 0
                            ) and 0 <= y2 < height and 0 <= x2 < width and problem[
                                    y2][x2] == 0:
                                return False
        return True

    generated = generate_problem(
        lambda problem: solve_slitherlink(height, width, problem),
        builder_pattern=ArrayBuilder2D(height,
                                       width,
                                       range(-1, 4),
                                       default=-1,
                                       symmetry=symmetry,
                                       disallow_adjacent=True),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=5),
        pretest=no_neighboring_zero,
        verbose=verbose)
    return generated
Example #2
0
def generate_simplegako(height, width, verbose=True, disallow_adjacent=False, symmetry=False, hard=False):
    pattern = range(max(height, width) + 1) if hard else range(height + width - 1)

    def pretest(problem):
        if not hard:
            return True

        for y in range(height):
            for x in range(width):
                if problem[y][x] > 0:
                    for i in range(1, width - x):
                        if problem[y][x+i] == problem[y][x]:
                            return False
                    for i in range(1, height - y):
                        if problem[y+i][x] == problem[y][x]:
                            return False

        mean = (height + width) // 2
        count_big = 0
        for y in range(height):
            for x in range(width):
                if problem[y][x] > 2:
                    count_big += 1
        return (count_big < mean)

    generated = generate_problem(lambda problem: solve_simplegako(height, width, problem),
                                builder_pattern=ArrayBuilder2D(height, width, pattern, default=0,
                                disallow_adjacent=disallow_adjacent, symmetry=symmetry),
                                clue_penalty=lambda problem: count_non_default_values(problem, default=0, weight=5),
                                pretest=pretest, verbose=verbose)
    return generated
Example #3
0
def generate_yinyang(height,
                     width,
                     disallow_adjacent=False,
                     no_clue_on_circumference=False,
                     verbose=False):
    def pretest(problem):
        for y in range(height):
            if problem[y][0] != 0 or problem[y][-1] != 0:
                return False
        for x in range(width):
            if problem[0][x] != 0 or problem[-1][x] != 0:
                return False
        return True

    generated = generate_problem(
        lambda problem: solve_yinyang(height, width, problem),
        builder_pattern=ArrayBuilder2D(height,
                                       width,
                                       range(0, 3),
                                       default=0,
                                       disallow_adjacent=disallow_adjacent),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=5),
        pretest=pretest if no_clue_on_circumference else None,
        verbose=verbose)
    return generated
Example #4
0
def generate_creek(height, width, no_easy=False, verbose=False):
    pattern = []
    for y in range(height + 1):
        row = []
        for x in range(width + 1):
            nmax = (1 if y in (0, height) else 2) * (1 if x in (0,
                                                                width) else 2)
            row.append(
                Choice([-1] + list(
                    range(1 if no_easy else 0, nmax if no_easy else nmax + 1)),
                       default=-1))
        pattern.append(row)

    def pretest(problem):
        if not no_easy:
            return True
        for y in range(height + 1):
            for x in range(width + 1):
                if y < height and (problem[y][x],
                                   problem[y + 1][x]) in ((1, 3), (3, 1)):
                    return False
                if x < width and (problem[y][x],
                                  problem[y][x + 1]) in ((1, 3), (3, 1)):
                    return False
        return True

    generated = generate_problem(
        lambda problem: solve_creek(height, width, problem),
        builder_pattern=pattern,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=3),
        pretest=pretest,
        verbose=verbose)
    return generated
Example #5
0
def generate_shakashaka(height, width, verbose=False):
    generated = generate_problem(lambda problem: solve_shakashaka(height, width, problem),
                                 builder_pattern=ArrayBuilder2D(height, width, [None, -1, 0, 1, 2, 3, 4],
                                                                default=None, disallow_adjacent=True),
                                 clue_penalty=lambda problem: count_non_default_values(problem, default=None, weight=6),
                                 verbose=verbose)
    return generated
Example #6
0
def generate_simpleloop(height, width, verbose):
    pivot = (random.randint(0, height - 1), random.randint(0, width - 1))

    def pretest(problem):
        parity = [0, 0]
        for y in range(height):
            for x in range(width):
                if problem[y][x] == 1:
                    continue
                a = (y + x) % 2 * 2 - 1
                if (y, x) != pivot:
                    parity[0] += a
                parity[1] += a
        return parity[0] == 0 or parity[1] == 0

    generated = generate_problem(
        lambda problem: solve_simpleloop(height, width, problem, pivot),
        builder_pattern=ArrayBuilder2D(height,
                                       width, [0, 1],
                                       default=0,
                                       disallow_adjacent=True),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=10),
        pretest=pretest,
        verbose=verbose)
    if generated is None:
        return None
    num_pass = 0
    for y in range(height):
        for x in range(width):
            if (y, x) != pivot and generated[y][x] == 0:
                num_pass += 1
    y, x = pivot
    generated[y][x] = 1 - num_pass % 2
    return generated
Example #7
0
def generate_yajilin(height,
                     width,
                     no_zero=False,
                     no_max_clue=False,
                     verbose=False):
    choices = []
    for y in range(height):
        row = []
        for x in range(width):
            c = ['..']
            for i in range(1 if no_zero else 0,
                           (y + 3) // 2 - (1 if no_max_clue else 0)):
                c.append('^{}'.format(i))
            for i in range(1 if no_zero else 0,
                           (x + 3) // 2 - (1 if no_max_clue else 0)):
                c.append('<{}'.format(i))
            for i in range(1 if no_zero else 0,
                           (height - y + 2) // 2 - (1 if no_max_clue else 0)):
                c.append('v{}'.format(i))
            for i in range(1 if no_zero else 0,
                           (width - x + 2) // 2 - (1 if no_max_clue else 0)):
                c.append('>{}'.format(i))
            row.append(Choice(c, '..'))
        choices.append(row)
    generated = generate_problem(
        lambda problem: solve_yajilin(height, width, problem),
        builder_pattern=choices,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default='..', weight=20),
        verbose=verbose)
    return generated
Example #8
0
def generate_doppelblock(n, verbose=False):
    max_sum = (n - 2) * (n - 1) // 2
    generated = generate_problem(lambda problem: solve_doppelblock(n, problem[0], problem[1]),
                                 builder_pattern=ArrayBuilder2D(2, n, [-1] + list(range(0, max_sum + 1)), default=-1),
                                 clue_penalty=lambda problem: count_non_default_values(problem, default=-1, weight=10),
                                 verbose=verbose)
    return generated
Example #9
0
def generate_nurikabe(height,
                      width,
                      min_clue=None,
                      max_clue=10,
                      verbose=False):
    disallow_adjacent = []
    for dy in range(-2, 3):
        for dx in range(-2, 3):
            if (dy, dx) != (0, 0):
                disallow_adjacent.append((dy, dx))
    generated = generate_problem(
        lambda problem: solve_nurikabe(
            height, width, problem, unknown_low=min_clue),
        builder_pattern=ArrayBuilder2D(height,
                                       width, [-1, 0] +
                                       list(range(min_clue or 1, max_clue)),
                                       default=0,
                                       disallow_adjacent=True,
                                       symmetry=False),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=5),
        verbose=verbose)
    if generated is None:
        return None
    else:
        return resolve_unknown(height, width, generated, unknown_low=min_clue)
Example #10
0
def generate_fillomino(height, width, verbose=False):
    generated = generate_problem(
        lambda problem: solve_nurimisaki(height, width, problem),
        builder_pattern=ArrayBuilder2D(height, width, [-1, 0], default=-1),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=7),
        verbose=verbose)
    return generated
Example #11
0
def generate_masyu(height, width, symmetry=False, verbose=False):
    generated = generate_problem(
        lambda problem: solve_masyu(height, width, problem),
        builder_pattern=ArrayBuilder2D(height,
                                       width, [0, 1, 2],
                                       default=0,
                                       symmetry=symmetry),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=10),
        verbose=verbose)
    return generated
Example #12
0
def generate_gokigen(height,
                     width,
                     no_easy=False,
                     no_adjacent=False,
                     verbose=False):
    pattern = []
    for y in range(height + 1):
        row = []
        for x in range(width + 1):
            lim = (1 if y in (0, height) else 2) * (1 if x in (0,
                                                               width) else 2)
            row.append(
                Choice([-1] + list(
                    range(1 if no_easy else 0, lim if no_easy else (lim + 1))),
                       default=-1))
        pattern.append(row)

    def pretest(problem):
        for y in range(height + 1):
            for x in range(width + 1):
                if no_adjacent:
                    if y < height:
                        if problem[y][x] != -1 and problem[y + 1][x] != -1:
                            return False
                    if x < width:
                        if problem[y][x] != -1 and problem[y][x + 1] != -1:
                            return False
                if no_easy:
                    if y < height:
                        if problem[y][x] in (1, 3) and problem[y +
                                                               1][x] in (1, 3):
                            return False
                    if x < width:
                        if problem[y][x] in (1, 3) and problem[y][x +
                                                                  1] in (1, 3):
                            return False
                    if y < height - 1:
                        if problem[y][x] != -1 and problem[
                                y + 1][x] != -1 and problem[y + 2][x] != -1:
                            return False
                    if x < width - 1:
                        if problem[y][x] != -1 and problem[y][
                                x + 1] != -1 and problem[y][x + 2] != -1:
                            return False
        return True

    generated = generate_problem(
        lambda problem: solve_gokigen(height, width, problem),
        builder_pattern=pattern,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=2),
        pretest=pretest,
        verbose=verbose)
    return generated
Example #13
0
def generate_firefly(height, width, min_clue=0, max_clue=5, verbose=False):
    cand = ['..']
    for d in ['^', 'v', '<', '>']:
        cand.append(d + '?')
        for i in range(min_clue, max_clue + 1):
            cand.append(d + str(i))
    generated = generate_problem(
        lambda problem: solve_firefly(height, width, problem),
        builder_pattern=ArrayBuilder2D(height, width, cand, default='..'),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default='..', weight=10),
        verbose=verbose)
    return generated
Example #14
0
def generate_building(size, verbose=False):
    initial, neighbor = build_neighbor_generator(
        [[Choice(range(0, size + 1), default=0) for _ in range(size)]
         for _ in range(4)])
    generated = generate_problem(
        lambda problem: solve_building(size, *problem),
        initial,
        neighbor,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=3.0),
        verbose=verbose)
    if generated is not None:
        return generated
Example #15
0
def generate_fillomino(height,
                       width,
                       checkered=False,
                       disallow_adjacent=False,
                       symmetry=False,
                       verbose=False):
    generated = generate_problem(
        lambda problem: solve_fillomino(
            height, width, problem, checkered=checkered),
        builder_pattern=ArrayBuilder2D(height,
                                       width,
                                       range(0, 9),
                                       default=0,
                                       disallow_adjacent=disallow_adjacent,
                                       symmetry=symmetry),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=5),
        verbose=verbose)
    return generated
Example #16
0
def generate_sudoku(n, max_clue=None, symmetry=False, verbose=False):
    size = n * n

    def pretest(problem):
        if max_clue is None:
            return True
        else:
            return count_non_default_values(problem, default=0,
                                            weight=1) <= max_clue

    generated = generate_problem(
        lambda problem: solve_sudoku(problem, n=n),
        builder_pattern=ArrayBuilder2D(size,
                                       size,
                                       range(0, size + 1),
                                       default=0,
                                       symmetry=symmetry),
        pretest=pretest,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=0, weight=5),
        verbose=verbose)
    return generated
Example #17
0
def generate_koutano(height, width, hard=False, symmetry=False, verbose=False):
    pattern = list(range(1, height + width - 3))
    if not hard:
        pattern += [0, height + width - 2]

    def pretest(problem):
        if not hard:
            return True

        for y in range(height):
            count_hint = 0
            for x in range(width):
                count_hint += 1 if problem[y][x] > -1 else 0
            if count_hint > 2:
                return False
        for x in range(width):
            count_hint = 0
            for y in range(height):
                count_hint += 1 if problem[y][x] > -1 else 0
            if count_hint > 2:
                return False
        return True

    generated = generate_problem(
        lambda problem: solve_koutano(height, width, problem),
        builder_pattern=ArrayBuilder2D(height,
                                       width,
                                       pattern,
                                       default=-1,
                                       symmetry=symmetry,
                                       disallow_adjacent=hard),
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=2),
        pretest=pretest,
        verbose=verbose)
    return generated
Example #18
0
def generate_akari(height, width, no_easy=False, verbose=False):
    def pretest(problem):
        visited = [[False for _ in range(width)] for _ in range(height)]

        def visit(y, x):
            if not (0 <= y < height and 0 <= x < width and problem[y][x] == -2 and not visited[y][x]):
                return
            visited[y][x] = True
            visit(y - 1, x)
            visit(y + 1, x)
            visit(y, x - 1)
            visit(y, x + 1)
        n_component = 0
        for y in range(height):
            for x in range(width):
                if problem[y][x] == -2 and not visited[y][x]:
                    n_component += 1
                    visit(y, x)
        if n_component != 1:
            return False
        if not no_easy:
            return True
        for y in range(height):
            for x in range(width):
                if problem[y][x] >= 0:
                    n_adj = (1 if y > 0 and problem[y - 1][x] == -2 else 0) + (1 if x > 0 and problem[y][x - 1] == -2 else 0) + (1 if y < height - 1 and problem[y + 1][x] == -2 else 0) + (1 if x < width - 1 and problem[y][x + 1] == -2 else 0)
                    if problem[y][x] >= n_adj - 1:
                        return False
        return True

    pattern = [-2, -1, 1, 2] if no_easy else [-2, -1, 0, 1, 2, 3, 4]
    generated = generate_problem(lambda problem: solve_akari(height, width, problem),
                                 builder_pattern=ArrayBuilder2D(height, width, pattern, default=-2, symmetry=True),
                                 clue_penalty=lambda problem: count_non_default_values(problem, default=-2, weight=5),
                                 pretest=pretest, verbose=verbose)
    return generated
Example #19
0
def generate_amarune(height, width, verbose=True):
    pattern = []
    cand = Choice([-1] + list(range(1, height * width - 1)), -1)
    pattern += [[cand for _ in range(width)] for _ in range(height)]
    cand = Choice([-1, 0, 1, 2, 3], -1)
    pattern += [[cand for _ in range(width - 1)] for _ in range(height)]
    pattern += [[cand for _ in range(width)] for _ in range(height - 1)]

    def pretest(problem):
        count_number_hint = 0
        for y in range(height):
            for x in range(width):
                if problem[y][x] > 0:
                    count_number_hint += 1
        return (count_number_hint < 3)

    generated = generate_problem(
        lambda problem: solve_amarune(height, width, problem),
        builder_pattern=pattern,
        clue_penalty=lambda problem: count_non_default_values(
            problem, default=-1, weight=2),
        pretest=pretest,
        verbose=verbose)
    return generated
Example #20
0
 def pretest(problem):
     if max_clue is None:
         return True
     else:
         return count_non_default_values(problem, default=0,
                                         weight=1) <= max_clue