Page 1 of 1

Python TUT: Conway's Game of Life

Posted: Wed Aug 06, 2014 8:59 pm
by Verahta
Found this pretty neat Python tutorial for Conway's Game of Life (cellular automata):

http://stanford.edu/~cpiech/cs221/hando ... orial.html

You create mathematical patterns that seem to take on a life of their own:

Image
Game of Life Overview

Our "Game of Life" board will be an n-by-n grid of square cells, each of which can be either "alive" or "dead". A given cell's neighbors are those cells directly above, below, left, or right of the cell, plus with the cells diagonally adjacent to it (the cells touching its diagonals). Each cell changes from one time step to the next according to the following rules:

Any living cell with fewer than two living neighbors dies.
Any living cell with exactly two or exactly three living neighbors remains alive.
Any living cell with more than three living neighbors dies.
Any dead cell with exactly three living neighbors becomes alive.
These extremely simple rules give rise to some incredibly complex and beautiful patterns, as illustrated here:
Image
In fact, these rules are so powerful that they actually allow Conway's Game of Life to be Turing Complete, which roughly means that we could perform any computation within the game that a standard computer could (though they would be painfully slow). And to just get super meta for a second, a consequence of this is that Game of Life can simulate ITSELF! (#Conwayception)
[YouTube]https://www.youtube.com/watch?v=D6aP9S9rEQk[/YouTube]

Re: Python TUT: Conway's Game of Life

Posted: Sun Aug 10, 2014 6:22 am
by Jackolantern
I have always had a strange fascination with Conway's Game of Life 8-)

Re: Python TUT: Conway's Game of Life

Posted: Mon Aug 18, 2014 7:51 pm
by Verahta

Re: Python TUT: Conway's Game of Life

Posted: Mon Aug 18, 2014 11:54 pm
by Chris
Cool! that inspired me to make this :D

See which color is most dominant :D

Code: Select all

