|
|
|
|
|
|
|
function rule_applicable(word, pos, consumed, rule) {
|
|
|
|
for(let i=0; i<rule.length; i++) {
|
|
|
|
if((word[pos+i] != rule[i]) | (consumed[pos+i] == true)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function generate(start, rules, iterations) {
|
|
|
|
if(iterations == 0) {
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
|
|
|
var word = start;
|
|
|
|
var consumed = new Array(word.length);
|
|
|
|
for(let rule of rules) {
|
|
|
|
let pos = 0;
|
|
|
|
var newword = [];
|
|
|
|
var newconsumed = [];
|
|
|
|
while(pos < word.length) {
|
|
|
|
if(rule_applicable(word, pos, consumed, rule[0])) {
|
|
|
|
var ruleres;
|
|
|
|
if(typeof rule[1] == 'function') {
|
|
|
|
ruleres = rule[1]();
|
|
|
|
} else if(typeof rule[1] == 'object') {
|
|
|
|
var r = Math.floor(Math.random() * rule[1].length);
|
|
|
|
ruleres = rule[1][r];
|
|
|
|
}else {
|
|
|
|
ruleres = rule[1];
|
|
|
|
}
|
|
|
|
newword += ruleres;
|
|
|
|
for(let i=0; i<ruleres.length; i++) {
|
|
|
|
newconsumed.push(true);
|
|
|
|
}
|
|
|
|
pos += rule[0].length;
|
|
|
|
} else {
|
|
|
|
newword += word[pos];
|
|
|
|
newconsumed.push(false);
|
|
|
|
pos += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
word = newword;
|
|
|
|
consumed = newconsumed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return generate(newword, rules, iterations - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_initstate(grp, state) {
|
|
|
|
if(!('dir' in state)) {
|
|
|
|
state.dir = 0;
|
|
|
|
state.turnnoise = 0;
|
|
|
|
state.lennoise = 0;
|
|
|
|
state.pos = new paper.Point(0, 0);
|
|
|
|
state.pathstack = [];
|
|
|
|
state.stepsize = 1;
|
|
|
|
state.stack = [];
|
|
|
|
state.curpath = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
for(let i=0; i<10; i++) {
|
|
|
|
var color = new paper.Color(255,255,255);
|
|
|
|
color.saturation = 1;
|
|
|
|
color.brightness = 1;
|
|
|
|
color.hue = 36 * (10-i); // TODO remove constant
|
|
|
|
state.palette.push(color);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
state.palette = [
|
|
|
|
new paper.Color('#ff0000'),
|
|
|
|
new paper.Color('#ff0000'),
|
|
|
|
new paper.Color('#ff00ff'),
|
|
|
|
new paper.Color('#ff00ff'),
|
|
|
|
new paper.Color('#0000ff'),
|
|
|
|
new paper.Color('#0000ff'),
|
|
|
|
new paper.Color('#00ff00'),
|
|
|
|
new paper.Color('#00ff00'),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_set_dir(dir) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.dir = dir;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_set_turn_noise(level) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.turnnoise = level;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_set_length_noise(level) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.lennoise = level;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_forward(factor=1) {
|
|
|
|
return function(grp, state) {
|
|
|
|
if(state.curpath == null) {
|
|
|
|
var p = new paper.Path();
|
|
|
|
p.add(state.pos);
|
|
|
|
state.curpath = p;
|
|
|
|
// index 0 corresponds to empty state.stack
|
|
|
|
if(state.pathstack[state.stack.length] == null) {
|
|
|
|
var cp = new paper.CompoundPath();
|
|
|
|
cp.addChild(p);
|
|
|
|
cp.strokeColor = state.palette[state.stack.length];
|
|
|
|
state.pathstack[state.stack.length] = cp;
|
|
|
|
grp.addChild(cp);
|
|
|
|
}
|
|
|
|
state.pathstack[state.stack.length].addChild(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
var lastp = state.curpath.segments[state.curpath.segments.length - 1].point;
|
|
|
|
var noise = 1 + (Math.random() - 0.5) * state.lennoise;
|
|
|
|
state.curpath.add(lastp.add(new paper.Point(
|
|
|
|
Math.sin(state.dir) * state.stepsize * factor * noise,
|
|
|
|
Math.cos(state.dir) * state.stepsize * factor * noise
|
|
|
|
)));
|
|
|
|
var lastseg = state.curpath.segments[state.curpath.segments.length - 1];
|
|
|
|
state.pos = lastseg.point;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_stepsize_mul(factor) {
|
|
|
|
return function(p, state) {
|
|
|
|
if(typeof factor == 'function') {
|
|
|
|
var f = factor();
|
|
|
|
} else {
|
|
|
|
var f = factor;
|
|
|
|
}
|
|
|
|
state.stepsize *= f;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_turn(angle) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.dir += angle;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_angle_turn(fac) {
|
|
|
|
return function(p, state) {
|
|
|
|
var a = state.angle * (1 + (Math.random() - 0.5) * state.turnnoise);
|
|
|
|
state.dir += a * fac;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_angle_init(angle) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.angle = angle;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_angle_add(delta) {
|
|
|
|
return function(p, state) {
|
|
|
|
state.angle += delta;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_state_push() {
|
|
|
|
return function(grp, state) {
|
|
|
|
state.stack.push({
|
|
|
|
pos: state.pos,
|
|
|
|
dir: state.dir,
|
|
|
|
stepsize: state.stepsize,
|
|
|
|
});
|
|
|
|
state.curpath = null;
|
|
|
|
/*
|
|
|
|
if(state.palette[state.stack.length] !=
|
|
|
|
state.palette[state.stack.length - 1]) {
|
|
|
|
p.addChild(new paper.Path());
|
|
|
|
state.curpath = p.lastChild;
|
|
|
|
state.curpath.add(pos);
|
|
|
|
state.curpath.strokeColor = state.palette[state.stack.length];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw_state_pop() {
|
|
|
|
return function(grp, state) {
|
|
|
|
var s = state.stack.pop();
|
|
|
|
state.dir = s.dir;
|
|
|
|
state.stepsize = s.stepsize;
|
|
|
|
state.pos = s.pos;
|
|
|
|
state.curpath = null;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function draw(word, actions) {
|
|
|
|
var grp = new paper.Group();
|
|
|
|
var state = {};
|
|
|
|
draw_initstate(grp, state);
|
|
|
|
for(let w of word) {
|
|
|
|
if(w in actions) {
|
|
|
|
actions[w](grp, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return grp;
|
|
|
|
}
|