Conway's Game of Life: Difference between revisions

no edit summary
imported>Chinhouse
No edit summary
 
(17 intermediate revisions by 6 users not shown)
Line 1,404:
 
=={{header|APL}}==
[[GNU APL]] (from Wikipedia: https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_Life#Translations)<syntaxhighlight lang="apl">
Life←{↑↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}
m ← 5 5⍴(0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0)
m
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
Life m
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
Life Life m
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
</syntaxhighlight>
 
 
[http://www.dyalog.com/dfnsdws/c_life.htm APL2 (Dyalog) Example in one line]
 
Line 3,803 ⟶ 3,827:
 
=={{header|C++}}==
 
Because Nobody else included a version with Graphics, Here is a simple implementation using SFML for graphic rendering
<syntaxhighlight lang="c">
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>
#include <thread>
#include <chrono>
using namespace std;
 
class Life {
private:
int ticks;
bool pass;
int height;
int width;
bool **board;
bool **buffer;
vector<pair<float,float>> liveCoords;
void init();
void lives(int x, int y);
void dies(int x, int y);
bool isAlive(bool **curr, int x, int y);
int checkNeighbors(bool **curr, int x, int y);
void evaluatePosition(bool** curr, int x, int y);
public:
Life(int w = 100, int h = 50, int seed = 1337);
Life(const Life& life);
~Life();
vector<pair<float,float>> doTick();
Life& operator=(const Life& life);
};
void Life::init() {
board = new bool*[height];
buffer = new bool*[height];
for (int y = 0; y < height; y++) {
board[y] = new bool[width];
buffer[y] = new bool[width];
for (int x = 0; x < width; x++) {
board[y][x] = false;
buffer[y][x] = false;
}
}
}
 
Life::Life(int w, int h, int seed) {
width = w;
height = h;
init();
for (int i = 0; i < seed; i++) {
board[rand() % height][rand() % width] = true;
}
pass = true;
}
 
Life::Life(const Life& life) {
width = life.width;
height = life.height;
init();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
board[y][x] = life.board[y][x];
buffer[y][x] = life.buffer[y][x];
}
}
}
 
Life& Life::operator=(const Life& life) {
width = life.width;
height = life.height;
init();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
board[y][x] = life.board[y][x];
buffer[y][x] = life.buffer[y][x];
}
}
return *this;
}
 
Life::~Life() {
for (int i = 0; i < height; i++) {
delete [] board[i];
delete [] buffer[i];
}
delete [] board;
delete [] buffer;
}
 
vector<pair<float,float>> Life::doTick() {
liveCoords.clear();
bool **currentGeneration = pass ? board:buffer;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
evaluatePosition(currentGeneration, x, y);
}
}
pass = !pass;
ticks++;
return liveCoords;
}
 
 
bool Life::isAlive(bool **curr, int x, int y) {
return curr[y][x];
}
int Life::checkNeighbors(bool **curr, int x, int y) {
int lc = 0;
int dx[8] = {-1, 0, 1,1,1,-1, 0,-1};
int dy[8] = {-1,-1,-1,0,1, 1, 1, 0};
for (int i = 0; i < 8; i++) {
int nx = ((dx[i]+x)+width) % width;
int ny = ((dy[i]+y)+height) % height;
lc += isAlive(curr, nx, ny);
}
return lc;
}
void Life::lives(int x, int y) {
if (!pass) {
board[y][x] = true;
} else {
buffer[y][x] = true;
}
liveCoords.push_back(make_pair((float)x,(float)y));
}
void Life::dies(int x, int y) {
if (!pass) {
board[y][x] = false;
} else {
buffer[y][x] = false;
}
}
void Life::evaluatePosition(bool** generation, int x, int y) {
int lc = checkNeighbors(generation, x, y);
if (isAlive(generation, x, y)) {
if (lc == 2 || lc == 3) {
lives(x, y);
} else {
dies(x, y);
}
} else {
if (lc == 3) {
lives(x, y);
} else {
dies(x, y);
}
}
}
 
class App {
private:
void sleep();
void drawLiveCells();
void render();
void handleEvent(sf::Event& event);
void saveDisplay();
int width;
int height;
Life life;
bool isRecording;
int tick;
sf::RenderWindow* window;
sf::RenderTexture* texture;
public:
App(int w = 100, int h = 50);
void start();
};
 
