npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

games-of-life

v1.0.0

Published

Create any Game of Life variation

Readme

games-of-life

Create any Game of Life variation

No deps

Hexagonal Demo

I created this hexagonal Game of Life demo to show that this package generalizes the Game of Life in any of its variations. Click the image below to try it!

Hexagonal game of life

Installation

With npm do

npm install games-of-life

You can also use a CDN by adding this to your HTML page

<script src="https://unpkg.com/games-of-life"></script>

Idea

On May 30th, 2015, I participated in a Coderetreat at Milan XPUG.

We had so much fun coding implementations of the Game of Life.

As a mathematician, I think it is a very interesting problem. I couldn't resist generalizing it and trying to solve it in any of its variations.

Let's start with some abstractions.

The function getNeighboursOf, which returns the set of cells adjacent to a given cell, defines the shape of a Game of Life universe.

In fact, since

getNeighboursOf(cell1) = getNeighboursOf(cell2) ⇒ cell1 = cell2

it can be said that the set of neighbours of a cell is dual to the cell itself, hence the definition of the getNeighboursOf function is equivalent to the definition of the space of a Game of Life universe. Note that it defines the concept of nearness.

In other words,

if you define a getNeighbours function you also shape the space of a Game of Life universe

On the other hand, given the definition of an isAlive function, which returns true if the given cell is alive, false otherwise. It can be easily extended to an areAlive function, which, given a list of cells, returns a list of booleans; following similar reasoning to what we used for the getNeighboursOf function, an isAlive function describes the state of a Game of Life universe at a given moment.

The considerations above allow us to implement an abstract Game of Life in a functional way, in any of its variations, for example:

  • finite grid
  • infinite grid
  • 2-dimensional, 3-dimensional, n-dimensional
  • square, triangular, hexagonal tiles
  • cylinder, torus, moebius strip, boy surface

Example

A simple example is the infinite grid with two dimensional coordinates.

Define the infiniteGrid2d function which returns the neighbours of a given cell.

function infiniteGrid2d ([x, y]) {
  const neighbours = []

  for (let j = y - 1; j <= y + 1; j++) {
    for (let i = x - 1; i <= x + 1; i++) {
      if ((i === x) && (j === y))
        continue

      neighbours.push([i, j])
    }
  }

  return neighbours
}

Create a Game of Life world and get the evolve function

import { createWorld, classicTransitionRule } from 'games-of-life'

const world = createWorld(infiniteGrid2d)
const transitionRule = classicTransitionRule.bind(null, 2, 3, 3)

const evolve = world(transitionRule)

The empty grid is represented by a function that always returns false, so

function emptyGrid () {
  return false
}

evolve(emptyGrid) // will always return false

Try with a single cell at the origin

function singleCellAtTheOrigin (cell) {
  return ((cell[0] === 0) && (cell[1] === 0))
}

evolve(singleCellAtTheOrigin) // will always return false too, because the cell dies

Now, a more interesting example is the blinker

Blinker

function horizontalBlinker ([x, y]) {
  if (y !== 0) {
    return false
  }

  if ((x >= -1) && (x <= 1)) {
    return true
  }

  return false
}

function verticalBlinker ([x, y]) {
  if (x !== 0) {
    return false
  }

  if ((y >= -1) && (y <= 1)) {
    return true
  }

  return false
}

You may check that the verticalBlinker evolves into the horizontalBlinker and vice versa

for (let i = -1; i < 1; i++) {
  for (let j = -1; j < 1; j++) {
    console.log(evolve(verticalBlinker)(i, j) ===  horizontalBlinker(i, j)) // true
  }
}

License

MIT