Advertisement
Guest User

Untitled

a guest
May 27th, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.56 KB | None | 0 0
  1. #! /usr/bin/env python
  2.  
  3. from heapq import *
  4.  
  5. '''
  6. legend
  7. w = wall
  8. r = red shape / fruit
  9. g = green shape / fruit
  10. b = blue shape
  11. x = cross shape
  12. p = pink fruit
  13. y = yellow fruit
  14. l = lightning tile
  15. space = empty tile
  16. '''
  17.  
  18. b_width, b_height = [10, 12]
  19. start_board = ("wwww      "
  20.                "www       "
  21.                "ww        "
  22.                "w         "
  23.                "          "
  24.                "          "
  25.                "ypppg     "
  26.                "ygypy     "
  27.                "yyrpg     "
  28.                "ypppr     "
  29.                "rgggyw    "
  30.                "rgrrr     ")
  31.  
  32.  
  33. def match(color, other):
  34.     return True if (color == 'l' or other == 'l') else color == other
  35.  
  36.  
  37. def is_clear(line):
  38.     # Remove spaces
  39.     line = filter(lambda x: x not in ' ', line)
  40.     if len(line) == 0:
  41.         return True, ' '
  42.     if len(line) == line.count(line[0]):
  43.         # All elements are the same
  44.         return True, line[0]
  45.     return False, None
  46.  
  47.  
  48. def lightning_reachable(board):
  49.     coord = None
  50.     # Find coordinates for lightning tile
  51.     for i, line in enumerate(board):
  52.         if 'l' in line:
  53.             coord = (i, line.index('l'))
  54.     if coord is None:
  55.         # No lightning found, not visible
  56.         return False
  57.     for i in range(coord[0]):
  58.         # For lines above lightning, need a wall one tile to the left
  59.         if coord[1] > 0 and board[i][coord[1]-1] != 'w':
  60.             continue
  61.         # Check if line is clear or has only one element
  62.         line = board[i][coord[1]:]
  63.         clear, base = is_clear(line)
  64.         if clear:
  65.             # All elements below need to be either space or same as base
  66.             col = [board[k][coord[1]] for k in range(i, coord[0])]
  67.             col = filter(lambda x: x not in " w", col)
  68.             if len(col) == 0:
  69.                 # All spaces / wall
  70.                 return True
  71.             if len(col) == col.count(col[0]) and (base in [col[0], ' ']):
  72.                 return True
  73.     # For lightning's line, simply check if line is clear
  74.     line = board[coord[0]][coord[1]+1:]
  75.     return is_clear(line)[0]
  76.  
  77.  
  78. def gravity(board):
  79.     for i, line in enumerate(board[::-1]):
  80.         i = b_height - 1 - i
  81.         if i == 0:
  82.             continue
  83.         for j, tile in enumerate(line):
  84.             if tile == ' ':
  85.                 for k in range(i)[::-1]:
  86.                     if board[k][j] == ' ':
  87.                         continue
  88.                     elif board[k][j] in "rgbxypl":
  89.                         board[i][j] = board[k][j]
  90.                         board[k][j] = ' '
  91.                         break
  92.                     else:
  93.                         break
  94.  
  95.  
  96. def throw(color, height, board):
  97.     new_board = [line[:] for line in board]
  98.     valid = False
  99.  
  100.     line = new_board[height]
  101.     for i, tile in enumerate(line[::-1]):
  102.         if tile == ' ':
  103.             # Empty tile, continue movement
  104.             continue
  105.         elif tile in "w":
  106.             # Collide with wall or pipe, fall
  107.             return fall(color, height, b_width - i, new_board, valid)
  108.         elif match(color, tile):
  109.             # Mark as a valid move
  110.             valid = True
  111.             # Lightning tile changes color to whatever it touched
  112.             if (color == 'l' and tile != 'l'):
  113.                 color = tile
  114.             # Erase matched tile
  115.             line[b_width - 1 - i] = ' '
  116.             continue
  117.         elif valid:
  118.             # Was a valid move, no more matches
  119.             # Swap thrown color for current touching color and return
  120.             ret_color = tile
  121.             line[b_width - 1 - i] = color
  122.             # Apply gravity to board
  123.             gravity(new_board)
  124.             return ret_color, new_board
  125.         else:
  126.             # Invalid move
  127.             return None, None
  128.     # Reached left boundary, fall from there
  129.     return fall(color, height, 0, new_board, valid)
  130.  
  131.  
  132. def fall(color, height, column, board, valid):
  133.     line = [row[column] for row in board]
  134.     for i, tile in enumerate(line):
  135.         if i < height or tile in ' w':
  136.             # Skip to starting height, empty tile, continue movement
  137.             continue
  138.         elif match(color, tile):
  139.             # Mark as a valid move
  140.             valid = True
  141.             # Lightning tile changes color to whatever it touched
  142.             # Passing through lightning tile does not change color
  143.             if (color == 'l' and tile != 'l'):
  144.                 color = tile
  145.             # Erase matched tile
  146.             board[i][column] = ' '
  147.             continue
  148.         elif valid:
  149.             # Was a valid move, no more matches
  150.             # Swap thrown color for current touching color and return
  151.             ret_color = tile
  152.             board[i][column] = color
  153.             # Apply gravity to board
  154.             gravity(board)
  155.             return ret_color, board
  156.         else:
  157.             # Invalid move
  158.             return None, None
  159.     # Reached bottom of board, check if valid move
  160.     if valid:
  161.         # Apply gravity to board
  162.         gravity(board)
  163.         # Return color is the same as thrown color
  164.         return color, board
  165.     else:
  166.         return None, None
  167.  
  168.  
  169. def grade(board):
  170.     # We want to minimize number of tiles in play, so we use that as score
  171.     score = 0
  172.     for line in board:
  173.         for tile in line:
  174.             if tile in "rgbxypl":
  175.                 score += 1
  176.     return score
  177.  
  178. if __name__ == '__main__':
  179.  
  180.     board = [list(start_board)[(i*10):((i+1)*10)] for i in range(12)]
  181.     lightning = 'l' in start_board
  182.     light = 999 if 'l' in start_board else 0
  183.  
  184.     score = grade(board)
  185.     states = []
  186.     iterations = 0
  187.     best = (light, score, 0, [], 'l', board)
  188.     heappush(states, (light, score, 0, [], 'l', board))
  189.  
  190.     while states and iterations < 1000000:
  191.         iterations += 1
  192.         light, score, count, moves, tile, board = heappop(states)
  193.         if lightning:
  194.             # If lightning is in field, check if it's accessible
  195.             visible = lightning_reachable(board)
  196.         if score < best[1] or (score == best[1] and light < best[0]):
  197.             # Current state is better than previou8s best state, store it
  198.             best = (light, score, count, moves, tile, board)
  199.             if lightning:
  200.                 print score, count, moves, light
  201.             else:
  202.                 print score, count, moves
  203.  
  204.         for i in range(b_height):
  205.             # For each possible move, check result
  206.             nt, new_board = throw(tile, i, board)
  207.             if nt is None:
  208.                 # Invalid move
  209.                 continue
  210.             score = grade(new_board)
  211.             if lightning:
  212.                 if visible:
  213.                     # If lighting was visible before move, check if it still is
  214.                     still_visible = False
  215.                     for line in new_board:
  216.                         if 'l' in line:
  217.                             still_visible = True
  218.                             break
  219.                     if still_visible:
  220.                         lrm = 999
  221.                     else:
  222.                         lrm = count + 1
  223.                 else:
  224.                     # If there was lightning, keep previous light removal
  225.                     lrm = light
  226.             else:
  227.                 lrm = 0
  228.             # Push new valid state
  229.             heappush(states, (lrm, score, count+1, moves+[i], nt, new_board))
  230.  
  231.     print "=================="
  232.     print "Iterations:", iterations
  233.     print len(states), "states left in queue"
  234.     light, score, count, moves, tile, board = best
  235.     print score, count, moves, tile, light
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement