Rubik's cube 5x5x5 edgeswap added.
[zzandy.git] / tendrils / index.html
blob4f827385b1093daf4303a67bc64634772d113a00
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <title>tendrils</title>
5 <style type="text/css">
6 body{background-color: #000}
7 div.field
9 margin: 0 auto;
10 font-size:9pt;
12 div.col
14 margin: 0;
15 float: left;
16 width: 6px;
18 div.col.odd
20 margin-top:3px;
22 div.cell
24 display: inline-block;
25 width: 6px;
26 height: 6px;
28 </style>
29 </head>
30 <body>
31 <div id="target">
32 </div>
33 <script type="text/javascript">
35 function rnd(a,b) {
36 switch (arguments.length) {
37 case 0:
38 return Math.random();
39 break;
40 case 1:
41 if(a instanceof Array)
42 return a[Math.floor(Math.random()*a.length)];
44 return Math.random() * a;
45 break;
46 case 2:
47 return a + Math.random() * (b - a);
48 break;
52 function rndi(a,b) {
53 switch (arguments.length) {
54 case 1:
55 return Math.floor(Math.random() * a);
56 break;
57 case 2:
58 return Math.floor(a + Math.random() * (b - a));
59 break;
63 if(!('contains' in Array.prototype))
64 Array.prototype.contains = function(needle){
65 var i=this.length;
66 while(i-->0)if(this[i] == needle)return true;
67 return false;
70 var maxchannel = 0xff;
71 function Color(r, g, b) {
73 function bound(a) {
74 if (a < 0) return 0;
75 else if (a > maxchannel) return maxchannel;
76 return a;
79 function octet(a) {
80 a = Math.floor(a).toString(16);
81 return a.length == 1 ? '0' + a : a;
84 r = bound(r);
85 g = bound(g);
86 b = bound(b);
88 // make color darker - k between 0 and 1
89 this.dim = function (k) {
90 return new Color(r * k, g * k, b * k);
93 // randomly change color - k between 0 and 1
94 this.deviate = function (k) {
95 return new Color(rnd(r * (1 - k), r * (1 + k)), rnd(g * (1 - k), g * (1 + k)), rnd(b * (1 - k), b * (1 + k)));
98 this.toString = function () {
99 return '#' + octet(r) + octet(g) + octet(b);
103 Color.random = function () {
104 var wr = .41;
105 var wg = .37;
106 var wb = .22;
108 var int = rnd(.5, .7);
110 var r = rnd();
111 var g = rnd();
112 var b = rnd();
114 switch (rndi(3)) {
115 case 0: r = (int - wg * g - wb * b) / wr;
116 break;
117 case 1: g = (int - wr * r - wb * b) / wg;
118 break;
119 case 2: b = (int - wg * g - wr * r) / wb;
120 break;
123 return new Color(r * maxchannel, g * maxchannel, b * maxchannel);
126 function mkArray(n, newvalfn) {
127 var map = [];
129 var i = -1;
130 while (++i < n) {
131 map.push(newvalfn(i));
134 return map;
137 function mkMatrix(n, m, newvalfn) {
138 var map = [];
140 var i = -1;
141 while (++i < n) {
142 var j = -1;
143 var row = [];
144 while (++j < m) row.push(newvalfn(i, j));
146 map.push(row);
149 return map;
152 function arci(co, r, a) {
153 return [Math.round(co[0] + r * Math.sin(2 * Math.PI * a)), Math.round(co[1] + r * Math.cos(2 * Math.PI * a))];
156 var dirs2n = [[-1, -1], [-1, 0], [-1, 1], [0, 1], [1, 0], [0, -1]];
157 var dirs2n1= [[0, -1], [-1, 0], [0, 1], [1, 1], [1, 0], [1, -1]];
159 var numdirs = dirs2n.length;
161 function getDir(id, i, j) {
162 if (id < 0 || id > dirs2n.length) id = rndi(dirs2n.length);
164 var dir = (j % 2) ? dirs2n1[id] : dirs2n[id];
165 return dir;
168 // numdirs = 4;
169 // getDir = function (id, i, j) {
170 // if (id < 0 || id > numdirs) id = rndi(numdirs);
172 // return [[-1, 0], [0, 1], [1, 0], [0, -1]][id];
173 // }
175 var allColor = Color.random();
176 console.log(allColor.toString());
178 var Walker = function (coord, dir, power) {
179 this.i = coord[0];
180 this.j = coord[1];
181 this.dir = dir;
182 this.power = power;
183 this.fill = allColor.deviate(.2);
186 function constant(val){return function(){return val}}
187 function args(){return [].join.call(arguments, 'x')}
189 var t = document.getElementById('target');
191 var aspect = 4/3;
192 var w = 128;
193 var h = Math.floor(w / aspect);
195 var empty = new Color(9,9,9);
197 function renderMap() {
198 var map = mkMatrix(h, w, constant(empty));
200 var getValidNext = function (coord, dirId) {
201 var dir = getDir(dirId, coord[0], coord[1]);
203 var i = coord[0] + dir[0];
204 var j = coord[1] + dir[1];
206 return (i >= 0 && j >= 0 && i < h && j < w && map[i][j] == empty)
207 ? { i: i, j: j }
208 : null;
211 var tryNewDir = function (i, j, fn) {
212 var next = null;
213 var retr = 3;
214 var dir = walker.dir;
216 while (retr-- > 0 && next == null) {
217 var dir = rndi(numdirs);
219 if (!fn || fn(dir))
220 next = getValidNext([i, j], dir);
223 return [next, dir];
226 var branchSmall = .2;
227 var branchBig = .5;
228 var pbig = .2;
230 var numwalkers = numdirs*2;
231 var fillfactor = .25;
232 var startingPower = Math.round(w * h * fillfactor / numwalkers);
234 var o = [Math.floor(h / 2), Math.round(w / 2 + w / 8)];
235 var makeWalker = function (i) { var dir = getDir(i, o[0], o[1]); return new Walker([o[0] + dir[0], o[1] + dir[1]], i, startingPower) };
237 var walkers = mkArray(numwalkers / 2, makeWalker).concat((function () { o = [Math.floor(h / 2), Math.round(w / 2 - w / 8)]; allColor = Color.random(); return mkArray(numwalkers / 2, makeWalker) })());
239 var walker;
240 var pool = 0;
242 while (walker = walkers.pop()) {
244 var i = walker.i;
245 var j = walker.j;
247 if (walker.power <= 0) {
248 map[i][j] = walker.fill.dim(.9);
249 --walker.power; // dead will have -1;
251 else {
253 map[i][j] = walker.fill;
254 --walker.power;
256 if (pool > 0) {
257 var loan = Math.round(rnd(pool));
258 walker.power += loan;
259 pool -= loan;
262 var next = null;
264 if (rnd() < .1) { // random change of direction
265 nextdir = tryNewDir(i, j);
266 next = nextdir[0];
267 dir = nextdir[1];
268 if (next) walker.dir = dir;
271 if (!next) {
272 next = getValidNext([i, j], walker.dir);
274 if (!next) { // forced change of direction
275 nextdir = tryNewDir(i, j);
276 next = nextdir[0];
277 dir = nextdir[1];
279 if (next) walker.dir = dir;
283 if (next) {
284 walker.i = next.i;
285 walker.j = next.j;
286 walker.fill = walker.fill.dim(.98);
288 // continue movement
289 walkers.unshift(walker);
291 var shareRatio = rnd() < pbig ? branchBig : branchSmall;
292 var share = Math.round(rnd(walker.power * shareRatio));
294 if (share > 0) {
295 var nextdir = tryNewDir(i, j, function (dir) { return dir != walker.dir && dir != walker.dir });
296 next = nextdir[0];
297 dir = nextdir[1];
299 if (next) { // add new spawn to the end
300 walkers.push({ i: next.i, j: next.j, dir: dir, power: share, parent: walker, fill: walker.fill });
301 walker.power -= share;
305 else {
307 if (walker.parent) {
308 if (walker.parent.power == -1) {
309 walker.parent.power = walker.power;
310 walkers.push(walker.parent);
312 else {
313 walker.parent.power += walker.power;
316 else {
318 pool += walker.power;
321 walker.power = -1;
327 console.log('wasted: ' + pool);
329 return map;
332 function render() {
333 var map = renderMap();
335 var text = ['<div class="field">'];
337 for (var j = 0; j < w; ++j) {
338 if (j % 2) text.push('<div class="col odd">');
339 else text.push('<div class="col">');
341 for (var i = 0; i < h; ++i) {
342 var col = map[i][j];
343 text.push('<div class="cell" style="color: '+col+'">&#x25cf;</div>');
346 text.push('</div>');
349 text.push('</div>');
350 return text.join('');
353 t.innerHTML = render();
355 </script>
356 </body>
357 </html>