bot_example.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #!/usr/bin/python3
  2. """
  3. Competitive tetris bot example
  4. """
  5. import time
  6. import random
  7. import zmq
  8. import flatbuffers
  9. import numpy as np
  10. import wire_protocol.Command
  11. import wire_protocol.CommandRequest
  12. import wire_protocol.CommandResponse
  13. import wire_protocol.CommandResponseError
  14. import game_state
  15. def dummy_next_piece_func():
  16. return 0
  17. def row_strength(field, row):
  18. strength = 0
  19. bonus = 1
  20. for col in range(field.shape[1]):
  21. if field[row][col] > 0:
  22. bonus = bonus * 2
  23. strength += bonus
  24. else:
  25. bonus = 1
  26. return strength
  27. def cell_strength(field, row, col):
  28. neighbour_count = 0
  29. for r in range(row-1, row+2):
  30. for c in range(col-1, col+2):
  31. if (r < 0 or r >= field.shape[0] or
  32. c < 0 or c >= field.shape[1]):
  33. # walls are neighbours
  34. neighbour_count += 1
  35. elif field[r][c] > 0:
  36. neighbour_count += 1
  37. if field[row][col]:
  38. return neighbour_count * row
  39. else:
  40. return -neighbour_count * row
  41. def has_top_neighbour(field, row, col):
  42. for r in range(0,row):
  43. if field[r][col] > 0:
  44. return True
  45. return False
  46. def field_heuristic(field):
  47. result = 0.0
  48. for r in range(field.shape[0]):
  49. result += row_strength(field, r)
  50. for c in range(field.shape[1]):
  51. result += cell_strength(field, r, c)
  52. for r in range(field.shape[0]):
  53. for c in range(field.shape[1]):
  54. if has_top_neighbour(field, r, c):
  55. result -= 1000.0
  56. return result
  57. class ShiftAndRotate:
  58. def __init__(self, rotate_count, col_offset, value, state):
  59. self.rotate_count = rotate_count
  60. self.col_offset = col_offset
  61. self.value = value
  62. self.state = state
  63. def shift_state(state, shift):
  64. if shift == 0:
  65. return state
  66. if shift < 0:
  67. for _ in range(abs(shift)):
  68. next_state = state.shift_left()
  69. if next_state is None:
  70. return None
  71. state = next_state
  72. else:
  73. for _ in range(shift):
  74. next_state = state.shift_right()
  75. if next_state is None:
  76. return None
  77. state = next_state
  78. return state
  79. def create_shifts_and_rotates(state):
  80. shift_and_rotates = []
  81. for rotate_count in range(5):
  82. rotate_state = state
  83. for _ in range(rotate_count):
  84. rotate_state = rotate_state.rotate()
  85. if rotate_state is None:
  86. break
  87. if rotate_state is None:
  88. continue
  89. for col_offset in range(-game_state.FIELD_WIDTH, game_state.FIELD_WIDTH+1):
  90. next_state = shift_state(rotate_state, col_offset)
  91. if next_state is not None:
  92. final_state, is_running = next_state.land().advance()
  93. if is_running:
  94. value = (field_heuristic(final_state.data.grid) +
  95. final_state.data.score*10000.0)
  96. shift_and_rotates.append(ShiftAndRotate(
  97. rotate_count,
  98. col_offset,
  99. value,
  100. final_state))
  101. return shift_and_rotates
  102. def main():
  103. context = zmq.Context()
  104. socket = context.socket(zmq.REQ)
  105. socket.connect("tcp://localhost:5555")
  106. builder = flatbuffers.Builder()
  107. wire_protocol.CommandRequest.Start(builder)
  108. wire_protocol.CommandRequest.AddCommand(
  109. builder,
  110. wire_protocol.Command.Command.StartGame)
  111. req = wire_protocol.CommandRequest.End(builder)
  112. builder.Finish(req)
  113. socket.send(builder.Output())
  114. rsp_buf = socket.recv()
  115. rsp = wire_protocol.CommandResponse.CommandResponse.GetRootAs(rsp_buf)
  116. while True:
  117. builder = flatbuffers.Builder()
  118. wire_protocol.CommandRequest.Start(builder)
  119. wire_protocol.CommandRequest.AddCommand(
  120. builder,
  121. wire_protocol.Command.Command.GetGameState)
  122. req = wire_protocol.CommandRequest.End(builder)
  123. builder.Finish(req)
  124. socket.send(builder.Output())
  125. rsp_buf = socket.recv()
  126. rsp = wire_protocol.CommandResponse.CommandResponse.GetRootAs(rsp_buf)
  127. if rsp.Error() != wire_protocol.CommandResponseError.CommandResponseError.OK:
  128. return
  129. grid = rsp.GameState().GridAsNumpy()
  130. grid = grid.reshape((rsp.GameState().Rows(), rsp.GameState().Cols()))
  131. state = game_state.GameState()
  132. state.data = game_state.GameStateData(
  133. grid = grid,
  134. current_piece = rsp.GameState().CurrentPiece(),
  135. next_piece = rsp.GameState().NextPiece(),
  136. rotation = rsp.GameState().PieceRotation(),
  137. row = rsp.GameState().PieceRow(),
  138. col = rsp.GameState().PieceCol(),
  139. score = rsp.GameState().Score())
  140. state.next_piece_func = dummy_next_piece_func
  141. next_moves = create_shifts_and_rotates(state)
  142. if len(next_moves) > 0:
  143. best_moves = sorted(next_moves, key=lambda x: x.value, reverse=True)
  144. best_move = best_moves[0]
  145. command = wire_protocol.Command.Command.Rotate
  146. for _ in range(best_move.rotate_count):
  147. builder = flatbuffers.Builder()
  148. wire_protocol.CommandRequest.Start(builder)
  149. wire_protocol.CommandRequest.AddCommand(builder, command)
  150. req = wire_protocol.CommandRequest.End(builder)
  151. builder.Finish(req)
  152. socket.send(builder.Output())
  153. rsp_buf = socket.recv()
  154. rsp = wire_protocol.CommandResponse.CommandResponse.GetRootAs(rsp_buf)
  155. if rsp.Error() != wire_protocol.CommandResponseError.CommandResponseError.OK:
  156. return
  157. command = wire_protocol.Command.Command.ShiftRight
  158. if best_move.col_offset < 0:
  159. command = wire_protocol.Command.Command.ShiftLeft
  160. for _ in range(abs(best_move.col_offset)):
  161. builder = flatbuffers.Builder()
  162. wire_protocol.CommandRequest.Start(builder)
  163. wire_protocol.CommandRequest.AddCommand(builder, command)
  164. req = wire_protocol.CommandRequest.End(builder)
  165. builder.Finish(req)
  166. socket.send(builder.Output())
  167. rsp_buf = socket.recv()
  168. rsp = wire_protocol.CommandResponse.CommandResponse.GetRootAs(rsp_buf)
  169. if rsp.Error() != wire_protocol.CommandResponseError.CommandResponseError.OK:
  170. return
  171. if best_move.col_offset == 0:
  172. builder = flatbuffers.Builder()
  173. wire_protocol.CommandRequest.Start(builder)
  174. wire_protocol.CommandRequest.AddCommand(
  175. builder, wire_protocol.Command.Command.Down)
  176. req = wire_protocol.CommandRequest.End(builder)
  177. builder.Finish(req)
  178. socket.send(builder.Output())
  179. rsp_buf = socket.recv()
  180. rsp = wire_protocol.CommandResponse.CommandResponse.GetRootAs(rsp_buf)
  181. if (rsp.Error() != wire_protocol.CommandResponseError.CommandResponseError.OK and
  182. rsp.Error() != wire_protocol.CommandResponseError.CommandResponseError.INVALID_COMMAND):
  183. return
  184. if __name__ == "__main__":
  185. main()