Conway's Game of Life: Difference between revisions

no edit summary
m (→‎APL: Added 2nd iteration result)
No edit summary
 
(One intermediate revision by one other user not shown)
Line 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,395 ⟶ 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>
6

edits