App::App(int w, int h) {
height = h;
width = w;
life = Life(width, height);
isRecording = false;
tick = 0;
}
 
void App::start() {
sf::Event event;
window = new sf::RenderWindow(sf::VideoMode(width*10, height*10), "The Game of Life");
texture = new sf::RenderTexture();
texture->create(width*10, height*10);
window->setFramerateLimit(60);
while (window->isOpen()) {
while (window->pollEvent(event)) {
handleEvent(event);
}
render();
tick++;
}
delete window;
delete texture;
}
 
void App::handleEvent(sf::Event& event) {
if (event.type == sf::Event::Closed) {
window->close();
}
if (event.type == sf::Event::KeyPressed) {
switch (event.key.code) {
case sf::Keyboard::R:
life = Life(width, height);
break;
case sf::Keyboard::S:
isRecording = !isRecording;
break;
case sf::Keyboard::Q:
case sf::Keyboard::Escape:
window->close();
break;
default:
break;
}
}
}
 
void App::sleep() {
std::this_thread::sleep_for(350ms);
}
 
void App::drawLiveCells() {
float XSCALE = 10.0, YSCALE = 10.0;
sf::RectangleShape rect;
rect.setSize(sf::Vector2f(XSCALE, YSCALE));
rect.setFillColor(sf::Color::Green);
auto coords = life.doTick();
texture->clear(sf::Color::Black);
for (auto m : coords) {
rect.setPosition(m.first*XSCALE, m.second*YSCALE);
texture->draw(rect);
}
texture->display();
}
 
void App::render() {
drawLiveCells();
window->clear();
sf::Sprite sprite(texture->getTexture());
window->draw(sprite);
window->display();
if (isRecording) saveDisplay();
sleep();
}
 
void App::saveDisplay() {
string name = "tick" + to_string(tick) + ".png";
sf::Image image = texture->getTexture().copyToImage();
image.saveToFile(name);
}
 
int main(int argc, char* argv[]) {
srand(time(0));
App app;
app.start();
return 0;
}
</syntaxhighlight>
 
And the output of the above program:
[[File:Game of Life.gif|thumb|Life]]
 
 
Considering that the simplest implementation in C++ would lack any use of the object-oriented paradigm, this code was specifically written to demonstrate the various object-oriented features of C++. Thus, while it is somewhat verbose, it fully simulates Conway's Game of Life and is relatively simple to expand to feature different starting shapes.
<syntaxhighlight lang="c">#include <iostream>
Line 4,371 ⟶ 4,657:
 
=={{header|Chapel}}==
 
Compile and run with <code>chpl gol.chpl; ./gol --gridWidth [x] --gridHeight [y]</code>.
<syntaxhighlight lang="chapel">
config const gridHeight : int = 3;
config const gridWidth : int = 3;
 
enum Statestate { dead = 0, alive = 1 };
 
