"Conway's Game of Life — 2D grid stepped by the standard rules: live with 2 or 3 neighbours stays alive; dead with exactly 3 becomes alive. Classic-corpus program for the Smalltalk-on-SX runtime. The canonical 'glider gun' demo (~36 cells, period-30 emission) is correct but too slow to verify on the spec interpreter without JIT — block, blinker, glider cover the rule arithmetic and edge handling." Object subclass: #Life instanceVariableNames: 'rows cols cells'! !Life methodsFor: 'init'! rows: r cols: c rows := r. cols := c. cells := Array new: r * c. 1 to: r * c do: [:i | cells at: i put: 0]. ^ self! ! !Life methodsFor: 'access'! rows ^ rows! cols ^ cols! at: r at: c ((r < 1) or: [r > rows]) ifTrue: [^ 0]. ((c < 1) or: [c > cols]) ifTrue: [^ 0]. ^ cells at: (r - 1) * cols + c! at: r at: c put: v cells at: (r - 1) * cols + c put: v. ^ v! ! !Life methodsFor: 'step'! neighbors: r at: c | sum | sum := 0. -1 to: 1 do: [:dr | -1 to: 1 do: [:dc | ((dr = 0) and: [dc = 0]) ifFalse: [ sum := sum + (self at: r + dr at: c + dc)]]]. ^ sum! step | next | next := Array new: rows * cols. 1 to: rows * cols do: [:i | next at: i put: 0]. 1 to: rows do: [:r | 1 to: cols do: [:c | | n alive lives | n := self neighbors: r at: c. alive := (self at: r at: c) = 1. lives := alive ifTrue: [(n = 2) or: [n = 3]] ifFalse: [n = 3]. lives ifTrue: [next at: (r - 1) * cols + c put: 1]]]. cells := next. ^ self! stepN: n n timesRepeat: [self step]. ^ self! ! !Life methodsFor: 'measure'! livingCount | sum | sum := 0. 1 to: rows * cols do: [:i | (cells at: i) = 1 ifTrue: [sum := sum + 1]]. ^ sum! !