fork(1) download
  1. # -*- coding: utf-8 -*-
  2. import copy
  3. from collections import defaultdict
  4. from itertools import product
  5.  
  6. FALL = '|'
  7. RIVER = '~'
  8. POOL = 'N'
  9.  
  10. SOURCE = 'x'
  11. SOURCE_AND_FALL = '*'
  12. SOURCE_AND_RIVER = 'X'
  13. SOURCE_AND_POOL = '%'
  14.  
  15. BLOCK = '#'
  16. LRAMP = '/'
  17. RRAMP = '\\'
  18. SPACE = ' '
  19.  
  20. LRAMP_AND_FALL = 'd'
  21. RRAMP_AND_FALL = 'b'
  22. LRAMP_AND_RIVER = '}'
  23. RRAMP_AND_RIVER = '{'
  24. LRAMP_AND_POOL = ']'
  25. RRAMP_AND_POOL = '['
  26.  
  27. def isSource(cell):
  28. return cell in [SOURCE, SOURCE_AND_FALL, SOURCE_AND_RIVER, SOURCE_AND_POOL]
  29.  
  30. def isLRamp(cell):
  31. return cell in [LRAMP, LRAMP_AND_FALL, LRAMP_AND_RIVER, LRAMP_AND_POOL]
  32. def isRRamp(cell):
  33. return cell in [RRAMP, RRAMP_AND_FALL, RRAMP_AND_RIVER, RRAMP_AND_POOL]
  34. def isRamp(cell):
  35. return isLRamp(cell) or isRRamp(cell)
  36.  
  37. def isFall(cell):
  38. return cell in [FALL, SOURCE_AND_FALL, LRAMP_AND_FALL, RRAMP_AND_FALL]
  39. def isRiver(cell):
  40. return cell in [RIVER, LRAMP_AND_RIVER, RRAMP_AND_RIVER, SOURCE_AND_RIVER]
  41. def isPool(cell):
  42. return cell in [POOL, LRAMP_AND_POOL, RRAMP_AND_POOL, SOURCE_AND_POOL]
  43. def isSpace(cell):
  44. return cell in [SPACE, SOURCE, LRAMP, RRAMP]
  45.  
  46. def isWetAndLeaky(cell):
  47. return isFall(cell) or isRiver(cell) or isPool(cell)# or isSource(cell) #TODO Should we include source here?
  48. def supportsRiver(cell):
  49. return cell == BLOCK or isPool(cell)
  50. def isOpenAtBottom(cell):
  51. return not (isRamp(cell) or cell == BLOCK)
  52.  
  53. def waterCanFlowIn(grid, i, j):
  54. # Can water flow in from left
  55. if not isRRamp(grid[(i,j)]) and grid[(i, j-1)] in [RIVER, POOL, SOURCE_AND_RIVER, SOURCE_AND_POOL, RRAMP_AND_RIVER, RRAMP_AND_POOL]:
  56. return True
  57. # Can water flow in from left
  58. return not isLRamp(grid[(i,j)]) and grid[(i, j+1)] in [RIVER, POOL, SOURCE_AND_RIVER, SOURCE_AND_POOL, LRAMP_AND_RIVER, LRAMP_AND_POOL]
  59.  
  60. def findBackground(cell):
  61. if cell in [SPACE, FALL, RIVER, POOL]:
  62. return SPACE
  63. elif cell in [BLOCK]:
  64. return BLOCK
  65. elif isSource(cell):
  66. return SOURCE
  67. elif isLRamp(cell):
  68. return LRAMP
  69. elif isRRamp(cell):
  70. return RRAMP
  71. raise Exception
  72.  
  73. def makeSpace(cell):
  74. background = findBackground(cell)
  75. if background == SPACE:
  76. return SPACE
  77. elif background == SOURCE:
  78. return SOURCE
  79. elif background == LRAMP:
  80. return LRAMP
  81. elif background == RRAMP:
  82. return RRAMP
  83. raise Exception
  84. def makeFall(cell):
  85. background = findBackground(cell)
  86. if background == SPACE:
  87. return FALL
  88. elif background == SOURCE:
  89. return SOURCE_AND_FALL
  90. elif background == LRAMP:
  91. return LRAMP_AND_RIVER
  92. elif background == RRAMP:
  93. return RRAMP_AND_RIVER
  94. raise Exception
  95. def makeRiver(cell):
  96. background = findBackground(cell)
  97. if background == SPACE:
  98. return RIVER
  99. elif background == SOURCE:
  100. return SOURCE_AND_RIVER
  101. elif background == LRAMP:
  102. return LRAMP_AND_RIVER
  103. elif background == RRAMP:
  104. return RRAMP_AND_RIVER
  105. raise Exception
  106. def makePool(cell):
  107. background = findBackground(cell)
  108. if background == SPACE:
  109. return POOL
  110. elif background == SOURCE:
  111. return SOURCE_AND_POOL
  112. elif background == LRAMP:
  113. return LRAMP_AND_POOL
  114. elif background == RRAMP:
  115. return RRAMP_AND_POOL
  116. raise Exception
  117.  
  118. def isRiverComplete(grid, i, j):
  119. # Check to left
  120. if not isRRamp(grid[i,j]):
  121. a = j-1
  122. while (isRiver(grid[i, a]) or isPool(grid[i, a])) and not isRamp(grid[i, a]):
  123. a -= 1
  124. if (isSpace(grid[i, a]) or isFall(grid[i, a])) and not isLRamp(grid[i, a]):
  125. return False
  126. # Check to right
  127. if not isLRamp(grid[i,j]):
  128. a = j+1
  129. while (isRiver(grid[i, a]) or isPool(grid[i, a])) and not isRamp(grid[i, a]):
  130. a += 1
  131. if (isSpace(grid[i, a]) or isFall(grid[i, a])) and not isRRamp(grid[i, a]):
  132. return False
  133. return True
  134.  
  135. gridStr = """\
  136. x
  137. # #
  138. # #
  139. # #
  140. #### #####
  141. #### #####
  142. #### #####
  143. ##########"""
  144. gridCells = map(lambda x: list(x), gridStr.split('\n'))
  145. height = len(gridCells)
  146. width = len(gridCells[0])
  147. grid = defaultdict(lambda : SPACE)
  148. for i in range(height):
  149. for j in range(width):
  150. grid[(i,j)] = gridCells[i][j]
  151.  
  152. def displayGrid(grid):
  153. print
  154. for i in range(height):
  155. row = ''
  156. for j in range(width):
  157. row = row+grid[(i,j)]
  158. print row
  159.  
  160. t = 0
  161. while t < 26:
  162. displayGrid(grid)
  163. newGrid = defaultdict(lambda : SPACE)
  164. for i, j in product(range(height), range(width)):
  165. cell = grid[(i,j)]
  166. if cell == FALL and supportsRiver(grid[(i+1, j)]):
  167. #A water fall with ground or pool under it becomes a river.
  168. newGrid[(i,j)] = makeRiver(cell)
  169. elif isSpace(cell) and supportsRiver(grid[(i+1, j)]) and waterCanFlowIn(grid, i, j):
  170. #A space with ground or pool under it and river next to it becomes a river.
  171. newGrid[(i,j)] = makeRiver(cell)
  172. elif isSpace(cell) and isWetAndLeaky(grid[(i-1,j)]):
  173. #A space with a water fall, spring or river above it becomes a water fall.
  174. newGrid[(i,j)] = makeFall(cell)
  175. elif isSpace(cell) and waterCanFlowIn(grid, i, j):
  176. #A space with a river or pool next to it, and no support below becomes a water fall.
  177. newGrid[(i,j)] = makeFall(cell)
  178. elif isRiver(cell) and isRiverComplete(grid, i, j):
  179. #A horizontal row of rivers squares bounded at both ends by walls/ramps becomes a horizontal row of pool squares.
  180. newGrid[(i,j)] = makePool(cell)
  181. elif isOpenAtBottom(cell) and isPool(grid[(i+1, j)]) and not isPool(cell):
  182. #A space above a pool becomes a river
  183. newGrid[(i,j)] = makeRiver(cell)
  184. elif isSource(cell):
  185. #A dry source becomes wet
  186. newGrid[(i,j)] = makeFall(cell)
  187. else:
  188. #Else by default things stay the same
  189. newGrid[(i,j)] = cell
  190.  
  191. # TODO Drying up rules
  192. #A pool or river without ground under it becomes a water fall (e.g. could be caused by bashing).
  193. #A pool with water fall next to it becomes a river.
  194. #A horizontal collection of river tiles without a water fall or spring above them dries up (I think this rule in particular needs some thinking about).
  195.  
  196. grid = newGrid
  197. t += 1
  198.  
  199. displayGrid(grid)
