├── README.md
├── CSS
└── style.css
├── .gitattributes
├── JS
├── index.js
├── canvas-toBlob.js
├── filesaver.js
└── gameoflife.js
├── index.html
└── .gitignore
/README.md:
--------------------------------------------------------------------------------
1 | Game of Life
2 | =======
3 | Conway's Game of Life
4 | - Random
5 | - Glider
6 | - Lightweight Spaceship
7 | - Pulsar
8 | - Glider Gun
9 | - Image
10 |
11 | License
12 | ======
13 | [MIT license] (http://opensource.org/licenses/MIT)
--------------------------------------------------------------------------------
/CSS/style.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | font-size: 2em;
3 | font-weight: bold;
4 | text-align:center;
5 | }
6 |
7 | #stop {
8 | display:none;
9 | }
10 |
11 | #canvas {
12 | margin-top:10px;
13 | }
14 |
15 | #image,#img_image {
16 | display:none;
17 | }
18 |
19 | #files {
20 | display:none;
21 | }
22 |
23 |
24 | .button {
25 | margin:5px 0px 0px 15px;
26 | background-color:#fb0;
27 | color: black;
28 | border-radius: 3px;
29 | padding:10px;
30 | width:auto;
31 | display:inline-block;
32 | cursor:pointer;
33 | }
34 |
35 |
36 | .save {
37 |
38 | width:100px;
39 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/JS/index.js:
--------------------------------------------------------------------------------
1 | var ctx = document.getElementById('canvas').getContext("2d");
2 | var gameoflife = new GoL(ctx);
3 |
4 | var id_config = document.getElementById('config');
5 | id_config.onchange = function() {
6 | if (id_config.value == "Image") {
7 | document.getElementById("files").style.display = "inline";
8 | } else {
9 | document.getElementById("files").style.display = "none";
10 | }
11 | }
12 |
13 | function start() {
14 | var width = document.getElementById("canvas").offsetWidth;
15 | var height = document.getElementById("canvas").offsetHeight;
16 |
17 |
18 | var timeout = document.getElementById("timeout").value;
19 | var alive = document.getElementById("alive").value;
20 | var config = document.getElementById("config").value;
21 | if (timeout > 0 && ((config == "Random" && alive > 0 && alive <= Math.floor(width/4)*Math.floor(height/4)) || config !== "Random")) {
22 | gameoflife.create_GoL(width,height,timeout,alive,config);
23 | document.getElementById("user_input").style.display = "none";
24 | document.getElementById("stop").style.display = "inline";
25 | } else {
26 | alert("Both (timeout and alive) must be > 0 and alive must be <= "+Math.floor(width/4)*Math.floor(height/4));
27 | }
28 | }
29 | function stop() {
30 | gameoflife.set_stop();
31 | document.getElementById("user_input").style.display = "inline";
32 | document.getElementById("stop").style.display = "none";
33 | }
34 |
35 | /* Save diagram */
36 | function save() {
37 | var canvas = document.getElementById("canvas");
38 | canvas.toBlob(function(blob) {
39 | saveAs(blob, "GoL.png");
40 | });
41 | };
42 |
43 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Game of Life
5 |
6 |
7 |
8 |
9 |
10 |
11 | Game of Life
12 |
13 | Timeout(ms): Number of alive cells (only for random):
14 |
23 |
24 |
Start
25 |
26 | Stop
28 |
29 |
30 | Save as png
31 |
32 |
33 |
34 |
35 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/JS/canvas-toBlob.js:
--------------------------------------------------------------------------------
1 | /* canvas-toBlob.js
2 | * A canvas.toBlob() implementation.
3 | * 2011-07-13
4 | *
5 | * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
6 | * License: X11/MIT
7 | * See LICENSE.md
8 | */
9 |
10 | /*global self */
11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
12 | plusplus: true */
13 |
14 | /*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
15 |
16 | (function(view) {
17 | "use strict";
18 | var
19 | Uint8Array = view.Uint8Array
20 | , HTMLCanvasElement = view.HTMLCanvasElement
21 | , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
22 | , base64_ranks
23 | , decode_base64 = function(base64) {
24 | var
25 | len = base64.length
26 | , buffer = new Uint8Array(len / 4 * 3 | 0)
27 | , i = 0
28 | , outptr = 0
29 | , last = [0, 0]
30 | , state = 0
31 | , save = 0
32 | , rank
33 | , code
34 | , undef
35 | ;
36 | while (len--) {
37 | code = base64.charCodeAt(i++);
38 | rank = base64_ranks[code-43];
39 | if (rank !== 255 && rank !== undef) {
40 | last[1] = last[0];
41 | last[0] = code;
42 | save = (save << 6) | rank;
43 | state++;
44 | if (state === 4) {
45 | buffer[outptr++] = save >>> 16;
46 | if (last[1] !== 61 /* padding character */) {
47 | buffer[outptr++] = save >>> 8;
48 | }
49 | if (last[0] !== 61 /* padding character */) {
50 | buffer[outptr++] = save;
51 | }
52 | state = 0;
53 | }
54 | }
55 | }
56 | // 2/3 chance there's going to be some null bytes at the end, but that
57 | // doesn't really matter with most image formats.
58 | // If it somehow matters for you, truncate the buffer up outptr.
59 | return buffer.buffer;
60 | }
61 | ;
62 | if (Uint8Array) {
63 | base64_ranks = new Uint8Array([
64 | 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
65 | , -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
66 | , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
67 | , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
68 | , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
69 | ]);
70 | }
71 | if (HTMLCanvasElement && !HTMLCanvasElement.prototype.toBlob) {
72 | HTMLCanvasElement.prototype.toBlob = function(callback, type /*, ...args*/) {
73 | if (!type) {
74 | type = "image/png";
75 | } if (this.mozGetAsFile) {
76 | callback(this.mozGetAsFile("canvas", type));
77 | return;
78 | }
79 | var
80 | args = Array.prototype.slice.call(arguments, 1)
81 | , dataURI = this.toDataURL.apply(this, args)
82 | , header_end = dataURI.indexOf(",")
83 | , data = dataURI.substring(header_end + 1)
84 | , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
85 | , blob
86 | ;
87 | if (Blob.fake) {
88 | // no reason to decode a data: URI that's just going to become a data URI again
89 | blob = new Blob
90 | if (is_base64) {
91 | blob.encoding = "base64";
92 | } else {
93 | blob.encoding = "URI";
94 | }
95 | blob.data = data;
96 | blob.size = data.length;
97 | } else if (Uint8Array) {
98 | if (is_base64) {
99 | blob = new Blob([decode_base64(data)], {type: type});
100 | } else {
101 | blob = new Blob([decodeURIComponent(data)], {type: type});
102 | }
103 | }
104 | callback(blob);
105 | };
106 | }
107 | }(self));
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | x64/
49 | build/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # MSTest test Results
54 | [Tt]est[Rr]esult*/
55 | [Bb]uild[Ll]og.*
56 |
57 | *_i.c
58 | *_p.c
59 | *.ilk
60 | *.meta
61 | *.obj
62 | *.pch
63 | *.pdb
64 | *.pgc
65 | *.pgd
66 | *.rsp
67 | *.sbr
68 | *.tlb
69 | *.tli
70 | *.tlh
71 | *.tmp
72 | *.tmp_proj
73 | *.log
74 | *.vspscc
75 | *.vssscc
76 | .builds
77 | *.pidb
78 | *.log
79 | *.scc
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | *.ncrunch*
109 | .*crunch*.local.xml
110 |
111 | # Installshield output folder
112 | [Ee]xpress/
113 |
114 | # DocProject is a documentation generator add-in
115 | DocProject/buildhelp/
116 | DocProject/Help/*.HxT
117 | DocProject/Help/*.HxC
118 | DocProject/Help/*.hhc
119 | DocProject/Help/*.hhk
120 | DocProject/Help/*.hhp
121 | DocProject/Help/Html2
122 | DocProject/Help/html
123 |
124 | # Click-Once directory
125 | publish/
126 |
127 | # Publish Web Output
128 | *.Publish.xml
129 | *.pubxml
130 |
131 | # NuGet Packages Directory
132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
133 | #packages/
134 |
135 | # Windows Azure Build Output
136 | csx
137 | *.build.csdef
138 |
139 | # Windows Store app package directory
140 | AppPackages/
141 |
142 | # Others
143 | sql/
144 | *.Cache
145 | ClientBin/
146 | [Ss]tyle[Cc]op.*
147 | ~$*
148 | *~
149 | *.dbmdl
150 | *.[Pp]ublish.xml
151 | *.pfx
152 | *.publishsettings
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | App_Data/*.mdf
166 | App_Data/*.ldf
167 |
168 | #############
169 | ## Windows detritus
170 | #############
171 |
172 | # Windows image file caches
173 | Thumbs.db
174 | ehthumbs.db
175 |
176 | # Folder config file
177 | Desktop.ini
178 |
179 | # Recycle Bin used on file shares
180 | $RECYCLE.BIN/
181 |
182 | # Mac crap
183 | .DS_Store
184 |
185 |
186 | #############
187 | ## Python
188 | #############
189 |
190 | *.py[co]
191 |
192 | # Packages
193 | *.egg
194 | *.egg-info
195 | dist/
196 | build/
197 | eggs/
198 | parts/
199 | var/
200 | sdist/
201 | develop-eggs/
202 | .installed.cfg
203 |
204 | # Installer logs
205 | pip-log.txt
206 |
207 | # Unit test / coverage reports
208 | .coverage
209 | .tox
210 |
211 | #Translations
212 | *.mo
213 |
214 | #Mr Developer
215 | .mr.developer.cfg
216 |
--------------------------------------------------------------------------------
/JS/filesaver.js:
--------------------------------------------------------------------------------
1 | /* FileSaver.js
2 | * A saveAs() FileSaver implementation.
3 | * 2013-01-23
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | * License: X11/MIT
7 | * See LICENSE.md
8 | */
9 |
10 | /*global self */
11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
12 | plusplus: true */
13 |
14 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
15 |
16 | var saveAs = saveAs
17 | || (navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
18 | || (function(view) {
19 | "use strict";
20 | var
21 | doc = view.document
22 | // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
23 | , get_URL = function() {
24 | return view.URL || view.webkitURL || view;
25 | }
26 | , URL = view.URL || view.webkitURL || view
27 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
28 | , can_use_save_link = !view.externalHost && "download" in save_link
29 | , click = function(node) {
30 | var event = doc.createEvent("MouseEvents");
31 | event.initMouseEvent(
32 | "click", true, false, view, 0, 0, 0, 0, 0
33 | , false, false, false, false, 0, null
34 | );
35 | node.dispatchEvent(event);
36 | }
37 | , webkit_req_fs = view.webkitRequestFileSystem
38 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
39 | , throw_outside = function (ex) {
40 | (view.setImmediate || view.setTimeout)(function() {
41 | throw ex;
42 | }, 0);
43 | }
44 | , force_saveable_type = "application/octet-stream"
45 | , fs_min_size = 0
46 | , deletion_queue = []
47 | , process_deletion_queue = function() {
48 | var i = deletion_queue.length;
49 | while (i--) {
50 | var file = deletion_queue[i];
51 | if (typeof file === "string") { // file is an object URL
52 | URL.revokeObjectURL(file);
53 | } else { // file is a File
54 | file.remove();
55 | }
56 | }
57 | deletion_queue.length = 0; // clear queue
58 | }
59 | , dispatch = function(filesaver, event_types, event) {
60 | event_types = [].concat(event_types);
61 | var i = event_types.length;
62 | while (i--) {
63 | var listener = filesaver["on" + event_types[i]];
64 | if (typeof listener === "function") {
65 | try {
66 | listener.call(filesaver, event || filesaver);
67 | } catch (ex) {
68 | throw_outside(ex);
69 | }
70 | }
71 | }
72 | }
73 | , FileSaver = function(blob, name) {
74 | // First try a.download, then web filesystem, then object URLs
75 | var
76 | filesaver = this
77 | , type = blob.type
78 | , blob_changed = false
79 | , object_url
80 | , target_view
81 | , get_object_url = function() {
82 | var object_url = get_URL().createObjectURL(blob);
83 | deletion_queue.push(object_url);
84 | return object_url;
85 | }
86 | , dispatch_all = function() {
87 | dispatch(filesaver, "writestart progress write writeend".split(" "));
88 | }
89 | // on any filesys errors revert to saving with object URLs
90 | , fs_error = function() {
91 | // don't create more object URLs than needed
92 | if (blob_changed || !object_url) {
93 | object_url = get_object_url(blob);
94 | }
95 | if (target_view) {
96 | target_view.location.href = object_url;
97 | } else {
98 | window.open(object_url, "_blank");
99 | }
100 | filesaver.readyState = filesaver.DONE;
101 | dispatch_all();
102 | }
103 | , abortable = function(func) {
104 | return function() {
105 | if (filesaver.readyState !== filesaver.DONE) {
106 | return func.apply(this, arguments);
107 | }
108 | };
109 | }
110 | , create_if_not_found = {create: true, exclusive: false}
111 | , slice
112 | ;
113 | filesaver.readyState = filesaver.INIT;
114 | if (!name) {
115 | name = "download";
116 | }
117 | if (can_use_save_link) {
118 | object_url = get_object_url(blob);
119 | save_link.href = object_url;
120 | save_link.download = name;
121 | click(save_link);
122 | filesaver.readyState = filesaver.DONE;
123 | dispatch_all();
124 | return;
125 | }
126 | // Object and web filesystem URLs have a problem saving in Google Chrome when
127 | // viewed in a tab, so I force save with application/octet-stream
128 | // http://code.google.com/p/chromium/issues/detail?id=91158
129 | if (view.chrome && type && type !== force_saveable_type) {
130 | slice = blob.slice || blob.webkitSlice;
131 | blob = slice.call(blob, 0, blob.size, force_saveable_type);
132 | blob_changed = true;
133 | }
134 | // Since I can't be sure that the guessed media type will trigger a download
135 | // in WebKit, I append .download to the filename.
136 | // https://bugs.webkit.org/show_bug.cgi?id=65440
137 | if (webkit_req_fs && name !== "download") {
138 | name += ".download";
139 | }
140 | if (type === force_saveable_type || webkit_req_fs) {
141 | target_view = view;
142 | }
143 | if (!req_fs) {
144 | fs_error();
145 | return;
146 | }
147 | fs_min_size += blob.size;
148 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
149 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
150 | var save = function() {
151 | dir.getFile(name, create_if_not_found, abortable(function(file) {
152 | file.createWriter(abortable(function(writer) {
153 | writer.onwriteend = function(event) {
154 | target_view.location.href = file.toURL();
155 | deletion_queue.push(file);
156 | filesaver.readyState = filesaver.DONE;
157 | dispatch(filesaver, "writeend", event);
158 | };
159 | writer.onerror = function() {
160 | var error = writer.error;
161 | if (error.code !== error.ABORT_ERR) {
162 | fs_error();
163 | }
164 | };
165 | "writestart progress write abort".split(" ").forEach(function(event) {
166 | writer["on" + event] = filesaver["on" + event];
167 | });
168 | writer.write(blob);
169 | filesaver.abort = function() {
170 | writer.abort();
171 | filesaver.readyState = filesaver.DONE;
172 | };
173 | filesaver.readyState = filesaver.WRITING;
174 | }), fs_error);
175 | }), fs_error);
176 | };
177 | dir.getFile(name, {create: false}, abortable(function(file) {
178 | // delete file if it already exists
179 | file.remove();
180 | save();
181 | }), abortable(function(ex) {
182 | if (ex.code === ex.NOT_FOUND_ERR) {
183 | save();
184 | } else {
185 | fs_error();
186 | }
187 | }));
188 | }), fs_error);
189 | }), fs_error);
190 | }
191 | , FS_proto = FileSaver.prototype
192 | , saveAs = function(blob, name) {
193 | return new FileSaver(blob, name);
194 | }
195 | ;
196 | FS_proto.abort = function() {
197 | var filesaver = this;
198 | filesaver.readyState = filesaver.DONE;
199 | dispatch(filesaver, "abort");
200 | };
201 | FS_proto.readyState = FS_proto.INIT = 0;
202 | FS_proto.WRITING = 1;
203 | FS_proto.DONE = 2;
204 |
205 | FS_proto.error =
206 | FS_proto.onwritestart =
207 | FS_proto.onprogress =
208 | FS_proto.onwrite =
209 | FS_proto.onabort =
210 | FS_proto.onerror =
211 | FS_proto.onwriteend =
212 | null;
213 |
214 | view.addEventListener("unload", process_deletion_queue, false);
215 | return saveAs;
216 | }(self));
217 |
218 | if (typeof module !== 'undefined') module.exports = saveAs;
--------------------------------------------------------------------------------
/JS/gameoflife.js:
--------------------------------------------------------------------------------
1 | window.GoL = function(context) {
2 | var ctx = context;
3 | var GoL_array = new Array();
4 | var next_GoL_array = new Array();
5 | var width;
6 | var height;
7 | var steps = 100000;
8 | var stop;
9 | var timeout;
10 |
11 | this.create_GoL = function(w,h,tout,alive,config) {
12 | stop = false;
13 | timeout = tout;
14 | width = w;
15 | height = h;
16 | ctx.fillStyle = '#FFF';
17 |
18 | ctx.fillRect(0,0,width,height);
19 | for (var x=0; x < Math.floor(width/4); x++) {
20 | GoL_array[x] = new Array();
21 | next_GoL_array[x] = new Array();
22 | for (var y=0; y < Math.floor(height/4); y++) {
23 | GoL_array[x][y] = 0;
24 | next_GoL_array[x][y] = 0;
25 | }
26 | }
27 |
28 |
29 |
30 | var grid = create_grid();
31 |
32 | switch (config) {
33 | case "Random":
34 | var rand_alive = random_alive(alive);
35 | break;
36 | case "Glider":
37 | set_alive(Math.floor(width/8)+1,Math.floor(height/8));
38 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)+1);
39 | set_alive(Math.floor(width/8),Math.floor(height/8)+1);
40 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)+1);
41 | set_alive(Math.floor(width/8),Math.floor(height/8)-1);
42 | show_state();
43 | break;
44 | case "LWSS":
45 | set_alive(Math.floor(width/8)+1,Math.floor(height/8));
46 | set_alive(Math.floor(width/8)+2,Math.floor(height/8));
47 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)+1);
48 | set_alive(Math.floor(width/8),Math.floor(height/8)+1);
49 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)+1);
50 | set_alive(Math.floor(width/8)-2,Math.floor(height/8)+1);
51 | set_alive(Math.floor(width/8),Math.floor(height/8)+2);
52 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)+2);
53 | set_alive(Math.floor(width/8)-1,Math.floor(height/8));
54 | set_alive(Math.floor(width/8)-2,Math.floor(height/8));
55 | set_alive(Math.floor(width/8),Math.floor(height/8)-1);
56 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)-1);
57 | break;
58 | case "Pulsar":
59 | for (var i = -4; i <= 4; i++) {
60 | if (i <= -2 || i >= 2) {
61 | set_alive(Math.floor(width/8)+i,Math.floor(height/8)-1);
62 | set_alive(Math.floor(width/8)+i,Math.floor(height/8)+1);
63 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)+i);
64 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)+i);
65 |
66 | set_alive(Math.floor(width/8)+i,Math.floor(height/8)-6);
67 | set_alive(Math.floor(width/8)+i,Math.floor(height/8)+6);
68 | set_alive(Math.floor(width/8)+6,Math.floor(height/8)+i);
69 | set_alive(Math.floor(width/8)-6,Math.floor(height/8)+i);
70 | }
71 | }
72 | break;
73 | case "Gun":
74 | set_alive(Math.floor(width/8)-13,Math.floor(height/8));
75 | set_alive(Math.floor(width/8)-14,Math.floor(height/8));
76 | set_alive(Math.floor(width/8)-13,Math.floor(height/8)-1);
77 | set_alive(Math.floor(width/8)-14,Math.floor(height/8)-1);
78 |
79 |
80 | set_alive(Math.floor(width/8)-4,Math.floor(height/8)-1);
81 | set_alive(Math.floor(width/8)-4,Math.floor(height/8));
82 | set_alive(Math.floor(width/8)-4,Math.floor(height/8)+1);
83 | set_alive(Math.floor(width/8)-3,Math.floor(height/8)-2);
84 | set_alive(Math.floor(width/8)-3,Math.floor(height/8)+2);
85 | set_alive(Math.floor(width/8)-2,Math.floor(height/8)-3);
86 | set_alive(Math.floor(width/8)-2,Math.floor(height/8)+3);
87 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)-3);
88 | set_alive(Math.floor(width/8)-1,Math.floor(height/8)+3);
89 |
90 | set_alive(Math.floor(width/8),Math.floor(height/8));
91 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)-2);
92 | set_alive(Math.floor(width/8)+1,Math.floor(height/8)+2);
93 | set_alive(Math.floor(width/8)+2,Math.floor(height/8)-1);
94 | set_alive(Math.floor(width/8)+2,Math.floor(height/8));
95 | set_alive(Math.floor(width/8)+2,Math.floor(height/8)+1);
96 | set_alive(Math.floor(width/8)+3,Math.floor(height/8));
97 |
98 |
99 |
100 | set_alive(Math.floor(width/8)+6,Math.floor(height/8)-1);
101 | set_alive(Math.floor(width/8)+6,Math.floor(height/8)-2);
102 | set_alive(Math.floor(width/8)+6,Math.floor(height/8)-3);
103 | set_alive(Math.floor(width/8)+7,Math.floor(height/8)-1);
104 | set_alive(Math.floor(width/8)+7,Math.floor(height/8)-2);
105 | set_alive(Math.floor(width/8)+7,Math.floor(height/8)-3);
106 |
107 | set_alive(Math.floor(width/8)+8,Math.floor(height/8));
108 | set_alive(Math.floor(width/8)+8,Math.floor(height/8)-4);
109 | set_alive(Math.floor(width/8)+10,Math.floor(height/8));
110 | set_alive(Math.floor(width/8)+10,Math.floor(height/8)+1);
111 | set_alive(Math.floor(width/8)+10,Math.floor(height/8)-4);
112 | set_alive(Math.floor(width/8)+10,Math.floor(height/8)-5);
113 |
114 |
115 |
116 | set_alive(Math.floor(width/8)+20,Math.floor(height/8)-3);
117 | set_alive(Math.floor(width/8)+20,Math.floor(height/8)-2);
118 | set_alive(Math.floor(width/8)+21,Math.floor(height/8)-3);
119 | set_alive(Math.floor(width/8)+21,Math.floor(height/8)-2);
120 |
121 | break;
122 | case "Stripes":
123 | for (var i = 0; i < Math.floor(width/4); i=i+2) {
124 | for (var j = 0; j < Math.floor(height/4); j++) {
125 | set_alive(i,j);
126 | }
127 | }
128 | break;
129 | case "Image":
130 |
131 | var img = new Image();
132 | img.onload = function() {
133 | document.getElementById("image").getContext("2d").drawImage(img,0,0, Math.floor(width/4), Math.floor(height/4));
134 |
135 | var imageData = document.getElementById("image").getContext("2d").getImageData(0, 0, Math.floor(width/4), Math.floor(height/4));
136 |
137 | var lightness_max = 0;
138 | var lightness_min = 255;
139 | var lightness_array = new Array(Math.floor(width/4));
140 |
141 | for (var x = 0; x < Math.floor(width/4); x++) {
142 | lightness_array[x] = new Array(Math.floor(height/4));
143 | for (var y = 0; y < Math.floor(height/4); y++) {
144 | var lightness = 0;
145 | var index = (y*imageData.width + x) * 4;
146 | var red = parseInt(imageData.data[index]);
147 | var green = parseInt(imageData.data[index + 1]);
148 | var blue = parseInt(imageData.data[index + 2]);
149 | lightness = parseInt((0.2126*red) + (0.7152*green) + (0.0722*blue));
150 | if (lightness > lightness_max) { lightness_max = lightness; }
151 | if (lightness < lightness_min) { lightness_min = lightness; }
152 | lightness_array[x][y] = lightness;
153 | }
154 | }
155 | med_lightness = 0.5*(lightness_max+lightness_min);
156 |
157 | for (var x = 0; x < Math.floor(width/4); x++) {
158 | for (var y = 0; y < Math.floor(height/4); y++) {
159 | if (lightness_array[x][y] <= med_lightness) {
160 | set_alive(x,y);
161 | }
162 | }
163 | }
164 |
165 | };
166 | img.src = document.getElementById("img_image").src;
167 | }
168 |
169 |
170 | var i = 0;
171 | setTimeout(function () {
172 | get_next_step(1);
173 | }, timeout);
174 |
175 | }
176 |
177 |
178 |
179 | this.set_stop = function() {
180 | stop = true;
181 | }
182 |
183 | function create_grid() {
184 | ctx.strokeStyle = '#eee';
185 | ctx.lineWidth = 1;
186 | ctx.beginPath();
187 | //vertical
188 | for(var i = 0; i <= Math.floor(width/4); i++) {
189 | ctx.moveTo(i*4,0);
190 | ctx.lineTo(i*4,500);
191 | ctx.stroke();
192 | }
193 | //horizontal
194 | for(var i = 0; i <= Math.floor(width/4); i++) {
195 | ctx.moveTo(0,i*4);
196 | ctx.lineTo(1000,i*4);
197 | ctx.stroke();
198 | }
199 | ctx.closePath();
200 | }
201 |
202 | function random_alive(nr) {
203 | var i = 0;
204 | while (i < nr) {
205 | var xrand = Math.floor(Math.random() * (Math.floor(width/4)));
206 | var yrand = Math.floor(Math.random() * (Math.floor(height/4)));
207 | if (GoL_array[xrand][yrand] == 0) {
208 | set_alive(xrand,yrand);
209 | i++;
210 | }
211 | }
212 | }
213 |
214 | function set_alive(x,y) {
215 | ctx.fillStyle = '#000000';
216 | GoL_array[x][y] = 1;
217 | ctx.fillRect(x*4+1,y*4+1,2,2);
218 | }
219 |
220 | function set_dead(x,y) {
221 | ctx.fillStyle = '#FFFFFF';
222 | GoL_array[x][y] = 0;
223 | ctx.fillRect(x*4+1,y*4+1,2,2);
224 | }
225 |
226 |
227 | function get_next_step(step) {
228 | if (stop === false && step < steps) {
229 | for (var x=0; x < Math.floor(width/4); x++) {
230 | for (var y=0; y < Math.floor(height/4); y++) {
231 | var c_dead = 0;
232 |
233 | for (var sx=x-1; sx<=x+1; sx++) {
234 | for (var sy=y-1; sy<=y+1; sy++) {
235 | if (sx == -1 || sx == Math.floor(width/4) || sy == -1 || sy == Math.floor(height/4)) {
236 | c_dead++;
237 | }else {
238 | if (GoL_array[sx][sy] == 0) { c_dead++; }
239 | }
240 | }
241 | }
242 |
243 | state = GoL_array[x][y];
244 | switch (state) {
245 | case 0: // dead
246 | c_dead--;
247 | if (c_dead == 5) { // exactly 3 alive
248 | next_GoL_array[x][y] = 1;
249 | }
250 | break;
251 | case 1: // alive
252 | if (c_dead >= 7 || c_dead < 5) { // <2 alive or >3
253 | next_GoL_array[x][y] = 0;
254 | }
255 | if (c_dead == 5 || c_dead == 6) {
256 | next_GoL_array[x][y] = 1;
257 | }
258 | break;
259 | }
260 |
261 | }
262 |
263 | }
264 |
265 | for (var x=0; x < Math.floor(width/4); x++) {
266 | for (var y=0; y < Math.floor(height/4); y++) {
267 | GoL_array[x][y] = next_GoL_array[x][y];
268 | }
269 | }
270 |
271 | show_state();
272 | step++;
273 | setTimeout(function () {
274 | get_next_step(step);
275 | }, timeout);
276 | }
277 | }
278 |
279 | function show_state() {
280 | var alive = 0;
281 | for (var x=0; x < Math.floor(width/4); x++) {
282 | for (var y=0; y < Math.floor(height/4); y++) {
283 | if (GoL_array[x][y] == 0) {
284 | set_dead(x,y);
285 | } else {
286 | set_alive(x,y);
287 | alive++;
288 | }
289 | }
290 | }
291 | }
292 | }
--------------------------------------------------------------------------------