Advertisement
Guest User

skyscraper.py

a guest
Jul 13th, 2013
5,381
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.05 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import os
  4. from copy import deepcopy
  5.  
  6. # set path here
  7. path_to_files = '.'
  8.  
  9. class Puzzle(object):
  10.  
  11.     def __init__(self, size):
  12.         self.size = size
  13.         self.cells = [[set(range(size)) for _x in range(size)]
  14.                       for _y in range(size)]
  15.         self.clues = [None] * 4
  16.  
  17.     def is_full(self):
  18.         for row in self.cells:
  19.             for cell in row:
  20.                 if len(cell) != 1:
  21.                     return False
  22.         return True
  23.  
  24.     def is_solvable(self):
  25.         for row in self.cells:
  26.             for cell in row:
  27.                 if len(cell) == 0:
  28.                     return False
  29.         return True
  30.  
  31.     def is_solved(self):
  32.         if not self.is_full():
  33.             return False
  34.  
  35.         for index in range(self.size):
  36.             column = [next(iter(self.cells[x][index]))
  37.                       for x in range(self.size)]
  38.             if not self.satisfies_clue(column, self.clues[0][index], self.clues[3][index]):
  39.                 return False
  40.  
  41.             row = [next(iter(self.cells[index][y])) for y in range(self.size)]
  42.             if not self.satisfies_clue(row, self.clues[1][index], self.clues[2][index]):
  43.                 return False
  44.  
  45.         return True
  46.  
  47.     def satisfies_clue(self, values, clue_left, clue_right):
  48.         current = - 1
  49.         for height in values:
  50.             if current < height:
  51.                 clue_left -= 1
  52.                 current = height
  53.         if clue_left != 0:
  54.             return False
  55.         current = - 1
  56.         for height in reversed(values):
  57.             if current < height:
  58.                 clue_right -= 1
  59.                 current = height
  60.         if clue_right != 0:
  61.             return False
  62.         return True
  63.  
  64.     def set_cell_to(self, x, y, value):
  65.         value = set([value])
  66.         for i in range(self.size):
  67.             self.cells[i][x] -= value
  68.             self.cells[y][i] -= value
  69.         self.cells[y][x] = value
  70.  
  71.     def fix(self):
  72.         for i in range(self.size):
  73.             for j in range(self.size):
  74.                 if len(self.cells[i][j]) == 1:
  75.                     self.set_cell_to(j, i, next(iter(self.cells[i][j])))
  76.  
  77.     def solve_basic_clues(self):
  78.         # top clues
  79.         for index, clue in enumerate(self.clues[0]):
  80.             if clue == 1:
  81.                 self.set_cell_to(index, 0, self.size - 1)
  82.             elif clue == self.size:
  83.                 for i in range(self.size):
  84.                     self.set_cell_to(index, i, i)
  85.  
  86.         # bottom clues
  87.         for index, clue in enumerate(self.clues[3]):
  88.             if clue == 1:
  89.                 self.set_cell_to(index, self.size - 1, self.size - 1)
  90.             elif clue == self.size:
  91.                 for i in range(self.size):
  92.                     self.set_cell_to(index, i, self.size - (i + 1))
  93.  
  94.         # left clues
  95.         for index, clue in enumerate(self.clues[1]):
  96.             if clue == 1:
  97.                 self.set_cell_to(0, index, self.size - 1)
  98.             elif clue == self.size:
  99.                 for i in range(self.size):
  100.                     self.set_cell_to(i, index, i)
  101.         # right clues
  102.         for index, clue in enumerate(self.clues[2]):
  103.             if clue == 1:
  104.                 self.set_cell_to(self.size - 1, index, self.size - 1)
  105.             elif clue == self.size:
  106.                 for i in range(self.size):
  107.                     self.set_cell_to(i, index, self.size - (i + 1))
  108.  
  109.     def __repr__(self):
  110.         result = []
  111.         if self.is_full():
  112.             for row in self.cells:
  113.                 result.append(
  114.                     ' '.join(str(next(iter(cell)) + 1) for cell in row))
  115.         else:
  116.             for row in self.cells:
  117.                 result.append(repr(row))
  118.         return '\n'.join(result)
  119.  
  120.  
  121. def main():
  122.     input_file_name = os.path.join(path_to_files, 'skyscraper_puzzles_unsolved.txt')
  123.     output_file_name = os.path.join(path_to_files, 'skyscraper_puzzles_solved.txt')
  124.  
  125.     lines = open(input_file_name)
  126.     output_file = open(output_file_name,'w')
  127.  
  128.     npuzzles = int(next(lines))
  129.     print >>output_file, npuzzles
  130.  
  131.     for i in range(npuzzles):
  132.         size = int(next(lines))
  133.         p = Puzzle(size)
  134.         for i in range(4):
  135.             p.clues[i] = [int(x) for x in next(lines).split()]
  136.         p.solve_basic_clues()
  137.         p.fix()
  138.         solution = recursive_solve(p, 0)
  139.  
  140.         print >>output_file, p.size
  141.         print >>output_file, solution or 'Invalid puzzle'
  142.  
  143.  
  144. def recursive_solve(puzzle, index):
  145.  
  146.     x = index % puzzle.size
  147.     y = index / puzzle.size
  148.     for value in puzzle.cells[y][x]:
  149.         tmp = deepcopy(puzzle)
  150.         tmp.set_cell_to(x, y, value)
  151.         tmp.fix()
  152.         if not tmp.is_solvable():
  153.             continue
  154.         elif tmp.is_solved():
  155.             return tmp
  156.         elif not tmp.is_full():
  157.             tmp2 = recursive_solve(tmp, index + 1)
  158.             if tmp2 is None:
  159.                 continue
  160.             elif tmp2.is_solved():
  161.                 return tmp2
  162.     return None
  163.  
  164. if __name__ == '__main__':
  165.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement