fork 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. gridStr = """\
  28. x
  29. # #
  30. # #
  31. # #
  32. #### #####
  33. #### #####
  34. #### #####
  35. ##########"""
  36. gridStr = """\
  37. x
  38.  
  39.  
  40. # # #
  41. # # #
  42. # # #
  43. # # #
  44. # # #
  45. #######################"""
  46. gridStr = """\
  47. x
  48. # /
  49. #####"""
  50. gridStr = """\
  51. x
  52. # /
  53. #####
  54. # #
  55. # # /
  56. ###\/#"""
  57. gridStr = """\
  58. x #
  59. # # #
  60. # # #
  61. # # #
  62. # #
  63. ######"""
  64.  
  65. HALF_CAPACITY = 50
  66. MAX_CAPACITY = 2*HALF_CAPACITY
  67. MAX_DOWN_RATE = HALF_CAPACITY
  68. SOURCE_RATE = HALF_CAPACITY
  69. DENSITY = 0.5
  70.  
  71. SPACE_THRESHHOLD = HALF_CAPACITY / 2
  72. RIVER_THRESHHOLD = HALF_CAPACITY + HALF_CAPACITY / 2
  73.  
  74. def isSource(cell):
  75. return cell in [SOURCE, SOURCE_AND_FALL, SOURCE_AND_RIVER, SOURCE_AND_POOL]
  76.  
  77. def isLRamp(cell):
  78. return cell in [LRAMP, LRAMP_AND_FALL, LRAMP_AND_RIVER, LRAMP_AND_POOL]
  79. def isRRamp(cell):
  80. return cell in [RRAMP, RRAMP_AND_FALL, RRAMP_AND_RIVER, RRAMP_AND_POOL]
  81. def isRamp(cell):
  82. return isLRamp(cell) or isRRamp(cell)
  83.  
  84. def findBackground(cell):
  85. if cell in [SPACE, FALL, RIVER, POOL, SOURCE]:
  86. return SPACE
  87. elif cell in [BLOCK]:
  88. return BLOCK
  89. elif isLRamp(cell):
  90. return LRAMP
  91. elif isRRamp(cell):
  92. return RRAMP
  93. raise Exception
  94.  
  95. class WaterType:
  96. FALL = 1
  97. SETTLED = 2
  98.  
  99. class Cell:
  100. def __init__(self, background, isSource):
  101. self.background = background
  102. self.isSource = isSource
  103. self.water = 0
  104. self.waterType = WaterType.FALL
  105. self.capacity = (0 if background == BLOCK else (HALF_CAPACITY if isRamp(background) else MAX_CAPACITY))
  106. def copyCell(self, cell):
  107. self.background = cell.background
  108. self.capacity = cell.capacity
  109. self.isSource = cell.isSource
  110. # Include any water already here
  111. self.water += cell.water
  112. self.waterType = cell.waterType
  113. def __str__(self):
  114. if self.background == SPACE and not self.isSource and self.water <= SPACE_THRESHHOLD:
  115. return SPACE
  116. elif self.background == SPACE and not self.isSource and self.waterType == WaterType.FALL:
  117. return FALL
  118. elif self.background == SPACE and not self.isSource and self.water <= RIVER_THRESHHOLD:
  119. return RIVER
  120. elif self.background == SPACE and not self.isSource:
  121. return POOL
  122. elif self.background == SPACE and self.water <= SPACE_THRESHHOLD:
  123. return SOURCE
  124. elif self.background == SPACE and self.waterType == WaterType.FALL:
  125. return SOURCE_AND_FALL
  126. elif self.background == SPACE and self.water <= RIVER_THRESHHOLD:
  127. return SOURCE_AND_RIVER
  128. elif self.background == SPACE:
  129. return SOURCE_AND_POOL
  130. elif self.background == BLOCK:
  131. return BLOCK
  132. elif isRamp(self.background) and self.isSource:
  133. raise Exception
  134. elif self.background == LRAMP and self.water <= SPACE_THRESHHOLD / 2:
  135. return LRAMP
  136. elif self.background == LRAMP and self.waterType == WaterType.FALL:
  137. return LRAMP_AND_FALL
  138. elif self.background == LRAMP and self.water <= RIVER_THRESHHOLD / 2:
  139. return LRAMP_AND_RIVER
  140. elif self.background == LRAMP:
  141. return LRAMP_AND_POOL
  142. elif self.water <= SPACE_THRESHHOLD / 2:
  143. return RRAMP
  144. elif self.waterType == WaterType.FALL:
  145. return RRAMP_AND_FALL
  146. elif self.water <= RIVER_THRESHHOLD / 2:
  147. return RRAMP_AND_RIVER
  148. else:
  149. return RRAMP_AND_POOL
  150.  
  151. gridCells = map(lambda x: list(x), gridStr.split('\n'))
  152. height = len(gridCells)
  153. width = len(gridCells[0])
  154. grid = defaultdict(lambda : Cell(SPACE, False))
  155. for i in range(height):
  156. for j in range(width):
  157. grid[i,j] = Cell(findBackground(gridCells[i][j]), isSource(gridCells[i][j]))
  158.  
  159. def findApatures(grid, i, j):
  160. apature = {}
  161. if grid[i,j].background == BLOCK:
  162. apature[i-1,j] = apature[i+1,j] = apature[i,j-1] = apature[i,j+1] = 0
  163. elif grid[i,j].background == LRAMP:
  164. apature[i+1,j] = apature[i,j+1] = 0
  165. apature[i-1,j] = 0 if grid[i-1,j].background in [BLOCK, LRAMP, RRAMP] else MAX_CAPACITY
  166. apature[i,j-1] = 0 if grid[i,j-1].background in [BLOCK, LRAMP] else MAX_CAPACITY
  167. elif grid[i,j].background == RRAMP:
  168. apature[i+1,j] = apature[i,j-1] = 0
  169. apature[i-1,j] = 0 if grid[i-1,j].background in [BLOCK, LRAMP, RRAMP] else MAX_CAPACITY
  170. apature[i,j+1] = 0 if grid[i,j+1].background in [BLOCK, RRAMP] else MAX_CAPACITY
  171. elif grid[i,j].background == SPACE:
  172. apature[i-1,j] = 0 if grid[i-1,j].background in [BLOCK, LRAMP, RRAMP] else MAX_CAPACITY
  173. apature[i+1,j] = 0 if grid[i+1,j].background in [BLOCK] else MAX_CAPACITY
  174. apature[i,j-1] = 0 if grid[i,j-1].background in [BLOCK, LRAMP] else MAX_CAPACITY
  175. apature[i,j+1] = 0 if grid[i,j+1].background in [BLOCK, RRAMP] else MAX_CAPACITY
  176. else:
  177. raise Exception
  178. return apature
  179.  
  180. def displayGrid(grid):
  181. print
  182. for i in range(height):
  183. row = ''
  184. for j in range(width):
  185. row += str(grid[i,j])
  186. row += ' '
  187. for j in range(width):
  188. row += ('%x'%(grid[i,j].water / 10) if grid[i,j].water < 160 else '+')
  189. print row
  190.  
  191. t = 0
  192. while t < 50:
  193. displayGrid(grid)
  194. newGrid = defaultdict(lambda : Cell(SPACE, False))
  195. for i, j in product(range(height), range(width)):
  196. cell = grid[i,j]
  197. newCell = newGrid[i,j]
  198. newCell.copyCell(cell)
  199. initWater = cell.water
  200. water = cell.water
  201. if cell.isSource:
  202. water += SOURCE_RATE
  203. apature = findApatures(grid, i, j)
  204. # Downwards
  205. availableFlow = min(max(grid[i+1,j].capacity - grid[i+1,j].water, 0), apature[i+1,j])
  206. toMove = min(availableFlow, water, MAX_DOWN_RATE)
  207. water -= toMove
  208. newGrid[i+1,j].water += toMove
  209. if toMove > 0:
  210. newGrid[i,j].waterType = WaterType.FALL
  211. else:
  212. newGrid[i,j].waterType = WaterType.SETTLED
  213. # Left and right
  214. availableFlowLeft = min(max(grid[i,j-1].capacity - grid[i,j-1].water, 0), apature[i,j-1])
  215. availableFlowRight = min(max(grid[i,j+1].capacity - grid[i,j+1].water, 0), apature[i,j+1])
  216. if availableFlowLeft + availableFlowRight > 0:
  217. spreadNumerator = (apature[i,j-1] + apature[i,j+1]) / MAX_CAPACITY
  218. spreadDenominator = (apature[i,j-1] + apature[i,j+1] + cell.capacity) / MAX_CAPACITY
  219. toMove = min(availableFlowLeft + availableFlowRight, int((water * spreadNumerator) / spreadDenominator))
  220. toMoveLeft = int((toMove * availableFlowLeft) / (availableFlowLeft + availableFlowRight))
  221. toMoveRight = int((toMove * availableFlowRight) / (availableFlowLeft + availableFlowRight))
  222. water -= (toMoveLeft + toMoveRight)
  223. newGrid[i,j-1].water += toMoveLeft
  224. newGrid[i,j+1].water += toMoveRight
  225. # Up
  226. availableFlow = min(max(grid[i-1,j].capacity - grid[i-1,j].water, 0), apature[i-1,j])
  227. if water > MAX_CAPACITY:
  228. toMove = min(availableFlow, water - MAX_CAPACITY)
  229. water -= toMove
  230. newGrid[i-1,j].water += toMove
  231. newGrid[i,j].water += (water - initWater)
  232. grid = newGrid
  233. t += 1
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
Success #stdin #stdout 0.06s 9120KB
stdin
Standard input is empty
stdout
 x #   000000
