# Genuary26 - 2 Prompt: [Twelve principles of animation](https://en.wikipedia.org/wiki/Twelve_basic_principles_of_animation) [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) jazzed up with some d3 transitions. [Mike Lynch](https://etc.mikelynch.org/) ```js const WIDTH = 800; const HEIGHT = 600; const CELL = 10; const CELLW = 80; const CELLH = 60; const GEN_TIME = 1000; const INIT_PROB = 0.5; const restart = { restart: false }; ``` ```js const trigger = view(Inputs.button("Restart")); ``` ```js trigger; restart["restart"] = true; ``` ```js function neighbours(i, j, id) { const VWRAP = CELLW * (CELLH - 1); const e = i > 0 ? id - 1 : id + CELLW - 1; const w = i < CELLW - 1 ? id + 1 : id - CELLW + 1; const n = [e, id, w].map((v) => j > 0 ? v - CELLW : v + VWRAP); const s = [e, id, w].map((v) => j < CELLH - 1 ? v + CELLW : v - VWRAP); return [...n, e, w, ...s]; } const show_grid = (async function* () { const grid = []; for( let j = 0; j < CELLH; j++ ) { for ( let i = 0; i < CELLW; i++ ) { const id = j * CELLW + i; const cell = { id: id, x: (i + 0.5) * CELL, y: (j + 0.5) * CELL, live: Math.random() > INIT_PROB }; cell["n"] = neighbours(i, j, id); grid.push(cell); } } let i = 0; while ( true ) { if( restart["restart"] ) { grid.forEach((c) => c.live = Math.random() > INIT_PROB); restart["restart"] = false } yield grid.filter((d) => d.live); i++; const ngrid = []; for( const id in grid ) { const live_n = grid[id].n.filter((i) => grid[i].live).length; if( grid[id].live ) { ngrid[id] = ( live_n > 2 && live_n < 4 ); } else { ngrid[id] = ( live_n === 3 ); } } for( const id in grid ) { grid[id].live = ngrid[id]; } await new Promise((resolve) => setTimeout(resolve, GEN_TIME)); } })(); ``` ```js // Set up the svg canvas const svg = d3.create("svg") .attr("width", WIDTH) .attr("height", HEIGHT) .attr("viewBox", [ 0, 0, WIDTH, HEIGHT ]); svg.append("clipPath") .attr("id", "clipRect") .append("rect") .attr("x", 0) .attr("y", 0) .attr("width", WIDTH) .attr("height", HEIGHT); const bg_g = svg.append("g") .attr("id", "background"); bg_g.selectAll("rect") .data( [ { bg: "white" } ] ) .join("rect") .attr("x", 0) .attr("y", 0) .attr("width", WIDTH) .attr("height", HEIGHT) .attr("fill", (d) => d.bg) ; const cells_g = svg.append("g") .attr("id", "cells"); // .attr("clip-path", "url(#clipRect)"); display(svg.node()); const ease = d3.easeElastic.period(0.4).amplitude(3); ``` ```js cells_g.selectAll("circle") .data(show_grid, d => d.id) .join( enter => enter.append("circle") .attr("cx", (d) => d.x) .attr("cy", (d) => d.y) .attr("fill", "green") .transition() .ease(ease) .duration(1000) .attr("r", (d) => 10), update => update.attr("fill", "blue"), exit => exit .transition() .duration(2000) .attr("r", 0) .attr("cy", (d) => d.y + 400) .remove() ); ```