# One Tick of Life

*Task 2 of 5 · [Cellular Automata](https://gpu.rocks/learn/cellular-automata-407c2c34.md) · GPU.js Learn*

In 1970 John Conway picked the simplest rules he could find that make a world worth
watching. **Birth:** a dead cell with exactly 3 live neighbors comes alive.
**Survival:** a live cell with 2 or 3 neighbors stays alive. Everything else —
lonely or overcrowded — dies. That's the whole game (the notation is B3/S23).

There's a classic bug in CPU implementations: update the grid *in place* and
cells start reading half-new, half-old neighbors. A kernel is immune by construction —
every thread reads the old `world` argument and writes into a brand-new output.
The double buffer isn't a technique here; it's what a kernel *is*.

## Goal

**Goal:** finish the kernel so it computes one full generation of
Conway's Life — birth on 3, survival on 2 or 3, death otherwise.

## Requirements

- Keep the wrapped neighbor census from the last task (already in place)
- A dead cell returns `1` exactly when `count === 3`
- A live cell returns `1` exactly when `count === 2 || count === 3`
- Everything else returns `0`

## Hint 1 — start dead

Declare `let next = 0;`, flip it to `1` in the cases
that live, and `return next;` once at the end. Two `if`s cover
the whole rulebook.

## Hint 2 — the two ifs

```js
if (self === 1 && (count === 2 || count === 3)) next = 1;
if (self === 0 && count === 3) next = 1;
```

## Same idea elsewhere

Reading one buffer while writing another is *ping-ponging*, and every
platform institutionalizes it: WebGPU simulations bind two storage buffers and swap their
roles each dispatch, and CUDA solvers keep `d_old`/`d_new` device
pointers and trade them every launch.

## Starter code

```js
// B3/S23: birth on 3 neighbors, survival on 2 or 3, death otherwise.
// The census below is task 1's answer — the rulebook is yours.
const gpu = new GPU({ mode });

const step = gpu.createKernel(function (world) {
  let count = 0;
  for (let dy = -1; dy < 2; dy++) {
    for (let dx = -1; dx < 2; dx++) {
      const yy = (this.thread.y + dy + 16) % 16;
      const xx = (this.thread.x + dx + 16) % 16;
      count += world[yy][xx];
    }
  }
  const self = world[this.thread.y][this.thread.x];
  count -= self;
  // TODO: apply Conway's rules to `self` and `count`.
  return self;
}, { output: [16, 16] });

const next = await step(world);
console.log('before:', world[7].join(''));
console.log('after :', Array.from(next[7]).join(''));
```

---

Interactive version: https://gpu.rocks/learn/cellular-automata-407c2c34/2

[Previous task](https://gpu.rocks/learn/cellular-automata-407c2c34/1.md) · [Next task](https://gpu.rocks/learn/cellular-automata-407c2c34/3.md)
