<jupyter_start><jupyter_text>Setup We require similar modules to the last project.<jupyter_code>import os
import re
import time

from IPython.display import clear_output<jupyter_output><empty_output><jupyter_text>RLE  File Reader I've started by creating a function to read a RLE file and return a 2D list of Booleans to represent the initial status of each cell.<jupyter_code>def read_rle(path, width, height, x_offset, y_offset):
    """
    Read a RLE file and return a 2D Boolean list.

    Args:
        path (str): Path to the RLE file
        width (int): The desired width of the grid
        height (int): The desired width of the grid
        x_offset (int): The horizontal offset the pattern
        y_offset (int): The horizontal offset the pattern

    Returns:
        grid (2D Boolean list): The initial game state

    Raises:
        ValueError: If the pattern cannot fit on the grid
    """
    # default to dead
    grid = [[False for j in range(width)]
            for i in range(height)]
    with open(path) as f:
        lines = f.readlines()
        # skip comment lines
        n = 0
        comments_finished = False
        while not comments_finished:
            if lines[n][0] != '#':
                comments_finished = True
                break
            n += 1
        # read header
        header = lines[n]
        x = int(re.search(r'x = (\d+)', header).group(1))
        y = int(re.search(r'y = (\d+)', header).group(1))
        
        # check that pattern can fit on grid
        if x_offset + x >= width or y_offset + y >= height:
            raise ValueError("pattern can't fit on grid")
        
        # read pattern
        i = 0
        j = 0
        multiplier = 1
        pattern_complete = False
        for l in lines[n+1:]:
            for c in l:
                if c.isnumeric():
                    multiplier = int(c)
                elif c == '$':
                    i += multiplier
                    j = 0
                    multiplier = 1
                elif c == '!':
                    pattern_complete = True
                    break
                elif c in ('b', 'o'):
                    alive = c == 'o'
                    for m in range(multiplier):
                        grid[i + x_offset][j + y_offset] = alive
                        j += 1
                    multiplier = 1
            if pattern_complete:
                break
    return grid<jupyter_output><empty_output><jupyter_text>Grid Updater<jupyter_code>def update_grid(grid, wrap=True):
    """
    Update a grid by passing through one time step.

    Args:
        grid (2D Boolean list): The grid to update
        wrap (bool): Whether to wrap the grid

    Returns:
        grid (2D Boolean list): The new game state
    """
    width = len(grid[0])
    height = len(grid)
    new_grid = [[None for j in range(height)]
                for i in range(width)]
    for i in range(height):
        for j in range(width):
            n_neighbours = 0
            for x_offset in (-1, 0, 1):
                for y_offset in (-1, 0, 1):
                    n_i = i + y_offset
                    n_j = j + x_offset
                    if wrap:
                        n_neighbours += grid[n_i % height][n_j % width]
                    else:
                        if not 0 <= n_i < height or not 0 <= n_j < width:
                            continue
                        n_neighbours += grid[n_i][n_j]
            # avoid counting self
            n_neighbours -= grid[i][j]
            if n_neighbours <= 1 or n_neighbours >= 4:
                new_grid[i][j] = False
            elif n_neighbours == 3:
                new_grid[i][j] = True
            else:
                new_grid[i][j] = grid[i][j]
    return new_grid<jupyter_output><empty_output><jupyter_text>Rendering<jupyter_code>def draw_grid(grid):
    """Pretty-print a grid."""
    for row in grid:
        print(*['#' if cell else '.' for cell in row], sep='')<jupyter_output><empty_output><jupyter_text>Run Game<jupyter_code>grid = read_rle('glider.rle', 10, 10, 1, 2)
num_iter = 100
for i in range(num_iter):
    clear_output(wait=True)
    draw_grid(grid)
    grid = update_grid(grid)
    time.sleep(0.1)
grid = read_rle('pulsar.rle', 15, 15, 1, 1)
num_iter = 100
for i in range(num_iter):
    clear_output(wait=True)
    draw_grid(grid)
    grid = update_grid(grid, wrap=False)
    time.sleep(0.1)<jupyter_output>...............
...###...###...
...............
.#....#.#....#.
.#....#.#....#.
.#....#.#....#.
...###...###...
...............
...###...###...
.#....#.#....#.
.#....#.#....#.
.#....#.#....#.
...............
...###...###...
...............
{'fraction_non_alphanumeric': 0.14004282655246253, 'fraction_numerical': 0.011349036402569594, 'mean_word_length': 1.5289658906334596, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '335676', 'license': 'MIT', 'n_tokens_mistral': 1481, 'n_tokens_neox': 1390, 'n_words': 422, 'path': 'session_three/session_three_project_solutions.ipynb', 'repo_name': 'THargreaves/practical-python', 'size': '4670'}