import random def is_good(walls, size, x, y) -> bool: return 0 <= x < size and 0 <= y < size and ((x == 0 or walls[x - 1][y]) + (y == 0 or walls[x][y - 1]) + (x == size - 1 or walls[x + 1][y]) + (y == size - 1 or walls[x][y + 1]) >= 3) def move_str2coord(move, x, y) -> tuple[int, int]: if move == "left": return x - 1, y elif move == "up": return x, y - 1 elif move == "right": return x + 1, y elif move == "down": return x, y + 1 else: raise ValueError() def invert_move(move): if move == "left": return "right" elif move == "up": return "down" elif move == "right": return "left" elif move == "down": return "up" else: raise ValueError() def generate_box_test() -> dict: size = random.randint(5, 15) tiles = [] winning_moves = [] walls = [[True] * size for _ in range(size)] x, y = random.randrange(size), random.randrange(size) starting_position = x, y walls[x][y] = False tiles.append({"kind": "player", "pos": {"x": x, "y": y}, "data": None}) while True: moves = [] for move in ("left", "up", "right", "down"): coords = move_str2coord(move, x, y) if coords != starting_position and is_good(walls, size, *coords): moves.append(move) if len(moves) == 0: break move = random.choice(moves) moves.remove(move) x1, y1 = move_str2coord(move, x, y) if len(moves) >= 1 and True: other_move = random.choice(moves) x2, y2 = move_str2coord(other_move, x, y) x3, y3 = move_str2coord(other_move, x2, y2) if is_good(walls, size, x3, y3): walls[x2][y2] = False walls[x3][y3] = False tiles.append({"kind": "door", "pos": {"x": x1, "y": y1}, "data": {"button_position": {"x": x3, "y": y3}}}) tiles.append({"kind": "box", "pos": {"x": x2, "y": y2}, "data": None}) winning_moves.extend((other_move, invert_move(other_move))) x, y = x1, y1 walls[x][y] = False winning_moves.append(move) tiles.append({"kind": "exit", "pos": {"x": x, "y": y}, "data": None}) for x in range(size): for y in range(size): if walls[x][y]: tiles.append({"kind": "wall", "pos": {"x": x, "y": y}, "data": None}) # debug_level_print(size, tiles, winning_moves) return {"size": size, "tiles": tiles}, winning_moves def generate_easy(): size = random.randint(10, 20) tiles = [] winning_moves = [] x1, y1 = random.randrange(size), random.randrange(size) tiles.append({"kind": "player", "pos": {"x": x1, "y": y1}, "data": None}) while True: x2, y2 = random.randrange(size), random.randrange(size) if x1 != x2 or y1 != y2: break tiles.append({"kind": "exit", "pos": {"x": x2, "y": y2}, "data": None}) x, y = x1, y1 while x < x2: winning_moves.append("right") x += 1 while x > x2: winning_moves.append("left") x -= 1 while y < y2: winning_moves.append("down") y += 1 while y > y2: winning_moves.append("up") y -= 1 # debug_level_print(size, tiles, winning_moves) return {"size": size, "tiles": tiles}, winning_moves def generate_unbeatable(): size = 6 tiles = [] tiles = [ { "kind": "wall", "pos": { "x": 1, "y": 0 }, "data": None }, { "kind": "wall", "pos": { "x": 1, "y": 1 }, "data": None }, { "kind": "wall", "pos": { "x": 1, "y": 2 }, "data": None }, { "kind": "wall", "pos": { "x": 1, "y": 3 }, "data": None }, { "kind": "wall", "pos": { "x": 1, "y": 4 }, "data": None }, { "kind": "wall", "pos": { "x": 1, "y": 5 }, "data": None }, { "kind": "wall", "pos": { "x": 2, "y": 3 }, "data": None }, { "kind": "wall", "pos": { "x": 3, "y": 3 }, "data": None }, { "kind": "wall", "pos": { "x": 4, "y": 3 }, "data": None }, { "kind": "wall", "pos": { "x": 5, "y": 3 }, "data": None }, { "kind": "wall", "pos": { "x": 4, "y": 0 }, "data": None }, { "kind": "wall", "pos": { "x": 4, "y": 1 }, "data": None }, { "kind": "door", "pos": { "x": 5, "y": 1 }, "data": { "button_position": { "x": 2, "y": 0 } } }, { "kind": "box", "pos": { "x": 2, "y": 1 }, "data": None }, { "kind": "exit", "pos": { "x": 5, "y": 0 }, "data": None } ] x, y = random.randint(2, 5), random.randint(4, 5) tiles.append({"kind": "player", "pos": {"x": x, "y": y}, "data": None}) x, y = 0, random.randrange(6) tiles.append({"kind": "box", "pos": {"x": x, "y": y}, "data": None}) # debug_level_print(size, tiles) return {"size": size, "tiles": tiles} def debug_level_print(size, tiles, winning_moves = None): if winning_moves: print(winning_moves) for y in range(size): for x in range(size): s = "" for tile in tiles: if tile["pos"]["x"] == x and tile["pos"]["y"] == y: if tile["kind"] == "exit": s = "00" elif tile["kind"] == "player": s = "<>" elif tile["kind"] == "door": s = "##" elif tile["kind"] == "box": s = "[]" elif tile["kind"] == "wall": s = s or "::" elif tile["kind"] == "door" and tile["data"]["button_position"]["x"] == x and tile["data"]["button_position"]["y"] == y: s = "xx" s = s or " " print(s, end="") print()