diff --git a/main.py b/main.py new file mode 100644 index 0000000..19df049 --- /dev/null +++ b/main.py @@ -0,0 +1,31 @@ +from src.game.board import Board +from src.agents.heuristic import * + +def test_heuristic(): + board = Board() + board.board =\ + [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] + + print(aggregate_heights(board)) + print(max_height(board)) + +test_heuristic() \ No newline at end of file diff --git a/src/agents/heuristic.py b/src/agents/heuristic.py index 22b8b43..88080ef 100644 --- a/src/agents/heuristic.py +++ b/src/agents/heuristic.py @@ -14,24 +14,15 @@ def aggregate_heights(gameState: Board) -> int: for j in range(gameState.columns): if gameState.board[i][j] > 0: if checkedList[j] == 0: - checkedList[j] = gameState.rows - i+1 + checkedList[j] = gameState.rows - i return sum(checkedList) - - - -if __name__ == "__main__": - board = Board() - board.board =\ - [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] - - assert aggregate_heights(board) == 27 \ No newline at end of file +def max_height(gameState: Board) -> int: + """ Returns the maximum height of the columns in the game state. """ + checkedList = [0 for i in range(gameState.columns)] + for i in range(gameState.rows): + for j in range(gameState.columns): + if gameState.board[i][j] > 0: + if checkedList[j] == 0: + checkedList[j] = gameState.rows - i + return max(checkedList) \ No newline at end of file diff --git a/src/game/block.py b/src/game/block.py index 5283b9e..7599ed3 100644 --- a/src/game/block.py +++ b/src/game/block.py @@ -44,7 +44,7 @@ def setCoordinates(self, x, y): def rotateLeft(self, undo: bool = False): if not undo: - self.rotation = (self.rotation - 1) % len(self.figures[self.type]) + self.rotation = (self.rotation - 1) % len(self.figures[self.type]) else: self.rotateRight() diff --git a/src/game/board.py b/src/game/board.py index 94245b5..86344fd 100644 --- a/src/game/board.py +++ b/src/game/board.py @@ -72,7 +72,7 @@ def checkCharacter(self, character): def rotateBlockRight(self): - if self.validMove(self.block.rotateRight): + if self.validRotation(self.block.rotateRight): self.placeBlock() @@ -110,12 +110,30 @@ def blockLanded(self): pass - def validMove(self, simulateimulatedMove: Callable): + def validMove(self, simulatedMove): # if simulated move fails = move out of bounds and should be disallowed - simulateimulatedMove() + block_indices = [i for i in range(16) if i in self.block.image()] - for row in range(4, 1, -1): - for column in range(4, 1, -1): + moving_direction = [0, 0] + moving_direction[0] = 1 if simulatedMove == self.block.moveRight else -1 if simulatedMove == self.block.moveLeft else 0 + moving_direction[1] = 1 if simulatedMove == self.block.moveDown else 0 + + for index in block_indices: + print(self.block.y + (index // 4) + moving_direction[1], self.rows - 1) + print(self.block.x + (index % 4) + moving_direction[0], self.columns - 1) + if ( + self.block.y + (index // 4) + moving_direction[1] < 0 or + self.block.y + (index // 4) + moving_direction[1] > self.rows - 2 or + self.block.x + (index % 4) + moving_direction[0] < 0 or + self.block.x + (index % 4) + moving_direction[0] > self.columns - 2 + ): + + return False + + simulatedMove() + + for row in range(4): + for column in range(4): if row * 4 + column in self.block.image(): if ( row + self.block.y > self.rows - 1 or @@ -124,11 +142,46 @@ def validMove(self, simulateimulatedMove: Callable): column + self.block.x < 0 or self.prevBoard[row + self.block.y][column + self.block.x] > 0 ): - simulateimulatedMove(Undo = True) + simulatedMove(Undo = True) return False return True # Return True if the move is valid + def validRotation(self, simulatedRotation): + # if simulated move fails = move out of bounds and should be disallowed + block_indices = [i for i in range(16) if i in self.block.image()] + rotation = 1 if simulatedRotation.__name__ == 'rotateRight' else -1 if simulatedRotation.__name__ == 'rotateLeft' else 0 + new_block_indices = self.figures[self.type][(self.rotation + rotation) % 4] + + # TODO: Implement valid rotation check similar to validMove + # Should push the block to closest valid position for the rotation in a given radius (but not able to go through walls) + + + for index in block_indices: + if ( + self.block.y + (index // 4) < 0 or + self.block.y + (index // 4) > self.rows - 2 or + self.block.x + (index % 4) < 0 or + self.block.x + (index % 4) > self.columns - 2 + ): + return False + + simulatedRotation() + + for row in range(4): + for column in range(4): + if row * 4 + column in self.block.image(): + if ( + row + self.block.y > self.rows - 1 or + row + self.block.y < 0 or + column + self.block.x > self.columns - 1 or + column + self.block.x < 0 or + self.prevBoard[row + self.block.y][column + self.block.x] > 0 + ): + simulatedRotation(Undo = True) + return False + return True + def clearRow(self, rownumber): # Fjerner den angitte raden og legger til en ny tom rad ved bunnen av matrisen newMatrix = self.board[:rownumber] + self.board[rownumber+1:] diff --git a/test/agents/test_heuristic.py b/test/agents/test_heuristic.py new file mode 100644 index 0000000..0bd6551 --- /dev/null +++ b/test/agents/test_heuristic.py @@ -0,0 +1,28 @@ +from src.game.board import Board +from src.agents.heuristic import aggregate_heights + +def test_heuristic(): + board = Board() + board.board =\ + [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] + + assert aggregate_heights(board) == 27 \ No newline at end of file