/ruby_as_apl

Conway's game of life in one statement of idiomatic Ruby... ported from APL

Primary LanguageRuby

This repository contains implementation of Conway's Game of Life in one Ruby statement.

It was inspired by (in)famous APL's one-line implementation and is a more-or-less straightforward port of it into idiomatic Ruby.

To port the algorithm, a small prototype library with APL-style Array were created—so, technically, it is not a one-statement implementation, but I still prefer to think about it as "one-statement" one, as the class implemented is of generic use (somewhat like Numo::NArray), and operations used are familiar to any Rubyist.

You can read an explanatory article in my blog, but here we'll just show an implementation:

require 'apl'

AA = APL::Ary

def life(current_gen)
  current_gen.wrap
    .product(AA[-1, 0, 1], &:hrotate)
    .product(AA[-1, 0, 1], &:vrotate)
    .reduce(&:+).reduce(&:+)
    .eq(AA[3, 4])
    .zip(AA[1, current_gen], &:&)
    .reduce(&:|)
    .unwrap
end

...and its usage:

def show(grid)
  # APL-style AA#values_at(aa) produces array of items from the first array, taken and shaped
  # using numbers from second array as indexes.
  puts AA[' ', '█'].values_at(grid)
end

glider = AA[1, 1, 1, 1, 0, 0, 0, 1, 0].reshape(3, 3)
grid = glider.take(-10, -10)

show grid.wrap
# ┌──────────┐
# │          │
# │          │
# │          │
# │          │
# │          │
# │          │
# │          │
# │       ███│
# │       █  │
# │        █ │
# └──────────┘


generations = [grid]
9.times { generations << life(generations.last) }

show AA[*generations]

# or, simpler, with 2.7's Enumerator#produce:

generations = Enumerator.produce(grid) { |cur| life(cur) }.take(10).map(&:wrap)
show AA[*generations]
# ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
# │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │
# │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │
# │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │
# │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │
# │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │      █   │
# │          │ │          │ │          │ │          │ │          │ │       █  │ │      ██  │ │      ██  │ │     ███  │ │     ██   │
# │          │ │        █ │ │       ██ │ │       ██ │ │      ███ │ │      ██  │ │      █ █ │ │     ██   │ │     █    │ │     █ █  │
# │       ███│ │       ██ │ │       █ █│ │      ██  │ │      █   │ │      █ █ │ │      █   │ │       █  │ │      █   │ │          │
# │       █  │ │       █ █│ │       █  │ │        █ │ │       █  │ │          │ │          │ │          │ │          │ │          │
# │        █ │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │ │          │
# └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