game of life screensaver

environment setup

{ pkgs ? import <nixpkgs> {} }:
  pkgs.mkShell {
  # nativeBuildInputs is usually what you want -- tools you need to run
	buildInputs = with pkgs.buildPackages; [
	  python3
	  python312Packages.pygame
	  python312Packages.numpy
	];

	buildPhase = ''
	'';

	installPhrase = ''
	'';

	shellHook = ''
	  python3.12 game_of_life.py
	'';
  }

script

import pygame
import numpy as np
import time

def update(grid):
        new_grid = np.copy(grid)
        for i in range(grid.shape[0]):
                for j in range(grid.shape[1]):
                        total_neighbors = int((grid[i, (j-1)%grid.shape[1]] + grid[i, (j+1)%grid.shape[1]] +
                                                                 grid[(i-1)%grid.shape[0], j] + grid[(i+1)%grid.shape[0], j] +
                                                                 grid[(i-1)%grid.shape[0], (j-1)%grid.shape[1]] + grid[(i-1)%grid.shape[0], (j+1)%grid.shape[1]] +
                                                                 grid[(i+1)%grid.shape[0], (j-1)%grid.shape[1]] + grid[(i+1)%grid.shape[0], (j+1)%grid.shape[1]])/255)
                        if grid[i, j] == 255:
                                if (total_neighbors < 2) or (total_neighbors > 3):
                                        new_grid[i, j] = 0
                        else:
                                if total_neighbors == 3:
                                        new_grid[i, j] = 255
        return new_grid

def main():
        screen_width, screen_height = 5120, 1440
        cell_size = 10

        pygame.init()
        screen = pygame.display.set_mode((screen_width, screen_height))
        pygame.display.set_caption("Conway's Game of Life")
        clock = pygame.time.Clock()

        grid_width, grid_height = screen_width // cell_size, screen_height // cell_size
        grid = np.random.choice([0, 255], grid_width * grid_height, p=[0.95, 0.05]).reshape(grid_height, grid_width)

        while True:
                for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                                pygame.quit()
                                return

                grid = update(grid)

                screen.fill((0, 0, 0))
                for i in range(grid.shape[0]):
                        for j in range(grid.shape[1]):
                                if grid[i, j] == 255:
                                        pygame.draw.rect(screen, (255, 255, 255), (j*cell_size, i*cell_size, cell_size, cell_size))

                pygame.display.update()
                clock.tick(10)

if __name__ == "__main__":
        main()

load environment and run

  nix-shell game_of_life_screensaver.nix