|
@@ -0,0 +1,139 @@
|
|
|
|
|
+import collections
|
|
|
|
|
+import numpy as np
|
|
|
|
|
+
|
|
|
|
|
+import tetrominos
|
|
|
|
|
+
|
|
|
|
|
+FIELD_WIDTH = 10
|
|
|
|
|
+FIELD_HEIGHT = 20
|
|
|
|
|
+
|
|
|
|
|
+COMMAND_NONE = 0
|
|
|
|
|
+COMMAND_LEFT = 1
|
|
|
|
|
+COMMAND_RIGHT = 2
|
|
|
|
|
+COMMAND_ROTATE = 3
|
|
|
|
|
+
|
|
|
|
|
+def tetromino_to_field_at(tetromino, row, col):
|
|
|
|
|
+ col_offset = col + tetromino.col_offset
|
|
|
|
|
+ row_offset = row + tetromino.row_offset
|
|
|
|
|
+ if col_offset < 0 or row_offset < 0:
|
|
|
|
|
+ return None
|
|
|
|
|
+ if col_offset + tetromino.data.shape[1] > FIELD_WIDTH:
|
|
|
|
|
+ return None
|
|
|
|
|
+ if row_offset + tetromino.data.shape[0] > FIELD_HEIGHT:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ array = tetromino.data
|
|
|
|
|
+ left_zeros = np.zeros(shape=(array.shape[0], col_offset),
|
|
|
|
|
+ dtype=np.int32, order="C")
|
|
|
|
|
+ right_zeros = np.zeros(shape=(array.shape[0],
|
|
|
|
|
+ FIELD_WIDTH-col_offset-array.shape[1]),
|
|
|
|
|
+ dtype=np.int32, order="C")
|
|
|
|
|
+ array = np.concatenate((left_zeros, array, right_zeros), axis=1)
|
|
|
|
|
+
|
|
|
|
|
+ top_zeros = np.zeros(shape=(row_offset,FIELD_WIDTH),
|
|
|
|
|
+ dtype=np.int32, order="C")
|
|
|
|
|
+ bottom_zeros = np.zeros(shape=(FIELD_HEIGHT - row_offset - array.shape[0],
|
|
|
|
|
+ FIELD_WIDTH),
|
|
|
|
|
+ dtype=np.int32, order="C")
|
|
|
|
|
+ array = np.concatenate((top_zeros, array, bottom_zeros), axis=0)
|
|
|
|
|
+ return array
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+GameState = collections.namedtuple('GameState',
|
|
|
|
|
+ ['grid', 'current_piece', 'next_piece',
|
|
|
|
|
+ 'rotation', 'row', 'col'])
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def initial_game_state(current_piece, next_piece):
|
|
|
|
|
+ return GameState(grid=np.zeros(shape=(FIELD_HEIGHT,FIELD_WIDTH),
|
|
|
|
|
+ dtype=np.int32, order="C"),
|
|
|
|
|
+ current_piece=current_piece,
|
|
|
|
|
+ next_piece=next_piece,
|
|
|
|
|
+ rotation=0, row=0, col=0)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def is_game_state_valid(game_state):
|
|
|
|
|
+ tetromino_array = tetromino_to_field_at(
|
|
|
|
|
+ tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
|
|
|
|
|
+ game_state.row, game_state.col)
|
|
|
|
|
+ if tetromino_array is None:
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ total_field = np.add(game_state.grid, tetromino_array)
|
|
|
|
|
+ if np.any(np.vectorize(lambda x: x > 1)(total_field)):
|
|
|
|
|
+ return False
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def game_state_field(game_state):
|
|
|
|
|
+ tetromino_array = tetromino_to_field_at(
|
|
|
|
|
+ tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
|
|
|
|
|
+ game_state.row, game_state.col)
|
|
|
|
|
+ total_field = np.add(game_state.grid, tetromino_array)
|
|
|
|
|
+ total_field = np.add(total_field, tetromino_array)
|
|
|
|
|
+ return total_field
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def advance_game_state_shift(game_state, col_offset):
|
|
|
|
|
+ next_game_state = GameState(grid=game_state.grid,
|
|
|
|
|
+ current_piece=game_state.current_piece,
|
|
|
|
|
+ next_piece=game_state.next_piece,
|
|
|
|
|
+ rotation=game_state.rotation,
|
|
|
|
|
+ row=game_state.row,
|
|
|
|
|
+ col=game_state.col + col_offset)
|
|
|
|
|
+ if is_game_state_valid(next_game_state):
|
|
|
|
|
+ return next_game_state
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def advance_game_state_rotate(game_state):
|
|
|
|
|
+ next_game_state = GameState(grid=game_state.grid,
|
|
|
|
|
+ current_piece=game_state.current_piece,
|
|
|
|
|
+ next_piece=game_state.next_piece,
|
|
|
|
|
+ rotation=(game_state.rotation + 1) % 4,
|
|
|
|
|
+ row=game_state.row,
|
|
|
|
|
+ col=game_state.col)
|
|
|
|
|
+ if is_game_state_valid(next_game_state):
|
|
|
|
|
+ return next_game_state
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def advance_game_state_down(game_state):
|
|
|
|
|
+ next_game_state = GameState(grid=game_state.grid,
|
|
|
|
|
+ current_piece=game_state.current_piece,
|
|
|
|
|
+ next_piece=game_state.next_piece,
|
|
|
|
|
+ rotation=game_state.rotation,
|
|
|
|
|
+ row=game_state.row + 1,
|
|
|
|
|
+ col=game_state.col)
|
|
|
|
|
+ if is_game_state_valid(next_game_state):
|
|
|
|
|
+ return next_game_state
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def advance_game_state_piece(game_state, next_piece):
|
|
|
|
|
+ tetromino_array = tetromino_to_field_at(
|
|
|
|
|
+ tetrominos.SHAPES[game_state.current_piece][game_state.rotation],
|
|
|
|
|
+ game_state.row, game_state.col)
|
|
|
|
|
+ next_grid = np.add(game_state.grid, tetromino_array)
|
|
|
|
|
+ next_game_state = GameState(grid=next_grid,
|
|
|
|
|
+ current_piece=game_state.next_piece,
|
|
|
|
|
+ next_piece=next_piece,
|
|
|
|
|
+ rotation=0, row=0, col=0)
|
|
|
|
|
+ return next_game_state
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def advance_game_state(game_state, command):
|
|
|
|
|
+ command_game_state = None
|
|
|
|
|
+ if command == COMMAND_LEFT:
|
|
|
|
|
+ command_game_state = advance_game_state_shift(game_state, -1)
|
|
|
|
|
+ elif command == COMMAND_RIGHT:
|
|
|
|
|
+ command_game_state = advance_game_state_shift(game_state, 1)
|
|
|
|
|
+ elif command == COMMAND_ROTATE:
|
|
|
|
|
+ command_game_state = advance_game_state_rotate(game_state)
|
|
|
|
|
+
|
|
|
|
|
+ if command_game_state is None:
|
|
|
|
|
+ command_game_state = game_state
|
|
|
|
|
+
|
|
|
|
|
+ next_game_state = advance_game_state_down(command_game_state)
|
|
|
|
|
+ if next_game_state is None:
|
|
|
|
|
+ next_game_state = advance_game_state_piece(command_game_state, 0)
|
|
|
|
|
+ return next_game_state
|