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
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)
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
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
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
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
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
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
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
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
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
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
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
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