Success #stdin #stdout 0.04s 9128KB
stdin
Standard input is empty
stdout
   x      
#        #
#        #
#        #
#### #####
#### #####
#### #####
##########

   *      
#        #
#        #
#        #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#        #
#        #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
#        #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
#  |     #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
#  ~     #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
# ~~|    #
#### #####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
#### #####
#### #####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####|#####
#### #####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####|#####
####|#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####|#####
####~#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####|#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####~#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####|#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####~#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~|    #
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~~    #
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~~~   #
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~~~~  #
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~~~~~ #
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#~~~~~~~~#
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#  |     #
#NNNNNNNN#
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#~~~~~~~~#
#NNNNNNNN#
####N#####
####N#####
####N#####
##########

   *      
#  |     #
#NNNNNNNN#
#NNNNNNNN#
####N#####
####N#####
####N#####
##########

   *      
#~~~~~~~~#
#NNNNNNNN#
#NNNNNNNN#
####N#####
####N#####
####N#####
##########

   *      
#NNNNNNNN#
#NNNNNNNN#
#NNNNNNNN#
####N#####
####N#####
####N#####
##########

 ~~X~~~~~ 
#NNNNNNNN#
#NNNNNNNN#
#NNNNNNNN#
####N#####
####N#####
####N#####
##########