<html>
	<head>
		<style type="text/css">
		*{ padding: 0px; margin: 0px; background: #000; }

		</style>
	</head>

	<body>
		<canvas id="canvas"></canvas>
		<script type="text/javascript">
		lifeFormSquareSize = 5;

		var Point = function(x,y) {
			this.x = x || parseInt(Math.random() * (window.innerWidth/lifeFormSquareSize));
			this.y = y || parseInt(Math.random() * (window.innerHeight/lifeFormSquareSize));
			return this;
		}

		Point.prototype.constructor = Point;
		Point.prototype = {
			x : 0,
			y : 0,
			colidesWith : function(point) {
				return point.x == this.x && point.y == this.y;
			},

			moveRandomly : function() {
				var randomX = Math.random() * 10;
				var randomY = Math.random() * 10;
				var displaceX = parseInt(Math.random()*lifeFormSquareSize);
				var displaceY = parseInt(Math.random()*lifeFormSquareSize);
				this.x = parseInt(randomX > 7.5 ? (this.x+displaceX) : (randomX > 5 ? (this.x-displaceX) : this.x));
				this.y = parseInt(randomY > 7.5 ? (this.y+displaceY) : (randomY > 5 ? (this.y-displaceY) : this.y));
			}
		}

		var lifeFormList = [];

		var LifeForm = function() {
			lifeFormList.push(this);
			this.point = new Point();
			this.color = '#' +(Math.random()*0xFFFFFF<<0).toString(16);
			return this;
		}
		LifeForm.prototype.contructor = LifeForm;
		LifeForm.prototype = {
			
			color : '#000000',
			point : null,

			takeTurn : function() {
				for(var i in lifeFormList) {
					if(lifeFormList[i] !== this) {
						if(this.point.colidesWith(lifeFormList[i].point)) {
							var choice = this.makeChoice();
							if(choice == 1) {
								if(!this.fight() && lifeFormList[i].fight()) {
									this.die();
									continue;
								}
								if(this.fight() && !lifeFormList[i].fight()) {
									lifeFormList[i].die();
									continue;
								}
							}
							if(choice == 2) {
								if(this.multiply() || lifeFormList[i].multiply()) {
									var child = new LifeForm();
									child.point = this.point;
									child.color = this.color;
									child.point.moveRandomly();
									console.log('multiply');
									break;
								}
							}
						}
					}
				}
				if(this.randomlyDie()) {
					this.die();
				}
				this.point.moveRandomly();
			},

			/**
			 * 1 = fight
			 * 2 = multiply
			 * 3 = pass
 			 */
			makeChoice : function() {
				var choice = Math.random()*10;
				return choice > 7.5 ? 1 : choice > 5 ? 2 : 3;
			},

			fight : function() {
				return Math.random() * 10 > 5;
			},

			multiply : function() {
				return Math.random()*10 > 8;
			},

			randomlyDie : function() {
				return Math.random() * 1000000000 > 999999998;
			},

			die : function() {
				console.log('die');
				lifeFormList.pop(this);
			}
		}

		//window.onload = function(){
			var canvas = document.getElementById('canvas');
			canvas.width = window.innerWidth;
			canvas.height = window.innerHeight;
			context = canvas.getContext('2d');

			

			for(var i = 0; i <= 200; i++) {
				new LifeForm();
			}

			// life loop
			setInterval(function(){
				for(var i in lifeFormList) {
					lifeFormList[i].takeTurn();
				}
			},1000/30);

			// render loop
			setInterval(function(){
				context.clearRect(0,0,canvas.width,canvas.height);
				for(var i in lifeFormList) {
					context.fillStyle = lifeFormList[i].color;
					context.fillRect(lifeFormList[i].point.x,lifeFormList[i].point.y,lifeFormSquareSize,lifeFormSquareSize);
				}

			},1000/30)
		//}


		</script>
	</body>
</html>

Re: Python TUT: Conway's Game of Life

Posted: Tue Aug 19, 2014 12:15 am
by Verahta
Awesome! After I wrap my head around it some mi=ore I'm going to make one too. Changing the size is cool.

Re: Python TUT: Conway's Game of Life

Posted: Tue Aug 19, 2014 12:32 am
by Chris

Code: Select all

<html>
	<head>
		<style type="text/css">
		*{ padding: 0px; margin: 0px; background: #000; }

		</style>
	</head>

	<body>
		<canvas id="canvas"></canvas>
		<script type="text/javascript">
		lifeFormSquareSize = 6;

		var Point = function(x,y) {
			this.x = x || parseInt(Math.random() * (window.innerWidth/6));
			this.y = y || parseInt(Math.random() * (window.innerHeight/6));
			return this;
		}

		Point.prototype.constructor = Point;
		Point.prototype = {
			x : 0,
			y : 0,
			colidesWith : function(point) {
				return point.x == this.x && point.y == this.y;
			},

			moveRandomly : function() {
				var randomX = Math.random() * 10;
				var randomY = Math.random() * 10;
				var displaceX = parseInt(Math.random()*lifeFormSquareSize);
				var displaceY = parseInt(Math.random()*lifeFormSquareSize);
				this.x = parseInt(randomX > 7.5 ? (this.x+displaceX) : (randomX > 5 ? (this.x-displaceX) : this.x));
				this.y = parseInt(randomY > 7.5 ? (this.y+displaceY) : (randomY > 5 ? (this.y-displaceY) : this.y));
			}
		}

		var lifeFormList = [];

		var LifeForm = function() {
			lifeFormList.push(this);
			this.point = new Point();
			this.color = '#' +(Math.random()*0xFFFFFF<<0).toString(16);
			return this;
		}
		LifeForm.prototype.contructor = LifeForm;
		LifeForm.prototype = {
			
			color : '#000000',
			point : null,

			takeTurn : function() {
				for(var i in lifeFormList) {
					if(lifeFormList[i] !== this) {
						if(this.point.colidesWith(lifeFormList[i].point)) {
							var choice = this.makeChoice();
							if(choice == 1) {
								if(this.fight() && lifeFormList[i].fight()) {
									if(Math.random() * 2 < 0.5 ) { 
										this.die();
									} else if(Math.random() * 2 < 1 ) {
										lifeFormList[i].die();
									}
									continue;
								}
							}
							if(choice == 2) {
								if(this.multiply() && lifeFormList[i].multiply()) {
									var child = new LifeForm();
									child.point = this.point;
									child.color = this.color;
									child.point.moveRandomly();
									new Born(this.point);
									console.log('multiply');
									break;
								}
							}
							if(choice == 3) {
								this.color = '#' +(Math.random()*0xFFFFFF<<0).toString(16);
							}
						}
					}
				}
				if(this.randomlyDie()) {
					this.die();
				}
				this.point.moveRandomly();
			},

			/**
			 * 1 = fight
			 * 2 = multiply
			 * 3 = pass
 			 */
			makeChoice : function() {
				var choice = Math.random()*10;
				return choice > 7.5 ? 1 : choice > 5 ? 2 : 3;
			},

			fight : function() {
				return Math.random() * 10 > 5;
			},

			multiply : function() {
				return Math.random()*10 > 8;
			},

			randomlyDie : function() {
				return Math.random() * 1000000000 > 999999998;
			},

			die : function() {
				console.log('die');
				lifeFormList.pop(this);
				new Die(this.point);
			}
		}

		var dieList = [];
		var Die = function(point) {
			var _point = new Point(point.x,point.y);
			this.point = _point;
			dieList.push(this);
			var _this = this;
			var textInterval = setInterval(function(){
				_this.point.y--;
			},10);
			setTimeout(function(){
				clearInterval(textInterval);
				dieList.pop(_this);
			},500);
		}
		var bornList = []
		var Born = function(point) {
			var _point = new Point(point.x,point.y);
			this.point = _point;
			bornList.push(this);
			var _this = this;
			var textInterval = setInterval(function(){
				_this.point.y--;
			},10);
			setTimeout(function(){
				clearInterval(textInterval);
				bornList.pop(_this);
			},500);

		}

		//window.onload = function(){
			var canvas = document.getElementById('canvas');
			canvas.width = window.innerWidth;
			canvas.height = window.innerHeight;
			context = canvas.getContext('2d');

			

			for(var i = 0; i <= 500; i++) {
				new LifeForm();
			}

			// life loop
			setInterval(function(){
				for(var i in lifeFormList) {
					lifeFormList[i].takeTurn();
				}
			},10);

			// render loop
			setInterval(function(){
				context.clearRect(0,0,canvas.width,canvas.height);
				for(var i in lifeFormList) {
					context.fillStyle = lifeFormList[i].color;
					context.fillRect(lifeFormList[i].point.x,lifeFormList[i].point.y,lifeFormSquareSize,lifeFormSquareSize);
				}
				for(var i in bornList) {
					context.fillStyle = '#00FF00';
					context.font = '10pt Arial';
					context.fillText('BORN', bornList[i].point.x,bornList[i].point.y);
				}

				for(var i in dieList) {
					context.fillStyle = '#FF0000';
					context.font = '10pt Arial';
					context.fillText('DIED', dieList[i].point.x,dieList[i].point.y);
				}
			},1000/60)
		//}


		</script>
	</body>
</html>