class ConwaysGameofLife
{
var gridDomain : domain(2, int);
var computeDomain : subdomain(gridDomain);
var grid : [gridDomain] state;
 
proc init(height : int, width : int)
{
this.gridDomain = {0..#height+2, 0..#width+2};
this.computeDomain = this.gridDomain.expand(-1);
}
 
 
proc step() : void
{
var tempGrid: [this.computeDomain] state;
 
forall (i,j) in this.computeDomain
{
var isAlive = this.grid[i,j] == state.alive;
var numAlive = (+ reduce this.grid[i-1..i+1, j-1..j+1]:int) - if isAlive then 1 else 0;
tempGrid[i,j] = if ( (2 == numAlive && isAlive) || numAlive == 3 ) then state.alive else state.dead ;
}
 
this.grid[this.computeDomain] = tempGrid;
}
 
proc this(i : int, j : int) ref : state
{
return this.grid[i,j];
}
 
 
proc prettyPrint() : string
{
var str : string;
for i in this.gridDomain.dim(0)
{
if i == 0 || i == gridDomain.dim(0).last
{
for j in this.gridDomain.dim(1)
{
str += "-";
}
}
else
{
for j in this.gridDomain.dim(1)
{
if j == 0 || j == this.gridDomain.dim(1).last
{
str += "|";
}
else
{
str += if this.grid[i,j] == state.alive then "#" else " ";
}
}
}
str += "\n";
}
 
return str;
}
 
class ConwaysGameofLife {
var gridDomain: domain(2);
var computeDomain: subdomain( gridDomain );
var grid: [gridDomain] int;
proc ConwaysGameofLife( height: int, width: int ) {
this.gridDomain = {0..#height+2, 0..#width+2};
this.computeDomain = this.gridDomain.expand( -1 );
}
proc step(){
var tempGrid: [this.computeDomain] State;
forall (i,j) in this.computeDomain {
var isAlive = this.grid[i,j] == State.alive;
var numAlive = (+ reduce this.grid[ i-1..i+1, j-1..j+1 ]) - if isAlive then 1 else 0;
tempGrid[i,j] = if ( (2 == numAlive && isAlive) || numAlive == 3 ) then State.alive else State.dead ;
}
this.grid[this.computeDomain] = tempGrid;
}
proc this( i: int, j: int ) ref : State {
return this.grid[i,j];
}
proc prettyPrint(): string {
var str: string;
for i in this.gridDomain.dim(1) {
if i == 0 || i == gridDomain.dim(1).last {
for j in this.gridDomain.dim(2) {
str += "-";
}
} else {
for j in this.gridDomain.dim(2) {
if j == 0 || j == this.gridDomain.dim(2).last {
str += "|";
} else {
str += if this.grid[i,j] == State.alive then "#" else " ";
}
}
}
str += "\n";
}
return str;
}
 
}
 
 
proc main{
proc main()
var game = new ConwaysGameofLife( gridHeight, gridWidth );
{
game[gridHeight/2 + 1, gridWidth/2 ] = State.alive;
var game[gridHeight/2 += 1new ConwaysGameofLife(gridHeight, gridWidth/2 + 1 ] = State.alive);
 
game[gridHeight/2 + 1, gridWidth/2 + 2 ] = State.alive;
game[gridHeight/2 + 1, gridWidth/2 ] = state.alive;
for i in 1..3 {
game[gridHeight/2 + 1, gridWidth/2 + 1 ] = state.alive;
writeln( game.prettyPrint() );
game[gridHeight/2 + 1, gridWidth/2 + 2 ] = state.alive;
game.step();
 
}
for i in 1..3
{
writeln(game.prettyPrint());
game.step();
}
}
</syntaxhighlight>
Line 5,593 ⟶ 5,905:
 
=={{header|Elena}}==
ELENA 6.0x, using cellular library
<syntaxhighlight lang="elena">import extensions;
import system'threading;
Line 5,673 ⟶ 5,985:
auto line := new TextBuilder();
for(int i := 0,; i < rows,; i += 1)
{
line.clear();
for(int j := 0,; j < columns,; j += 1)
{
int cell := self.at(i, j);
Line 5,699 ⟶ 6,011:
model.run();
threadControl.sleep:(DELAY)
};
 
Line 7,283 ⟶ 7,595:
to_int_board board
</syntaxhighlight>
 
 
 
=={{header|FutureBasic}}==
This is just the basic central routine.
<syntaxhighlight lang="futurebasic">
 
Short a(4, 4), c(4, 4) // Initialize arrays of cells and a working copy
 
void local fn seed
Short x, y
// Blinker
a(1, 2) = 1 : a(2, 2) = 1 : a(3, 2) = 1
for y = 1 to 3 : for x = 1 to 3
print a(x, y); // Draw array
next : print : next : print
end fn
 
void local fn nextGen
Short x, y, dx, dy, n
// Calculate next generation on temporary board
for y = 1 to 3 : for x = 1 to 3
c(x, y) = 0 // Initialize
n = -a(x, y) // Don't count center cell
for dy = -1 to 1 : for dx = -1 to 1
n += a(x + dx, y + dy) // Count the neighbours
next : next
c(x, y) = ( n == 3 ) or ( n == 2 and a(x, y) ) // Conway’s rule
next : next
// Copy temp array to actual array and draw
for y = 1 to 3 : for x = 1 to 3
a(x, y) = c(x, y) // Copy
print a(x, y); // Draw
next : print : next : print
end fn
 
fn seed
fn nextGen
fn nextGen
 
handleevents // Go into Mac event loop
 
 
</syntaxhighlight>
Just three generations, as requested:
<pre>
000
111
000
 
010
010
010
 
000
111
000
 
 
</pre>
 
=={{header|Go}}==
Line 7,944 ⟶ 8,316:
0 0 0
1 1 1
0 0 0</syntaxhighlight>
 
</syntaxhighlight>
 
'''Example''' (showing start and six following generations of a glider)
Line 12,905 ⟶ 13,279:
 
conway_life()</syntaxhighlight>
 
=={{header|Quackery}}==
 
Uses a Tortoise and Hare algorithm to detect when Life becomes static or repetitive. The tortoise version is displayed, along with five victory laps of the cyclic part once a cycle is detected.
 
<syntaxhighlight lang="Quackery">
[ $ "turtleduck.qky" loadfile ] now!
 
[ $ \
import time
now = time.time()
sleepy_time = 5/7-(now%(5/7))
time.sleep(sleepy_time)
\ python ] is wait ( --> )
 
[ dup 1
[ 2dup > while + 1 >> 2dup / again ]
drop nip ] is sqrt ( n --> n )
 
[ stack ] is width ( --> s )
 
[ tuck witheach
[ over i^ peek + rot i^ poke swap ]
drop ] is add ( [ [ --> [ )
 
[ 1 split swap join ] is left ( [ --> [ )
 
[ -1 split swap join ] is right ( [ --> [ )
 
[ width share split swap join ] is up ( [ --> [ )
 
[ width share negate split swap join ] is down ( [ --> [ )
 
[ left dup up tuck add
swap right tuck add
swap right tuck add
swap down tuck add
swap down tuck add
swap left tuck add
swap left add ] is neighbours ( [ --> [ )
 
[ [] swap
width share times
[ width share split
dip [ 0 swap 0 join join join ] ]
drop
2 width tally
0 width share of tuck join join ] is makeborder ( [ --> [ )
 
[ dup size times
[ 0 swap i^ poke
0 swap i^ width share + 1 - poke
width share step ]
width share times
[ 0 swap i^ poke
0 swap i^ 1 + negate poke ] ] is clearborder ( [ --> [ )
 
[ dup neighbours
witheach
[ over i^ peek iff
[ 1 | 3 != if
[ 0 swap i^ poke ] ]
done
3 = if [ 1 swap i^ poke ] ]
clearborder ] is nextgen ( [ --> [ )
 
[ 6 random
[ table
[ 200 200 255 ] [ 200 255 200 ]
[ 255 200 200 ] [ 200 255 255 ]
[ 255 200 255 ] [ 255 255 200 ] ]
fill
[ 4 times
[ 20 1 walk -1 4 turn ] ] ] is block ( --> )
 
 
[ clear
width share 10 *
dup negate
4 - 1 fly
-1 4 turn
16 - 1 fly
1 4 turn
20 1 fly
' [ 200 200 200 ] colour
4 times
[ width share 2 - 20 * 1 walk
1 4 turn ]
-20 1 fly
' [ 63 63 63 ] colour
width share times
[ width share split
swap witheach
[ if block
20 1 fly ]
width share -20 * 1 fly
1 4 turn
20 1 fly
-1 4 turn ]
drop wait frame ] is draw ( [ --> )
 
[ turtle 0 frames 2 wide
dup size sqrt width put
makeborder
dup
[ dup draw nextgen
dip [ nextgen nextgen ]
2dup = until ]
5 times
[ dup draw nextgen 2dup = until ]
2drop width release ] is life ( [ --> )
 
' [ 0 0 0
1 1 1
0 0 0 ] life ( task requirement )
 
' [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] life ( more interesting )
 
randomise
[ []
1089 times
[ 2 random join ]
life
again ] ( ... runs forever )</syntaxhighlight>
 
{{out}}
 
<code>( task requirement )</code>
 
[[File:Quackery Life Task.png|thumb|center]]
 
<code>( more interesting )</code>
 
[[File:Quackery Life.gif|thumb|center]]
 
<code>( ... runs forever )</code>
 
https://youtu.be/U5owgEpxzwg
 
(The code runs forever, not the video. The accompanying music is also generative, and comes from the Kolakoski Sequence.)
 
=={{header|R}}==
Line 17,293 ⟶ 17,821:
=={{header|Wren}}==
{{trans|Kotlin}}
<syntaxhighlight lang="ecmascriptwren">import "random" for Random
import "timer" for Timer
 
6

edits