Skip to content

Instantly share code, notes, and snippets.

@paigeadelethompson
Created May 25, 2026 01:19
Show Gist options
  • Select an option

  • Save paigeadelethompson/bb33089de4250d62c7d2821dbf034181 to your computer and use it in GitHub Desktop.

Select an option

Save paigeadelethompson/bb33089de4250d62c7d2821dbf034181 to your computer and use it in GitHub Desktop.
;;; conway.ss - Conway's Game of Life
;;; Renders the classic cellular automaton on an infinite toroidal grid using ANSI terminal codes.
(export main)
;; Import standard utility modules
(import :std/iter ; For imperative loops (for, in-range)
:std/sugar ; Syntactic sugar additions
:std/srfi/1 ; List processing library
:std/misc/threads) ; For frame-rate limiting (thread-sleep!)
;; --- 1. CONFIGURATION ---
;; Grid size variables for the display window
(def *rows* 20)
(def *cols* 40)
;; --- 2. GRID CREATION & CORE ENGINE UTILITIES ---
(def (make-grid rows cols)
;; Allocates a fresh 2D array matrix: a top-level vector containing child vectors
(let (grid (make-vector rows))
(for (i (in-range rows))
;; Initialize every individual cell position to 0 (dead)
(vector-set! grid i (make-vector cols 0)))
grid))
(def (random-grid rows cols)
;; Generates a seed matrix where each cell has a 20% statistical chance of living
(let (grid (make-grid rows cols))
(for (r (in-range rows))
(for (c (in-range cols))
;; random-integer rolls a number from 0 to 99
(when (< (random-integer 100) 20)
(vector-set! (vector-ref grid r) c 1))))
grid))
(def (grid-ref grid r c)
;; Retrieves cell state with boundary wrapping.
;; The 'modulo' logic binds edges together so cells wrap like a donut (torus).
(let ((wrapped-r (modulo r *rows*))
(wrapped-c (modulo c *cols*)))
(vector-ref (vector-ref grid wrapped-r) wrapped-c)))
;; --- 3. GAME OF LIFE STATE LAWS ---
(def (count-neighbors grid r c)
;; Aggregates the living integer states (0 or 1) of all 8 bordering locations.
;; Uses (1- x) for subtraction and (1+ x) for addition to shift index locations.
(+ (grid-ref grid (1- r) (1- c)) (grid-ref grid (1- r) c) (grid-ref grid (1- r) (1+ c)) ; Top row offset
(grid-ref grid r (1- c)) (grid-ref grid r (1+ c)) ; Center row offset
(grid-ref grid (1+ r) (1- c)) (grid-ref grid (1+ r) c) (grid-ref grid (1+ r) (1+ c)))) ; Bottom row offset
(def (next-generation current-grid)
;; Processes and isolates the next full grid state based on the active canvas
(let (new-grid (make-grid *rows* *cols*))
(for (r (in-range *rows*))
(for (c (in-range *cols*))
(let ((neighbors (count-neighbors current-grid r c))
(alive? (= (grid-ref current-grid r c) 1)))
;; Evaluate Conway's rules using Scheme conditional branches
(cond
;; Rule 1 & 3: Overpopulation or Underpopulation causes cell failure
((and alive? (or (< neighbors 2) (> neighbors 3)))
(vector-set! (vector-ref new-grid r) c 0))
;; Rule 2: Optimal cell clustering allows life to sustain
((and alive? (or (= neighbors 2) (= neighbors 3)))
(vector-set! (vector-ref new-grid r) c 1))
;; Rule 4: Dead zone with exactly 3 neighbors sparks cell birth
((and (not alive?) (= neighbors 3))
(vector-set! (vector-ref new-grid r) c 1))
;; Baseline: Maintain existing death states if conditions aren't met
(else
(vector-set! (vector-ref new-grid r) c 0))))))
new-grid))
;; --- 4. RENDER DRIVER & RUNTIME LOOP ---
(def (display-grid grid)
;; Updates terminal window frame by shifting the cursor back home instead of scrolling
(write-vector #u8(27 91 72)) ; ANSI Escape code: Home cursor positioning
(for (r (in-range *rows*))
(for (c (in-range *cols*))
;; Render visual blocks for alive cells, blank strings for dead ones
(if (= (grid-ref grid r c) 1)
(write-vector #u8(226 150 136))
(write-byte 32)))
(newline)))
(def (game-loop grid)
;; Infinite driver cycle processing the evolution timeline step by step
(display-grid grid)
(thread-sleep! 0.1) ; Rest cycle of 100 milliseconds to control simulation speed
(game-loop (next-generation grid)))
;; Global execution endpoint compiled down
(def (main . args)
(write-vector #u8(27 91 50 74)) ; ANSI Escape code: Initial hard screen clear
(game-loop (random-grid *rows* *cols*)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment