"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! !
