Help for conway.view_game_of_life

Sample CLI

gway conway view-game-of-life

Full Code

def view_game_of_life(
    *args,
    action=None,
    board=None,
    toggle_x=None,
    toggle_y=None,
    **kwargs
):
    # 1. Load the current board
    msg = ""
    current_board = load_board()

    # 2. Handle form board (from hidden input)
    if board:
        try:
            new_board = [
                [int(cell) for cell in row.split(",")]
                for row in board.strip().split(";")
            ]
            current_board = new_board
        except Exception:
            msg = "Failed to parse board!"

    # 3. Action handlers
    if action == "random":
        current_board = _random_board()
    elif action == "clear":
        current_board = _new_board()
    elif action == "step":
        current_board = next_generation(current_board)
    elif action == "toggle":
        x = int(toggle_x) if toggle_x is not None else -1
        y = int(toggle_y) if toggle_y is not None else -1
        if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE:
            current_board[x][y] = 0 if current_board[x][y] else 1
        save_board(current_board)
        return redirect("/conway/game-of-life")  # POST-redirect-GET

    # 4. Always save board for step/random/clear (toggle already saved above)
    if action in ("step", "random", "clear"):
        save_board(current_board)

    # 5. Prepare HTML board
    html_board = ""
    for x, row in enumerate(current_board):
        row_html = "".join(
            f'<td class="cell cell-{cell}" data-x="{x}" data-y="{y}"></td>'
            for y, cell in enumerate(row)
        )
        html_board += f"<tr>{row_html}</tr>"

    flat_board = ";".join(",".join(str(cell) for cell in row) for row in current_board)

    # 6. Get last modified date of board file
    last_mod = None
    if os.path.exists(BOARD_FILE):
        last_mod = datetime.fromtimestamp(os.path.getmtime(BOARD_FILE)).strftime("%Y-%m-%d %H:%M:%S")

    ICONS = {
        "step": '<svg viewBox="0 0 20 20"><polyline points="5,3 15,10 5,17" fill="none" stroke="currentColor" stroke-width="2"/></svg>',
        "random": '<svg viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="10" cy="10" r="3" fill="currentColor"/></svg>',
        "clear": '<svg viewBox="0 0 20 20"><rect x="4" y="4" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2"/><line x1="6" y1="6" x2="14" y2="14" stroke="currentColor" stroke-width="2"/><line x1="14" y1="6" x2="6" y2="14" stroke="currentColor" stroke-width="2"/></svg>',
        "download": '<svg viewBox="0 0 20 20"><path d="M10 3v10m0 0l-4-4m4 4l4-4M3 17h14" fill="none" stroke="currentColor" stroke-width="2"/></svg>',
    }

    return f"""
    <h1>Conway's Game of Life</h1>
    <div>
        <form id="lifeform" method="post" class="game-actions" autocomplete="off" style="margin-bottom:8px;">
            <input type="hidden" name="board" id="boarddata" value="{html.escape(flat_board)}" />
            <button type="submit" name="action" value="step">{ICONS['step']} Step Forward</button>
            <button type="submit" name="action" value="random">{ICONS['random']} Random</button>
            <button type="submit" name="action" value="clear">{ICONS['clear']} Clear</button>
            <a href="/shared/conway.txt" download class="button">{ICONS['download']} Download</a>
        </form>
        <p style="color:#aa2222">{html.escape(msg)}</p>
        <table id="gameboard" class="game-board">{html_board}</table>
        <div style="margin-top:0.8em;color:#888;font-size:0.96em">
            Last updated: {last_mod or "Never"}
        </div>
    </div>
    """