Last active
June 1, 2023 03:33
-
-
Save mentix02/f4c64c2cca117630ec4e1cbd93c9f322 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import enum | |
import time | |
import random | |
import argparse | |
@enum.unique | |
class Tile(enum.Enum): | |
FIRE = "🔥" | |
GREEN = "🍏" | |
WATER = "🌊" | |
BERRY = "🍒" | |
PURPLE = "🟣" | |
THUNDER = "⚡" | |
@classmethod | |
def random_tile(cls) -> "Tile": | |
return random.choice(tuple(cls)) | |
def __str__(self) -> str: | |
return self.value | |
class Grid: | |
def __init__(self, size: int, legal: bool = False): | |
self.data: list[list[Tile]] = [[None] * size for _ in range(size)] | |
if legal: | |
self.generate_legal_grid() | |
else: | |
self.generate_random_grid() | |
def generate_random_grid(self) -> "Grid": | |
""" | |
Generates a random grid. This grid may not be legal (most likely). | |
""" | |
for row_idx in range(len(self)): | |
for col_idx in range(len(self)): | |
self.data[row_idx][col_idx] = Tile.random_tile() | |
return self | |
def generate_legal_grid(self) -> "Grid": | |
""" | |
Optimized algorithm to generate a legal grid. Performs | |
look aheads while generating the grid to ensure that | |
no matching tiles are generated. | |
""" | |
for row_idx in range(len(self)): | |
for col_idx in range(len(self)): | |
self.data[row_idx][col_idx] = self._generate_tile(row_idx, col_idx) | |
return self | |
def _generate_tile(self, row_idx: int, col_idx: int) -> Tile: | |
""" | |
Generates a tile that is not the same as the tiles | |
to the left and above it. | |
""" | |
while True: | |
tile = Tile.random_tile() | |
if self._is_legal_tile(row_idx, col_idx, tile): | |
return tile | |
def _is_legal_tile(self, row_idx: int, col_idx: int, tile: Tile) -> bool: | |
""" | |
Checks if the given tile is legal at the given position. | |
""" | |
if col_idx > 0 and self.data[row_idx][col_idx - 1] == tile: | |
return False | |
if row_idx > 0 and self.data[row_idx - 1][col_idx] == tile: | |
return False | |
return True | |
@property | |
def is_legal(self) -> bool: | |
return not self.has_matches | |
@property | |
def has_matches(self) -> bool: | |
""" | |
Checks if there is a legal pair of more than 3 matching | |
tiles in the grid. Can only be horizontally or vertically. | |
NOT diagonally. | |
""" | |
for row_idx in range(len(self.data)): | |
for col_idx in range(len(self.data)): | |
if self._has_matches(row_idx, col_idx): | |
return True | |
else: | |
return False | |
def _has_matches(self, row_idx: int, col_idx: int) -> bool: | |
# check if there is a horizontal match | |
if col_idx + 2 < len(self.data): | |
tiles = [self.data[row_idx][col_idx + i] for i in range(3)] | |
if self._all_same(tiles): | |
return True | |
# check if there is a vertical match | |
if row_idx + 2 < len(self.data): | |
tiles = [self.data[row_idx + i][col_idx] for i in range(3)] | |
if self._all_same(tiles): | |
return True | |
return False | |
@staticmethod | |
def _all_same(tiles: list[Tile]) -> bool: | |
return all(tile == tiles[0] for tile in tiles) | |
def __str__(self) -> str: | |
res = "\n" | |
for row in self.data[:-1]: | |
res += " ".join(map(str, row)) + "\n\n" | |
res += " ".join(map(str, self.data[-1])) + "\n" | |
return res | |
def __len__(self) -> int: | |
return len(self.data) | |
def __getitem__(self, idx: int) -> list[str]: | |
return self.data[idx] | |
def main(): | |
parser = argparse.ArgumentParser( | |
description="shuffle random tiles to tickle your brain" | |
) | |
parser.add_argument("-n", "--number", type=int, default=5, help="size of grid") | |
parser.add_argument("-s", "--seed", type=int, help="seed to generate randomness") | |
parser.add_argument( | |
"-l", "--legal", action="store_true", help="only show legal grids" | |
) | |
args = parser.parse_args() | |
if args.seed is None: | |
args.seed = time.time_ns() | |
random.seed(args.seed) | |
n = args.number | |
grid = Grid(n, legal=args.legal) | |
print(grid) | |
print("is legal:", grid.is_legal) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment