Skip to content

Instantly share code, notes, and snippets.

@mentix02
Last active June 1, 2023 03:33
Show Gist options
  • Save mentix02/f4c64c2cca117630ec4e1cbd93c9f322 to your computer and use it in GitHub Desktop.
Save mentix02/f4c64c2cca117630ec4e1cbd93c9f322 to your computer and use it in GitHub Desktop.
#!/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