#  # # 000000
#  # # 000000
#  # # 000000
#    # 000000
###### 000000

 x #   000000
#~ # # 050000
#  # # 000000
#  # # 000000
#    # 000000
###### 000000

 x #   000000
#| # # 050000
#~ # # 050000
#  # # 000000
#    # 000000
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#~ # # 050000
#    # 000000
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#| # # 050000
#~   # 050000
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#| # # 050000
#~   # 072000
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#| # # 061000
#~~  # 064100
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#| # # 051000
#~~~ # 076200
###### 000000

 x #   000000
#| # # 050000
#| # # 040000
#| # # 061000
#~N~ # 077410
###### 000000

 x #   000000
#| # # 040000
#| # # 050000
#| # # 052000
#N~~~# 097520
###### 000000

 x #   000000
#| # # 050000
#| # # 050000
#||# # 063000
#NNN~# 088740
###### 000000

 x #   000000
#| # # 050000
#| # # 051000
#||# # 064000
#NN~~# 0a8760
###### 000000

 x #   000000
#| # # 050000
#| # # 051000
#N|# # 085000
#NNN~# 089860
###### 000000

 x #   000000
#| # # 040000
#| # # 062000
#||# # 078000
#NNNN# 0a7880
###### 000000

 x #   000000
#| # # 050000
#| # # 052000
#N|# # 0a6000
#NN~N# 08d780
###### 000000

 x #   000000
#| # # 040000
#~|# # 073000
#|N# # 06c000
#NNN~# 0b9a70
###### 000000

 x #   000000
#| # # 061000
#|~# # 064000
#N|# # 0e7000
#NN~N# 0ac7a0
###### 000000

 x #   000000
#| # # 051000
#N|# # 095000
#NN# # 0ac000
#NNN~# 0a9c70
###### 000000

 x #   000000
#||# # 072000
#~N# # 05c000
#N|# # 0aa000
#NNNN# 09b9a0
###### 000000

 x #   110000
#|~# # 053000
#NN# # 0e8000
#|N# # 09a000
#NNNN# 0aaa90
###### 000000

 x #   000000
#N|# # 0a4000
#|N# # 0ab000
#NN# # 0b9000
#NNNN# 0aaaa0
###### 000000

 x #   221000
#~N# # 05a000
#N|# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

 x #   121000
#N~# # 0f5000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~X #   332000
#NN# # 0ab000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~X~#   355000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~X~#   575000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%~#   676000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   687000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   698000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6a9000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000

~%N#   6aa000
#NN# # 0aa000
#NN# # 0aa000
#NN# # 0aa000
#NNNN# 0aaaa0
###### 000000