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">
4 <title>tendrils
</title>
5 <style type=
"text/css">
6 body
{background-color: #000}
24 display: inline-block
;
33 <script type=
"text/javascript">
36 switch (arguments
.length
) {
41 if(a
instanceof Array
)
42 return a
[Math
.floor(Math
.random()*a
.length
)];
44 return Math
.random() * a
;
47 return a
+ Math
.random() * (b
- a
);
53 switch (arguments
.length
) {
55 return Math
.floor(Math
.random() * a
);
58 return Math
.floor(a
+ Math
.random() * (b
- a
));
63 if(!('contains' in Array
.prototype))
64 Array
.prototype.contains = function(needle
){
66 while(i
-->0)if(this[i
] == needle
)return true;
70 var maxchannel
= 0xff;
71 function Color(r
, g
, b
) {
75 else if (a
> maxchannel
) return maxchannel
;
80 a
= Math
.floor(a
).toString(16);
81 return a
.length
== 1 ? '0' + a
: a
;
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 () {
108 var int = rnd(.5, .7);
115 case 0: r
= (int - wg
* g
- wb
* b
) / wr
;
117 case 1: g
= (int - wr
* r
- wb
* b
) / wg
;
119 case 2: b
= (int - wg
* g
- wr
* r
) / wb
;
123 return new Color(r
* maxchannel
, g
* maxchannel
, b
* maxchannel
);
126 function mkArray(n
, newvalfn
) {
131 map
.push(newvalfn(i
));
137 function mkMatrix(n
, m
, newvalfn
) {
144 while (++j
< m
) row
.push(newvalfn(i
, j
));
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
];
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];
175 var allColor
= Color
.random();
176 console
.log(allColor
.toString());
178 var Walker = function (coord
, dir
, 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');
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
)
211 var tryNewDir = function (i
, j
, fn
) {
214 var dir
= walker
.dir
;
216 while (retr
-- > 0 && next
== null) {
217 var dir
= rndi(numdirs
);
220 next
= getValidNext([i
, j
], dir
);
226 var branchSmall
= .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
) })());
242 while (walker
= walkers
.pop()) {
247 if (walker
.power
<= 0) {
248 map
[i
][j
] = walker
.fill
.dim(.9);
249 --walker
.power
; // dead will have -1;
253 map
[i
][j
] = walker
.fill
;
257 var loan
= Math
.round(rnd(pool
));
258 walker
.power
+= loan
;
264 if (rnd() < .1) { // random change of direction
265 nextdir
= tryNewDir(i
, j
);
268 if (next
) walker
.dir
= dir
;
272 next
= getValidNext([i
, j
], walker
.dir
);
274 if (!next
) { // forced change of direction
275 nextdir
= tryNewDir(i
, j
);
279 if (next
) walker
.dir
= dir
;
286 walker
.fill
= walker
.fill
.dim(.98);
289 walkers
.unshift(walker
);
291 var shareRatio
= rnd() < pbig
? branchBig
: branchSmall
;
292 var share
= Math
.round(rnd(walker
.power
* shareRatio
));
295 var nextdir
= tryNewDir(i
, j
, function (dir
) { return dir
!= walker
.dir
&& dir
!= walker
.dir
});
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
;
308 if (walker
.parent
.power
== -1) {
309 walker
.parent
.power
= walker
.power
;
310 walkers
.push(walker
.parent
);
313 walker
.parent
.power
+= walker
.power
;
318 pool
+= walker
.power
;
327 console
.log('wasted: ' + pool
);
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
) {
343 text
.push('<div class="cell" style="color: '+col
+'">●</div>');
350 return text
.join('');
353 t
.innerHTML
= render();