Expand upon this code and add a scoreboard function and make the game infinite doesn't stop

import pygame
import random

# Initialize pygame
pygame.init()

# Screen dimensions
SCREEN_WIDTH = 300
SCREEN_HEIGHT = 600
BLOCK_SIZE = 30
GRID_WIDTH = SCREEN_WIDTH // BLOCK_SIZE
GRID_HEIGHT = SCREEN_HEIGHT // BLOCK_SIZE

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)
COLORS = [
    (0, 255, 255),   # Cyan
    (255, 255, 0),   # Yellow
    (255, 165, 0),   # Orange
    (0, 0, 255),     # Blue
    (0, 255, 0),     # Green
    (255, 0, 0),     # Red
    (128, 0, 128)    # Purple
]

# Tetrimino shapes
SHAPES = [
    [[1, 1, 1, 1]],  # I
    [[1, 1], [1, 1]],  # O
    [[0, 1, 0], [1, 1, 1]],  # T
    [[1, 0, 0], [1, 1, 1]],  # L
    [[0, 0, 1], [1, 1, 1]],  # J
    [[1, 1, 0], [0, 1, 1]],  # S
    [[0, 1, 1], [1, 1, 0]],  # Z
]

# Shape class
class Shape:
    def __init__(self, shape, color):
        self.shape = shape
        self.color = color
        self.x = GRID_WIDTH // 2 - len(shape[0]) // 2
        self.y = 0

    def rotate(self):
        self.shape = [list(row) for row in zip(*reversed(self.shape))]

# Create the grid
def create_grid(locked_positions={}):
    grid = [[BLACK for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if (x, y) in locked_positions:
                grid[y][x] = locked_positions[(x, y)]

    return grid

# Check if a position is valid
def valid_space(shape, grid):
    for y, row in enumerate(shape.shape):
        for x, cell in enumerate(row):
            if cell:
                if x + shape.x < 0 or x + shape.x >= GRID_WIDTH or y + shape.y >= GRID_HEIGHT:
                    return False
                if grid[y + shape.y][x + shape.x] != BLACK:
                    return False
    return True

# Check if a row is full
def check_rows(grid, locked_positions):
    rows_cleared = 0
    for y in range(GRID_HEIGHT - 1, -1, -1):
        if BLACK not in grid[y]:
            rows_cleared += 1
            del_row(y, grid, locked_positions)
    return rows_cleared

# Delete a full row and shift others down
def del_row(row, grid, locked_positions):
    for y in range(row, 0, -1):
        for x in range(GRID_WIDTH):
            grid[y][x] = grid[y - 1][x]
            if (x, y - 1) in locked_positions:
                locked_positions[(x, y)] = locked_positions.pop((x, y - 1))
    for x in range(GRID_WIDTH):
        grid[0][x] = BLACK

# Get a new random shape
def get_new_shape():
    shape = random.choice(SHAPES)
    color = random.choice(COLORS)
    return Shape(shape, color)

# Main game loop
def main():
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption('Tetris')

    clock = pygame.time.Clock()
    fall_time = 0
    fall_speed = 0.3  # Speed at which pieces fall

    locked_positions = {}
    grid = create_grid(locked_positions)

    current_shape = get_new_shape()
    next_shape = get_new_shape()

    score = 0
    game_over = False

    while not game_over:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Piece falling logic
        if fall_time / 1000 >= fall_speed:
            current_shape.y += 1
            if not valid_space(current_shape, grid):
                current_shape.y -= 1
                for y, row in enumerate(current_shape.shape):
                    for x, cell in enumerate(row):
                        if cell:
                            locked_positions[(x + current_shape.x, y + current_shape.y)] = current_shape.color
                current_shape = next_shape
                next_shape = get_new_shape()
                if not valid_space(current_shape, grid):
                    game_over = True
            fall_time = 0

        # Check for player inputs
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_shape.x -= 1
                    if not valid_space(current_shape, grid):
                        current_shape.x += 1
                elif event.key == pygame.K_RIGHT:
                    current_shape.x += 1
                    if not valid_space(current_shape, grid):
                        current_shape.x -= 1
                elif event.key == pygame.K_DOWN:
                    current_shape.y += 1
                    if not valid_space(current_shape, grid):
                        current_shape.y -= 1
                elif event.key == pygame.K_UP:
                    current_shape.rotate()
                    if not valid_space(current_shape, grid):
                        current_shape.rotate()  # Rotate back if not valid

        # Clear rows and update score
        rows_cleared = check_rows(grid, locked_positions)
        if rows_cleared > 0:
            score += rows_cleared * 10

        # Draw grid and current shape
        screen.fill(BLACK)
        draw_grid(screen, grid)

        for y, row in enumerate(current_shape.shape):
            for x, cell in enumerate(row):
                if cell:
                    pygame.draw.rect(screen, current_shape.color, (current_shape.x * BLOCK_SIZE + x * BLOCK_SIZE,
                                                                   current_shape.y * BLOCK_SIZE + y * BLOCK_SIZE,
                                                                   BLOCK_SIZE, BLOCK_SIZE), 0)

        pygame.display.update()

    pygame.quit()

# Draw the grid on the screen
def draw_grid(surface, grid):
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            pygame.draw.rect(surface, grid[y][x], (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 0)
    draw_grid_lines(surface)

# Draw grid lines
def draw_grid_lines(surface):
    for x in range(GRID_WIDTH):
        pygame.draw.line(surface, GRAY, (x * BLOCK_SIZE, 0), (x * BLOCK_SIZE, SCREEN_HEIGHT))
    for y in range(GRID_HEIGHT):
        pygame.draw.line(surface, GRAY, (0, y * BLOCK_SIZE), (SCREEN_WIDTH, y * BLOCK_SIZE))

if __name__ == "__main__":
    main()