Skip to content

Instantly share code, notes, and snippets.

@Transfusion
Created May 15, 2023 12:56
Show Gist options
  • Save Transfusion/72a349616afe71580e8d932cf8f3c726 to your computer and use it in GitHub Desktop.
Save Transfusion/72a349616afe71580e8d932cf8f3c726 to your computer and use it in GitHub Desktop.
# No two skyscrapers in a row or column may have the same number of floors
# The height of the skyscrapers is between 1 and 4
# so conservative upper bound is (4!)**4 = 331776
# A clue is the number of skyscrapers you can see.
import itertools
n=4
def solve_puzzle (clues):
grid=[]
def validate_column(clue, c, from_top):
can_see, last_seen_height = 0, -1
for i in (range(0, n) if from_top else range(n-1, -1,-1)):
if grid[i][c] > last_seen_height:
can_see, last_seen_height = can_see+1, grid[i][c]
return can_see == clue
def validate_row(clue, r, from_left):
can_see, last_seen_height = 0, -1
for i in (range(0, n) if from_left else range(n-1, -1,-1)):
if grid[r][i] > last_seen_height:
can_see, last_seen_height = can_see+1, grid[r][i]
return can_see == clue
# grid = ( (2,1,4,3),
# (3,4,1,2),
# (4,2,3,1),
# (1,3,2,4))
# the test case
# print( validate_column(1,2,True), validate_column(2,3,True), validate_row(2,1,False), validate_column(3,2,False), validate_row(1,2,True), )
def validate_grid():
for i, v in enumerate(clues):
if v == 0: continue
if i // n == 0 and not validate_column(v, i, True): # column down
return False
elif i // n == 1 and not validate_row(v, i % n, False): # row right
return False
elif i // n == 2 and not validate_column(v, n - (i % n) - 1, False): # column up
return False
elif i // n == 3 and not validate_row(v, n - (i % n) - 1, True): # row left
return False
return True
# print(validate_grid())
res = None
def rec(a=0,b=0,c=0,d=0):
nonlocal res
if res: return
if all(map(lambda x: x == (1<<n)-1 << 1, (a,b,c,d) )):
# if all bitmasks are 01111
if validate_grid():
res = tuple(tuple(l) for l in grid)
return
for perm in map(lambda x: list(map(lambda y: y+1, x)), itertools.permutations(range(n))):
if res: return
used = [a,b,c,d]
ok = True
for i in range(n):
if used[i] & (1<<perm[i]):
ok = False
break
else: used[i] |= (1<<perm[i])
if ok:
grid.append(perm)
rec(*used)
grid.pop()
rec()
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment