parser.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #!/usr/bin/env python3
  2. import time
  3. COLUMNS = 7
  4. BLOCK_SIZE = 60
  5. MAX_COLUMN_HEIGHT = 546
  6. DETECT_COLUMN_OFFSET_X = 8, 50
  7. DETECT_COLUMN_OFFSET_Y = -11
  8. MIN_COLUMN_SAT = 130
  9. MIN_COLUMN_VAL = 120
  10. COLUMN_VSHIFT = [-2, -2, -1, -1, 0, 0, 0]
  11. RED, PINK, GREEN, BLUE, YELLOW, NONE = range(6)
  12. BOMB_OFFSET = NONE + 1
  13. BASIC_HUES = [248, 224, 118, 158, 26]
  14. BOMB_HUES = [250, 219, 131, 174, 38]
  15. HUE_TOLERANCE = 5
  16. DETECT_BASIC_X = 9
  17. DETECT_BASIC_Y = 15
  18. DETECT_BOMB_X = 25
  19. DETECT_BOMB_Y = 44
  20. MIN_BASIC_SAT = 180
  21. DETECT_EXA_X = 30
  22. DETECT_EXA_Y = 547
  23. EXA_HUE = 129
  24. EXA_MIN_VAL = 240
  25. DETECT_HELD_Y = 579
  26. DETECT_EXA_LIGHT_X = 30
  27. DETECT_EXA_LIGHT_Y = 609
  28. EXA_LIGHT_HUE = 226
  29. MIN_EXA_LIGHT_VAL = 180
  30. def is_hue(h, hexpect):
  31. return abs(h - hexpect) <= HUE_TOLERANCE
  32. def detect_columns(board):
  33. def saturated(x, y):
  34. h, s, v = board.getpixel((x, y))
  35. return s > MIN_COLUMN_SAT and v > MIN_COLUMN_VAL
  36. a, b = DETECT_COLUMN_OFFSET_X
  37. for y in range(MAX_COLUMN_HEIGHT, BLOCK_SIZE, -1):
  38. for col in range(COLUMNS):
  39. x = col * BLOCK_SIZE
  40. if saturated(x + a, y) and saturated(x + b, y):
  41. #print('found bottom in column', col)
  42. return y + 1 - DETECT_COLUMN_OFFSET_Y + COLUMN_VSHIFT[col]
  43. def detect_block_type(board, x, y):
  44. h, s, v = board.getpixel((x + DETECT_BASIC_X,
  45. y + DETECT_BASIC_Y))
  46. # check for basic blocks first, use saturation filter to avoid confusing
  47. # green blocks with background
  48. if s >= MIN_BASIC_SAT:
  49. for ty, hexpect in enumerate(BASIC_HUES):
  50. if is_hue(h, hexpect):
  51. return ty
  52. # if no basic block is detected, check another pixel for bomb contents
  53. h, s, v = board.getpixel((x + DETECT_BOMB_X,
  54. y + DETECT_BOMB_Y))
  55. for ty, hexpect in enumerate(BOMB_HUES):
  56. if is_hue(h, hexpect):
  57. return ty + BOMB_OFFSET
  58. # no basic block or bomb -> empty slot
  59. return NONE
  60. def detect_blocks(board):
  61. maxy = detect_columns(board) - BLOCK_SIZE
  62. for y in range(maxy, 0, -BLOCK_SIZE):
  63. for col in range(COLUMNS):
  64. x = col * BLOCK_SIZE
  65. yield detect_block_type(board, x, y + COLUMN_VSHIFT[col])
  66. def detect_exa(board):
  67. for col in range(COLUMNS):
  68. x = col * BLOCK_SIZE + DETECT_EXA_X
  69. y = DETECT_EXA_Y + COLUMN_VSHIFT[col]
  70. h, s, v = board.getpixel((x, y))
  71. if is_hue(h, EXA_HUE) and v >= EXA_MIN_VAL:
  72. return col
  73. def detect_held(board, exa):
  74. if exa is not None:
  75. x = exa * BLOCK_SIZE + DETECT_EXA_LIGHT_X
  76. y = DETECT_EXA_LIGHT_Y + COLUMN_VSHIFT[exa]
  77. h, s, v = board.getpixel((x, y))
  78. if not is_hue(h, EXA_LIGHT_HUE) or v < MIN_EXA_LIGHT_VAL:
  79. return detect_block_type(board, exa * BLOCK_SIZE, DETECT_HELD_Y)
  80. return NONE
  81. def print_board(blocks, exa, held):
  82. rows = len(blocks) // COLUMNS
  83. for row in range(rows):
  84. row = rows - row
  85. row_blocks = blocks[(row - 1) * COLUMNS:row * COLUMNS]
  86. print(' ' + ''.join('rpgby.RPGBY'[ty] for ty in row_blocks))
  87. if exa is not None:
  88. print(' ' * exa + ' |')
  89. print('-' * exa, '(', 'rpgby RPGBY'[held], ')',
  90. '-' * (COLUMNS - exa - 1), sep='')
  91. if __name__ == '__main__':
  92. from iteraction import get_exapunks_window, screenshot_board
  93. win = get_exapunks_window()
  94. win.raise_window()
  95. while True:
  96. board = screenshot_board(win)
  97. blocks = list(detect_blocks(board))
  98. exa = detect_exa(board)
  99. held = detect_held(board, exa)
  100. print('\033c', end='')
  101. print_board(blocks, exa, held)
  102. time.sleep(0.05)