Skip to content

Instantly share code, notes, and snippets.

@jthemphill
Last active February 15, 2022 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jthemphill/1a0165950095eeb24e1ad0aa467969ed to your computer and use it in GitHub Desktop.
Save jthemphill/1a0165950095eeb24e1ad0aa467969ed to your computer and use it in GitHub Desktop.
import collections
horiz_edges = [
[">", "<", ">", ">"],
["<", " ", "<", ">"],
[">", ">", "<", " "],
["<", " ", ">", "<"],
[" ", " ", ">", ">"],
]
assert len(horiz_edges) == 5
assert all((len(row) == 4 for row in horiz_edges))
vert_edges = [
[">", "<", " ", " ", " "],
[" ", " ", ">", ">", ">"],
[">", "<", "<", ">", " "],
[" ", " ", " ", "<", ">"],
]
assert len(vert_edges) == 4
assert all((len(col) == 5 for col in vert_edges))
STEEL = 1
ELECTRIC = 2
GROUND = 3
FIGHTING = 4
FLYING = 5
BEATS_LIST: "list[tuple[int, int]]" = [
(ELECTRIC, STEEL),
(GROUND, STEEL),
(FIGHTING, STEEL),
(STEEL, FLYING),
(GROUND, ELECTRIC),
(ELECTRIC, FLYING),
(FLYING, GROUND),
(FLYING, FIGHTING),
]
beats: "collections.defaultdict[int, list[int]]" = collections.defaultdict(list)
for winner, loser in BEATS_LIST:
beats[winner].append(loser)
def does_beat(type_1: int, type_2: int) -> bool:
assert type_1 > 0
assert type_2 > 0
return type_2 in beats[type_1]
def is_valid(grid: "list[list[int]]"):
assert len(grid) == 5
assert all((len(row) == 5 for row in grid))
# Row uniqueness
for row in grid:
for t in range(STEEL, FLYING + 1):
if row.count(t) > 1:
return False
# Column uniqueness
for c in range(5):
col = [grid[r][c] for r in range(5)]
for t in range(STEEL, FLYING + 1):
if col.count(t) > 1:
return False
# Horizontal inequality
for r in range(5):
for c in range(4):
left = grid[r][c]
if left == 0:
continue
right = grid[r][c + 1]
if right == 0:
continue
if horiz_edges[r][c] == ">" and not does_beat(left, right):
return False
elif horiz_edges[r][c] == "<" and not does_beat(right, left):
return False
# Vertical inequality
for r in range(4):
for c in range(5):
up = grid[r][c]
if up == 0:
continue
down = grid[r + 1][c]
if down == 0:
continue
if vert_edges[r][c] == ">" and not does_beat(up, down):
return False
elif vert_edges[r][c] == "<" and not does_beat(down, up):
return False
return True
def solve(grid: "list[list[int]]"):
assert len(grid) == 5
assert all((len(row) == 5 for row in grid))
if all((all((t != 0 for t in row)) for row in grid)):
render(grid)
return
for r in range(5):
for c in range(5):
if grid[r][c] == 0:
for t in range(STEEL, FLYING + 1):
grid[r][c] = t
if is_valid(grid):
solve(grid)
grid[r][c] = 0
return
def render_type(t: int):
if t == STEEL:
return "steel"
elif t == ELECTRIC:
return "electric"
elif t == GROUND:
return "ground"
elif t == FIGHTING:
return "fighting"
elif t == FLYING:
return "flying"
def render(grid: "list[list[int]]"):
print("---")
for row in grid:
line = ""
for t in row:
line += f"{render_type(t):10}"
print(line)
print("---")
grid = [[0 for c in range(5)] for r in range(5)]
solve(grid)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment