game.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import collections
  2. import numpy as np
  3. import tetrominos
  4. FIELD_WIDTH = 10
  5. FIELD_HEIGHT = 20
  6. COMMAND_NONE = 0
  7. COMMAND_LEFT = 1
  8. COMMAND_RIGHT = 2
  9. COMMAND_ROTATE = 3
  10. def tetromino_to_field_at(tetromino, row, col):
  11. col_offset = col + tetromino.col_offset
  12. row_offset = row + tetromino.row_offset
  13. if col_offset < 0 or row_offset < 0:
  14. return None
  15. if col_offset + tetromino.data.shape[1] > FIELD_WIDTH:
  16. return None
  17. if row_offset + tetromino.data.shape[0] > FIELD_HEIGHT:
  18. return None
  19. array = tetromino.data
  20. left_zeros = np.zeros(shape=(array.shape[0], col_offset),
  21. dtype=np.int32, order="C")
  22. right_zeros = np.zeros(shape=(array.shape[0],
  23. FIELD_WIDTH-col_offset-array.shape[1]),
  24. dtype=np.int32, order="C")
  25. array = np.concatenate((left_zeros, array, right_zeros), axis=1)
  26. top_zeros = np.zeros(shape=(row_offset,FIELD_WIDTH),
  27. dtype=np.int32, order="C")
  28. bottom_zeros = np.zeros(shape=(FIELD_HEIGHT - row_offset - array.shape[0],
  29. FIELD_WIDTH),
  30. dtype=np.int32, order="C")
  31. array = np.concatenate((top_zeros, array, bottom_zeros), axis=0)
  32. return array
  33. GameState = collections.namedtuple('GameState',
  34. ['grid', 'current_piece', 'next_piece',
  35. 'rotation', 'row', 'col', 'score'])
  36. def initial_game_state(current_piece, next_piece):
  37. return GameState(grid=np.zeros(shape=(FIELD_HEIGHT,FIELD_WIDTH),
  38. dtype=np.int32, order="C"),
  39. current_piece=current_piece,
  40. next_piece=next_piece,
  41. rotation=0, row=0, col=0, score=0)
  42. def is_game_state_valid(game_state):
  43. tetromino_array = tetromino_to_field_at(
  44. tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
  45. game_state.row, game_state.col)
  46. if tetromino_array is None:
  47. return False
  48. total_field = np.add(game_state.grid, tetromino_array)
  49. if np.any(np.vectorize(lambda x: x > 1)(total_field)):
  50. return False
  51. return True
  52. def get_game_state_field(game_state):
  53. tetromino_array = tetromino_to_field_at(
  54. tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
  55. game_state.row, game_state.col)
  56. total_field = np.add(game_state.grid, tetromino_array)
  57. total_field = np.add(total_field, tetromino_array)
  58. return total_field
  59. def game_state_shift(game_state, col_offset):
  60. next_game_state = GameState(grid=game_state.grid,
  61. current_piece=game_state.current_piece,
  62. next_piece=game_state.next_piece,
  63. rotation=game_state.rotation,
  64. row=game_state.row,
  65. col=game_state.col + col_offset,
  66. score=game_state.score)
  67. if is_game_state_valid(next_game_state):
  68. return next_game_state
  69. return game_state
  70. def game_state_land(game_state):
  71. while True:
  72. next_game_state = GameState(grid=game_state.grid,
  73. current_piece=game_state.current_piece,
  74. next_piece=game_state.next_piece,
  75. rotation=game_state.rotation,
  76. row=game_state.row + 1,
  77. col=game_state.col,
  78. score=game_state.score)
  79. if is_game_state_valid(next_game_state):
  80. game_state = next_game_state
  81. else:
  82. break
  83. return game_state
  84. def game_state_rotate(game_state):
  85. next_game_state = GameState(grid=game_state.grid,
  86. current_piece=game_state.current_piece,
  87. next_piece=game_state.next_piece,
  88. rotation=(game_state.rotation + 1) % 4,
  89. row=game_state.row,
  90. col=game_state.col,
  91. score=game_state.score)
  92. if is_game_state_valid(next_game_state):
  93. return next_game_state
  94. return game_state
  95. def advance_game_state_down(game_state):
  96. next_game_state = GameState(grid=game_state.grid,
  97. current_piece=game_state.current_piece,
  98. next_piece=game_state.next_piece,
  99. rotation=game_state.rotation,
  100. row=game_state.row + 1,
  101. col=game_state.col,
  102. score=game_state.score)
  103. if is_game_state_valid(next_game_state):
  104. return next_game_state
  105. return None
  106. def advance_game_state_piece(game_state, next_piece):
  107. tetromino_array = tetromino_to_field_at(
  108. tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
  109. game_state.row, game_state.col)
  110. next_grid = np.add(game_state.grid, tetromino_array)
  111. next_game_state = GameState(grid=next_grid,
  112. current_piece=game_state.next_piece,
  113. next_piece=next_piece,
  114. rotation=0, row=0, col=0,
  115. score=game_state.score)
  116. return next_game_state
  117. def advance_game_state_purge_lines(game_state):
  118. next_grid_row = FIELD_HEIGHT-1
  119. next_grid = np.zeros(shape=(FIELD_HEIGHT,FIELD_WIDTH),
  120. dtype=np.int32, order="C")
  121. next_score = game_state.score
  122. for row in range(FIELD_HEIGHT-1, -1,-1):
  123. if np.all(game_state.grid[row,:]):
  124. next_score += 1
  125. else:
  126. next_grid[next_grid_row,:] = game_state.grid[row,:]
  127. next_grid_row -= 1
  128. next_game_state = GameState(grid=next_grid,
  129. current_piece=game_state.current_piece,
  130. next_piece=game_state.next_piece,
  131. rotation=game_state.rotation,
  132. row=game_state.row,
  133. col=game_state.col,
  134. score=next_score)
  135. return next_game_state
  136. def advance_game_state(game_state, next_piece_func):
  137. next_game_state = advance_game_state_down(game_state)
  138. is_game_running = True
  139. if next_game_state is None:
  140. next_game_state = advance_game_state_piece(game_state, next_piece_func())
  141. next_game_state = advance_game_state_purge_lines(next_game_state)
  142. if not is_game_state_valid(next_game_state):
  143. is_game_running = False
  144. if not is_game_running:
  145. return game_state, False
  146. return next_game_state, True