Skip to content

Commit

Permalink
feat: implement block placement logic and game over logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
SverreNystad committed Apr 10, 2024
1 parent ea1ff56 commit c3a4c4e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 28 deletions.
67 changes: 42 additions & 25 deletions src/game/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ class Board:

ROWS = 20
COLUMNS = 10
START_X = 3
START_Y = 0

def __init__(self, board=None, block=None):
def __init__(self, board: list[list[int]] = None, block: Block = None):
"""
Initializes a new game board instance, setting up an empty board, placing the first block, and selecting the next block.
"""
Expand All @@ -64,14 +66,14 @@ def __init__(self, board=None, block=None):
else:
self.board = board
if block == None:
self.block = Block(3, 0, 0)
self.block = Block(self.START_X, self.START_Y, 0)
else:
self.block = block
self.prevBoard = copy.deepcopy(self.board)

self._placeBlock()

self.nextBlock = Block(0, 5, random.randint(0, 6))
self.nextBlock = Block(self.START_X, self.START_Y, random.randint(0, 6))

def _initBoard(self) -> list[list[int]]:
"""Initializes an empty the board"""
Expand Down Expand Up @@ -108,7 +110,6 @@ def doAction(self, action: Action) -> None:
case Action.HARD_DROP:
while True:
new_block.moveDown()
self.printBoard()
if not self.isValidBlockPosition(new_block):
new_block.moveUp()
break
Expand All @@ -117,10 +118,22 @@ def doAction(self, action: Action) -> None:

# Given the new block position, check if it is valid and update the board
if self.isValidBlockPosition(new_block):
print("Valid move")
self.block = new_block
self._placeBlock()

# For blocks reaching the bottom of the board, place the block and introduce a new one
if (
not self.isValidBlockPosition(new_block)
and action == Action.SOFT_DROP
or action == Action.HARD_DROP
):
self._placeBlock()
self._checkGameOver()
# Store the previous board state before the new block placement
self.prevBoard = copy.deepcopy(self.board)
self._checkForFullRows()
self._shiftToNewBlock()

def isValidBlockPosition(self, block: Block) -> bool:
"""
Checks if the given block's position is valid (not out of bounds, not intersecting with existing blocks, and not causing a game over).
Expand Down Expand Up @@ -194,41 +207,45 @@ def _placeBlock(self):
def _shiftToNewBlock(self):
"""Places the current block on the board and sets the next block as the current block"""
self.block = self.nextBlock
self.nextBlock = Block(0, 5, random.randint(0, 6))
self.nextBlock = Block(self.START_X, self.START_Y, random.randint(0, 6))
for i in range(4):
for j in range(4):
if i * 4 + j in self.block.image():
self.board[i + self.block.y][
j + self.block.x
] = 1 # self.block.color

def _checkGameState(self) -> int:
def _checkGameOver(self):
"""Checks if the game is over"""
for cell in self.board[0]:
if cell > 0:
self.gameOver = True
break

def _checkForFullRows(self) -> int:
"""Checks the board for full rows and removes them, returning the number of rows removed"""
amount = 0
fullRows = []

for rowIndex, row in enumerate(
self.board
): # Itererer over matrisen for å finne fulle rader
if 0 not in row: # Sjekker om raden er full
fullRows.append(
rowIndex
) # Legger til indeksen til listen over fulle rader
for rowIndex in reversed(
fullRows
): # Går gjennom listen over fulle rader i reversert rekkefølge for å fjerne dem
self._clearRow(rowIndex) # Fjerner raden basert på dens indeks
amount += 1 # Øker telleren for antall fjernede rader
return amount # Returnerer totalt antall fjernede rader
# Find all full rows
for rowIndex, row in enumerate(self.board):
# Check if the row is full
if 0 not in row:
fullRows.append(rowIndex)
# Remove all full rows
for rowIndex in reversed(fullRows):
self._clearRow(rowIndex)
amount += 1
return amount

def _clearRow(self, rownumber: int):
"""Clears the specified row and moves all rows above down one step"""
# Fjerner den angitte raden og legger til en ny tom rad ved bunnen av matrisen
# Remove the row and add a new empty row at the top
newMatrix = self.board[:rownumber] + self.board[rownumber + 1 :]
newMatrix.append([0 for _ in range(self.COLUMNS)])
self.board = newMatrix # Oppdaterer matrisen med den nye matrisen
self.rowsRemoved += 1 # Oppdaterer antall fjernede rader
self.board = newMatrix
self.rowsRemoved += 1

def getPossibleMoves(self) -> list["Board"]:
def getPossibleBoards(self) -> list["Board"]:
possibleMoves = []

# Number of rotations which gives unique block positions
Expand Down
7 changes: 4 additions & 3 deletions test/game/test_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_clear_row():
]
lines_to_remove = 1
board.printBoard()
rows_removed = board._checkGameState()
rows_removed = board._checkForFullRows()
board.printBoard()
for expected_row, board_row in zip(expected_board, board.board):
assert expected_row == board_row
Expand Down Expand Up @@ -125,7 +125,7 @@ def test_clear_rows():
]
lines_to_remove = 3
board.printBoard()
rows_removed = board._checkGameState()
rows_removed = board._checkForFullRows()
board.printBoard()
for expected_row, board_row in zip(expected_board, board.board):
assert expected_row == board_row
Expand Down Expand Up @@ -159,7 +159,7 @@ def test_do_not_clear_not_full_row():
]
lines_to_remove = 0
board.printBoard()
rows_removed = board._checkGameState()
rows_removed = board._checkForFullRows()
board.printBoard()

assert rows_removed == lines_to_remove
Expand Down Expand Up @@ -192,6 +192,7 @@ def test_transition_model_complex_target():
Action.MOVE_RIGHT,
Action.MOVE_RIGHT,
Action.MOVE_RIGHT,
Action.HARD_DROP,
]
for action in actual_actions:
target_board.doAction(action)
Expand Down

0 comments on commit c3a4c4e

Please sign in to comment.