Skip to content

Instantly share code, notes, and snippets.

@dribnet
Forked from carlgordon64/.block
Last active October 19, 2016 13:04
Show Gist options
  • Save dribnet/18d482f5df02d15837de616d46dba6f9 to your computer and use it in GitHub Desktop.
Save dribnet/18d482f5df02d15837de616d46dba6f9 to your computer and use it in GitHub Desktop.
Online Chatbox
license: mit
// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
function saveBlocksImages(doZoom) {
if(doZoom == null) {
doZoom = false;
}
// generate 960x500 preview.jpg of entire canvas
// TODO: should this be recycled?
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 960;
offscreenCanvas.height = 500;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 960, 500);
context.drawImage(this.canvas, 0, 0, 960, 500);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/jpeg');
imageData = imageData.replace('image/jpeg', downloadMime);
p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');
// generate 230x120 thumbnail.png centered on mouse
offscreenCanvas.width = 230;
offscreenCanvas.height = 120;
// background is flat white
context = offscreenCanvas.getContext('2d');
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 230, 120);
if(doZoom) {
// pixelDensity does the right thing on retina displays
var pd = this._pixelDensity;
var sx = pd * mouseX - pd * 230/2;
var sy = pd * mouseY - pd * 120/2;
var sw = pd * 230;
var sh = pd * 120;
// bounds checking - just displace if necessary
if (sx < 0) {
sx = 0;
}
if (sx > this.canvas.width - sw) {
sx = this.canvas.width - sw;
}
if (sy < 0) {
sy = 0;
}
if (sy > this.canvas.height - sh) {
sy = this.canvas.height - sh;
}
// save to browser
context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
}
else {
// now scaledown
var full_width = this.canvas.width;
var full_height = this.canvas.height;
context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
}
imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}

PS3 MDDN 342 2016

Final Twitter Bot - Survival Maze

Part 2 -

The Artifact my generator makes is a procedural survival story set in a maze. The hero of the story is a character who is endlessly looking for a way out. Our hero's only chance at surviving is by running between shelters, searching for food while dodiging dangerous creatures at every turn. The maze itself is works on a real-time day and night cycle with weather events controlled by real local weather conditions. The concrete properties that drive the events within the story are:

Character Position (x,y),Monster 1 Position (x,y),Monster 2 Position (x,y), Shelter Position (x,y), Food / Lifepoints Position (x,y)

These properties are initally set to randomized values within the maze however if the character comes within a controlled pixel radius of any of the objects he jumps to them to investigate causing various interactions with the objects.

time of day is represented in a cycle of four stages of the day: Early-morning, Morning, Afternoon and Night. This was a design consideration that I developed to break up the monotony of the generated artifact. I also added a zoom function to randomly zoom in on the maze to change the scenery slightly.

weather is sourced from YahooWeather API for Wellington city and the climate of the maze is set to local temperature + conditions.

-how will I make sure the artifact has good properties?

I have used some extra constraints to determine the results of the artifact. There is a random spin array with values 1 - 10 that helps provides controlled randomness for determining the text events in the story. The generated text uses Tracery to assist in forming a paragraph that makes sense. This is also randomized and driven by arrays of potential text options.

GREEN BOT. Because this version of my bot uses Yahoo Weather to control condition variables within the maze / storyline the open data coming in should enrich the randomness of the artifact making it a green bot.

function bot() {
this.url = 'https://query.yahooapis.com/v1/public/yql?q=select%20item.forecast%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22wellington%2Cnz%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys'
this.weatherData;
this.url2 = 'https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22wellington%2Cnz%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys'
this.weatherData2;
this.temperatures3 = [];
var LegitTemp;
this.temperatures = [];
this.temperatures2 = [];
this.conditions = [];
var currentTemp;
var RealTemp;
var currentTemp2;
var RealTemp2;
var po;
var op;
var condit;
var Hitemp;
var Lotemp;
var avTemp;
var currentCondit;
var daycount = 0;
var findShelter = false;
var x;
var y;
var easing = 0.05;
var night;
var forecast;
var d = new Date();
var n = d.getHours();
if(n>=18){
//6pm onwards
daycount=1;
}
var hp=100;
var charX2;
var charY2;
var charX;
var charY;
var zombX;
var zombY;
var foodX;
var foodY;
var findFood = false;
var shelterX;
var shelterY;
var chaserdiffX;
var chaserdiffY;
var zombiediffX;
var zombiediffY;
var shelterdiffX;
var shelterdiffY;
var fooddiffX;
var fooddiffY;
var inspire = ["you live on to fight another day","Nothing can touch you"];
var death=random(inspire);
var isHidden=false;
var isDead=false;
var isDetect=false;
var isWarm=false;
var hidden = [""];
var ninja=random(hidden);
//status
var incognito = ["they can't see me here","I think it's safe here","the path ahead looks safe"];
var inshelter = ["Its nice in here","I might have to stay a while","I better rest up here for a bit","I dont think they will find me here","you run into a small hutt and hide yourself with leaves","for the first time in a while, you feel safe."];
var eating = ["the food protects you temporarily","time to rest up","you feel your energy replenishing","you feel strong"];
var insight = ["they are getting closer","you come face to face with the beast","I can hear heavy breathing nearby","you're being hunted","a silent croaking sound stops you in your tracks.","You spot a pair of eyes gazing at you through the corn..","I can hear something tracking my scent"];
var attack = ["it swipes at you with long claws","it leaps out and bites you with sharp fangs","you feel a quick swipe at your legs!"];
//chaser collision
var risk =random(incognito);
var collision = false;
//filters to decide story plot
var spinarray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var spin = random(spinarray);
var spin2 = random(spinarray);
var spin3 = random(spinarray);
//early-morning shades
var day1 = color(0,111,73);
var day2 = color(18,84,56);
var day3 = color(32, 47, 30);
//morning shades
var day4 = color(86, 111, 0);
var day5 = color(64, 74, 20);
var day6 = color(28, 48, 25);
//afternoon shades
var day7 = color(0, 128, 0);
var day8 = color(0, 100, 0);
var day9 = color(20, 70, 0);
//night shades
var day10 = color(0, 53, 52);
var day11 = color(19, 72, 69);
var day12 = color(0, 40, 46);
this.preload = function() {
this.weatherData = loadJSON(this.url);
this.weatherData2 = loadJSON(this.url2);
console.log();
}
this.setup = function() {
//GET WEATHER RESULTS
var results = this.weatherData["query"]["results"]["channel"];
//todays WEATHER CONDITIONS : COND : HIGH : LOW
for(var i=0;i<results.length;i++) {
var forecast = results[i]["item"]["forecast"]
var pair = [
//todays HIGH
forecast["text"],parseInt(forecast["high"], 10)
]
//todays LOW
var pair2 = [
forecast["text"],parseInt(forecast["low"], 10)
]
//high
this.temperatures.push(pair)
//low
this.temperatures2.push(pair2)
}
console.log("COND " + this.temperatures[1][0])
condit = this.temperatures[1][0];
console.log("HIGH " + this.temperatures[0][1])
Hitemp = this.temperatures[0][1];
console.log("LOW " + this.temperatures2[0][1])
Lotemp = this.temperatures2[0][1];
//console.log("TOMORROW " + this.temperatures[1][0])
}
this.isDone = function() {
return true;
}
this.grammar = {
"travelState": ["travelling","investigating"],
"animal": ["bird","animal","creature","sun rising","night-watcher","sun set","shadowy-figure"],
"reaction": ["vexing","perplexing","exciting","wistful","enigmatic"],
"prediction": ["prediction", "forecast", "prognostication"],
"timeunit": ["day", "night"],
"gender": ["he","she","it"],
"describe": ["he","she","it"],
"verb": ["leaped","crouched","hid","jumped","slid","sprinted","tiptioed","crawled","sprawled"],
"adjective": ["furiously", "crazily", "quietly","hastely","on all fours"],
"direction": ["up", "down", "around"],
"weatherCold": ["it was freezing in here", "wind was ripping through the maze", "the air was Ssssooo Cold."],
"weatherWarm": ["The warmth was almost relaxing", "a warm breeze swept the dry air", "The sun was too much"],
"weatherCondit": ["it was freezing in here", "wind was ripping through the maze", "the air was Ssssooo Cold."],
"observation": ["but its too early to run away", "but there were signs of struggle","It was an exhausting night.","I'm sure i'll come by some shelter soon","my bones were too frozen to run far","the air was ice cold","there was an eeire silence in the corn"],
"observation2": ["the sun started flooding the maze","the icy gorund was sterting to melt","its a miracle I survived the night","the ground is wet with dew", "I must escape today","there are strange footprints in the dew","but today was the day","there was a musty odour in the air","shivers went down my spine"],
"observation3": ["I should find shelter immediately", "but my instincts told me RUN!","but anything could be waiting around the next turn.","but how did I wake up here?","I'm sure i'll come by some shelter soon","there was a musty odour in the air","shivers went down my spine"],
"observation4": ["I hope they cant see me in the dark", "but the sign read 'go back now'","It was too late to stop now","The maze was glowing in the moonlight","Darkness had consumed the entire maze","I had never been so afraid of the dark"],
"deathstring": ["The creature drags you into the hedge", "I should have gone back","It was all a dream","I guess this is it","shivers went down my spine"],
"hidestring": ["They wont see me","Im a ghost"],
"detectstring": ["I really dont feel safe here","I think the corn has eyes"],
"location": ["bushes", "creepers", "garden","hedge","next turn","last safe place","shadows"],
"chance": ["there was a glimpse at escapse", "there was a bright light shining up ahead","there were strange markings in the dirt"],
"risk": ["nothing to lose.", "everything to lose.", "everything to gain.","everything to lose.","a slim chance at getting out","a slim chance at getting out","eaten away at my faith","chased me long enough","nowhere to run"],
"ending": ["but it only lead to more maze.","when suddenly... it all made sense.", "and luckily there was an opening.", "there was no possible way out.","but there was no way through the hedge.","the way back was long forgotten.","it was as if escape was never an option","I was put here for a reason","there was nothing but hedge for miles.","I must be getting close to an exit!"]
}
this.maze= function(){
//conditionals to workout time
//colour scheme will change along with survival risks
//TIME CYCLE
//night
if(n<=5){
background(day3);
var mazewall1 = day1;
var mazewall2 = day2;
night="early-morning";
}
if(n>5&&n<=11){
background(day6);
var mazewall1 = day4;
var mazewall2 = day5;
night="morning";
}
if(n>11&&n<=17){
background(day9);
var mazewall1 = day7;
var mazewall2 = day8;
night="afternoon";
}
if(n>17){
background(day12);
var mazewall1 = day10;
var mazewall2 = day11;
night="night";
}
//
push();
//move start ponts of the maze rows up and off the screen
translate(0,-10);
//options limit complexity of the maze
var options = [1, 2,3];
//scale should be set to 2 or less when travelling and 3 when investigating something
//travelling or investigating boolean
for( y=0; y < height; y+=20){
for( x=0; x < width; x+=20){
var tile_selection = random(options);
if(tile_selection == 1){
stroke(mazewall1);
for(h=0; h<=10; h++){
for(h2=0; h2<=2; h2++){
strokeWeight(1);
line(x+h2,y+h,x+20+h2,y+20+h);
}
}
stroke(40);
strokeWeight(0.5);
line(x,y,x+20,y+20);
} else {
stroke(mazewall2);
for(j=0; j<=10; j++){
for(j2=0; j2<=2; j2++){
strokeWeight(1);
line(x+20+j2,y+j,x+j2,y+20+j);
}
}
strokeWeight(0.5);
stroke(40);
line(x+20,y,x,y+20);
}
}
}
pop();
}
this.character= function(){
//character colour could change on respawn?
stroke(0, 103, 187);
//legs
strokeWeight(2);
line(-3, 3, -3, 13);
line(3, 3, 3, 13);
strokeWeight(2);
//neck
stroke(255, 212, 185);
line(0, -11, 0, 0);
//head
noStroke();
fill(255, 212, 185);
rect(-4, -19, 8, 10);
//body
noStroke();
fill(0, 103, 187);
ellipse(0, 4, 14, 14);
//clothes
fill(80);
//eyes
fill(255);
strokeWeight(1);
ellipse(-3, -12, 4, 2.5);
ellipse(3, -12, 4, 2.5);
fill(25);
ellipse(-3, -12, 2, 2);
ellipse(3, -12, 2, 2);
stroke(0, 103, 187);
}
//MONSTER CHARACTER / CHASER
this.monster= function(){
stroke(40);
//legs
strokeWeight(2);
line(-3,3,-3,13);
line(3,3,3,13);
strokeWeight(1);
//body
fill(94,99,79);
ellipse(0,0-2,12,14);
//head
stroke(40);
fill(94,99,79);
ellipse(0,0-12,9,10);
//clothes
fill(80);
//eyes
fill(255);
ellipse(-3,-12,4,2.5);
ellipse(3,-12,4,2.5);
fill(25);
ellipse(-2,-12,2,2);
ellipse(2,-12,2,2);
stroke(80);
//arms
strokeWeight(2);
line(-5,-5,-10,-3);
line(5,-5,10,-3);
}
//END MONSTER
//FOOD RESOURCE
this.food= function(){
fill(200, 0, 0);
stroke(200, 0, 0);
ellipse(-1, 1, 10, 10);
ellipse(11, 1, 10, 10);
ellipse(5, 5, 10, 10);
strokeWeight(5);
line(-3, 3, 5, 13);
line(13, 3, 5, 13);
}
//SHELTER
this.shelter= function(){
fill(56,54,33);
stroke(94,99,79);
strokeWeight(3);
for(o=0;o<=20;o++){
rect(0-o,0-o,40,40);
}
fill(40);
stroke(80);
noStroke();
beginShape();
//bot l
vertex(10, 40);
//bot r
vertex(30, 40);
//top r
vertex(15, 25);
//top l
vertex(-5, 25);
endShape();
//line details
stroke(20);
//inside door line
line(10, 38,10, 27);
strokeWeight(1);
line(-2, 40,-22, 20);
line(40, 40,22, 20);
//floor line
line(41, 0,41, 40);
//
line(40, -2,22, -20);
//roof line
line(-22, -20,-22, 20);
line(-22, -21,20, -21);
//smaller
line(-18, -18,-18, 18);
line(-18, -18,18, -18);
line(0, 41,40, 41);
fill(255);
}
this.respond = function() {
var travel = [1,2,3,4,5,6];
var travelspin = random(travel);
//calculates scale of the maze and character for zoom ins
if (travelspin <4) {
//travelling true
var zoom = 1.3;
}else{
//travelling false
var zoom = 2.3;
}
//storymode
//storymode helps decide when shelter/food/monster gets drawn
if(spin>="4"&&spin<="8"){
var storymode = 2;
}
if(spin<="3"){
var storymode = 1;
}
if(spin>="9"){
var storymode = 0;
}
//
push();
scale(zoom);
this.maze();
pop();
push();
//could decrease these width and height ranges to simulate fatigue or injuries
//lower ranges limit the area the character can travel each turn
charX2 = 10+random(width-20);
charY2 = 10+random(height-40);
translate(charX2,charY2);
scale(zoom/2);
this.character();
pop();
//ZOMBIE SPAWN
//logic for deciding when to draw zombies
if(storymode==2||storymode==1){
push();
//zombie ranges should be decreased with character ranges to increase the zombies likliness of attacking
charX = 10+random(width-20);
charY = 10+random(height-40);
if(chaserdiffX<50&&chaserdiffY<50){
translate(charX2,charY2);
if (findShelter==false&&findFood==false) {
hp=0;
collision = true;
risk =random(attack);
}else{
hp=100;
collision = false;
}
}
else{
translate(charX,charY);
}
scale(zoom/2);
this.monster();
pop();
}else{
charX = 300;
charY = 300;
}
//ZOMBIE 2
//logic for deciding when to draw zombies
if(spin<=5){
push();
zombX = 10+random(width-20);
zombY = 10+random(height-40);
if(zombiediffX<50&&zombiediffY<50){
translate(charX2,charY2);
if (findShelter==false&&findFood==false) {
hp=0;
collision = true;
risk =random(attack);
}else{
hp=100;
collision = false;
risk =random(eating);
}
}else{
translate(zombX,zombY);
}
scale(zoom/2);
this.monster();
pop();
}else{
zombX = 300;
zombY = 300;
}
//FOOD SPAWN
if(spin>1){
push();
//these ranges control the likliness of consuming food / potion
foodX = 10+random(width-20);
foodY = 10+random(height-40);
if(fooddiffX<50&&fooddiffY<50){
translate(charX2,charY2);
findFood=true;
risk =random(eating);
}else{
translate(foodX,foodY);
}
scale(zoom/3);
this.food();
pop();
}
//logic for deciding when to draw shelter
//draw shelter
if(spin>4){
push();
//these ranges control the likliness of finding shelter
shelterX = 10+random(width-20);
shelterY = 10+random(height-40);
if(shelterdiffX<50&&shelterdiffY<50){
translate(charX2,charY2);
findShelter=true;
risk =random(inshelter);
}else{
findShelter=false;
translate(shelterX,shelterY);
}
scale(zoom/2);
var deg = 45;
var rad = radians(deg);
rotate(rad);
this.shelter();
pop();
}
var genderRand1 = ["male", "female", "unknown"];
var activegen1 = random(genderRand1);
//decicive conditionals for the story
//gender
if(activegen1=="male"){
//var activegen = "he";
}else if(activegen1=="female"){
//var activegen = "she";
}else if(activegen1=="unknown"){
//var activegen = "it";
}
var who = ["it","he","I"]
var activegen = random(who);
textSize(14);
push();
//position health bar
translate(-10,0);
//HEALTH BAR
noStroke();
fill(255);
text(hp,45,height-27);
//text(t,100,height-20);
text(condit,width-100,height-10);
stroke(255);
fill(255);
for(j=0;j<=hp;j++){
ellipse(40+j,height-17,8,8);
fill(200,0,0);
ellipse(40+j,height-17,5,5);
}
//hearticon
fill(0,0,0);
noStroke();
fill(255);
ellipse(30,height-18,30,30);
fill(200,0,0);
stroke(200,0,0);
ellipse(24,height-20,10,10);
ellipse(36,height-20,10,10);
ellipse(30,height-15,10,10);
strokeWeight(5);
line(38,height-19,30,height-10);
line(21,height-19,30,height-10);
pop();
noStroke();
// set have_drawn to true since we have completed
this.have_drawn = true;
// construct the message
var grammar = tracery.createGrammar(this.grammar);
po = ["as soon as","when","at that moment","when suddenly"];
op = random(po);
altverb = ["touched","saw","spotted","felt","sensed"];
verbed = random(altverb);
var seed2 = op+" "+activegen+" "+verbed+ " the #animal# ";
if(night=="early-morning"){
var seed4 = "#observation#";
}
else if(night=="morning"){
var seed4 = "#observation2#";
}
else if(night=="afternoon"){
var seed4 = "#observation3#";
}
else if(night=="night"){
var seed4 = "#observation4#";
}
//
if(currentTemp>18){
var weatherseed = "#weatherWarm";
}
else {
var weatherseed = "#weatherCold";
}
var seed5 = "#chance#";
var seed = activegen + " #verb# #adjective# #direction# to the #location#";
var end = "#ending#";
var seed3 = activegen + " knew "+activegen+" had #risk#" ;
var message = grammar.flatten(seed);
var opener = grammar.flatten(seed2);
var weatherObserve = grammar.flatten(weatherseed);
var observe = grammar.flatten(seed4);
var hope = grammar.flatten(seed5);
var body = grammar.flatten(seed3);
var conclusion = grammar.flatten(end);
//process to calculate the distance between the player and the spawning objects
//food distance
if (charX2 > foodX){
fooddiffX= charX2-foodX;
}
else{
fooddiffX= foodX-charX2;
}
//shelter y distance
if (charY2 > foodY){
fooddiffY= charY2-foodY;
}
else{
fooddiffY= foodY-charY2;
}
//shelter distance
if (charX2 > shelterX){
shelterdiffX= charX2-shelterX;
}
else{
shelterdiffX= shelterX-charX2;
}
//shelter y distance
if (charY2 > shelterY){
shelterdiffY= charY2-shelterY;
}
else{
shelterdiffY= shelterY-charY2;
}
//CHASER DISTANCE TRACKER
//monster x distance
if (charX2 > charX){
chaserdiffX= charX2-charX;
}
else{
chaserdiffX= charX-charX2;
}
//monster y distance
if (charY2 > charY){
chaserdiffY= charY2-charY;
}
else{
chaserdiffY= charY-charY2;
}
//
//possible states of the zombie & chaser: incognito, insight or attack based on the distance between him and our character
//ZOMBIE & CHASER DETECTION PARAMETERS
//very-close Y and semi-close X
if(zombiediffX<90&&zombiediffX>0 || chaserdiffX<90&&chaserdiffX>0 ){
if(zombiediffY<90&&zombiediffY>0 || chaserdiffY<90&&chaserdiffY>0 ){
risk =random(insight);
isDetect=true;
/*
var detectseed = "#detectstring#";
detect = grammar.flatten(detectseed);
isDetect=true;
*/
}
}else{
risk =random(incognito);
isHidden=true;
/*
var hideseed = "#hidestring#";
ninja = grammar.flatten(hideseed);
isHidden=true;
*/
}
if(zombiediffX<50&&zombiediffY<50 || chaserdiffX<50&&chaserdiffY<50){
risk =random(attack);
isDead=true;
}
//ZOMBIE DISTANCE TRACKER
//zombie x distance
if (charX2 > zombX){
zombiediffX= charX2-zombX;
}
else{
zombiediffX= zombX-charX2;
}
//zombie y distance
if (charY2 > zombY){
zombiediffY= charY2-zombY;
}
else{
zombiediffY= zombY-charY2;
}
//stats
//return " Temprature:"+"<br> Days survived: "+ daycount+"<br> hours survived: "+n+"<br> Nighttime?: "+night+"<br> shelter x dist: "+shelterdiffX+"<br> shelter y dist: "+shelterdiffY+"<br> chaser x dist: "+chaserdiffX+"<br> chaser y dist: "+chaserdiffY+"<br> zombie x dist: "+zombiediffX+"<br> zombie y dist: "+zombiediffY+"<br> food x dist: "+fooddiffX+"<br> food y dist: "+fooddiffY+"<br> zombie attack: "+collision+"<br> shelter: "+findShelter+"<br> food pickup: "+findFood+"<br> storymode: "+storymode;
//AV TEMP is a hack to work out todays temprature non directly.
//It takes todays Low and High values and finds the average.
//works out average temp from high and low
avTemp = (Hitemp+Lotemp)/(2);
//convert avTemp to celcius
RealTemp = (avTemp-32)*(5/9);
//cap float at 2dp
ActualTemp = RealTemp.toFixed(2);
currentTemp = ActualTemp;
//conditionals to determine the players current risk (danger) level
if(findFood==true&&isDead==true){
isDead=false;
isDetect=false;
}
//IF CONSUMING FOOD WHILE BEING ATTACKED OVERRIDE DEATH
if(findFood==true&&isDetect==true||findFood==true&&isHidden==true){
isDead=false;
risk=random(eating);
}
if(findShelter==true&&isDead==true){
isDead=false;
isDetect=false;
}
//IF IN SHELTER WHILE BEING ATTACKED OVERRIDE DEATH AND GO INCOGNITO
if(findShelter==true&&isDetect==true||findShelter==true&&isHidden==true){
isDead=false;
risk=random(inshelter);
isDetect=false;
}
// hidden within shelter
if(isHidden==true&&findShelter==true){
risk=random(incognito);
isDetect=false;
}
if(findFood==true){
risk =random(eating);
}
if(findShelter==true){
risk =random(inshelter);
}
//console status
//return " Detection: "+risk+"<br> temprature: "+ActualTemp+"<br> Weather Condition: "+ condit+"<br> hours survived: "+n+"<br> Nighttime?: "+night+"<br> shelter x dist: "+shelterdiffX+"<br> shelter y dist: "+shelterdiffY+"<br> chaser x dist: "+chaserdiffX+"<br> chaser y dist: "+chaserdiffY+"<br><br> zombie x dist: "+zombiediffX+"<br> zombie y dist: "+zombiediffY+"<br> food x dist: "+fooddiffX+"<br> food y dist: "+fooddiffY+"<br> zombie attack: "+collision+"<br> shelter: "+findShelter+"<br> food pickup: "+findFood+"<br> storymode: "+storymode;
//if not dead print paragraph
if(isDead==false&&findShelter==false&&findFood==false){
//paragraph
return " "+risk+"<br> "+observe+" and "+weatherObserve+"<br> "+opener + "" +message+ "<br> " +body+ "<br> "+hope+".<br> "+conclusion;
}
//if not dead print paragraph
if(findShelter==true){
//paragraph
return random(inshelter);
}
//if not dead print paragraph
if(findFood==true){
//paragraph
return random(eating);
}
var deadhero = ["you get eaten alive","it wasn't meant to be","there was no time to react"];
if(isDead==true){
return random(attack)+" "+random(deadhero);
}
//returns statuses of all constraints
//return("death= "+isDead+"<br> hidden= "+isHidden+"<br> detect= "+isDetect+"<br> shelter= "+findShelter+"<br> food= "+findFood+"<br> warm= "+isWarm+"<br><br>"+risk+"");
}
}
function resetFocusedRandom() {
return Math.seedrandom(arguments);
}
function focusedRandom(min, max, focus, mean) {
// console.log("hello")
if(max === undefined) {
max = min;
min = 0;
}
if(focus === undefined) {
focus = 1.0;
}
if(mean === undefined) {
mean = (min + max) / 2.0;
}
if(focus == 0) {
return d3.randomUniform(min, max)();
}
else if(focus < 0) {
focus = -1 / focus;
}
sigma = (max - mean) / focus;
val = d3.randomNormal(mean, sigma)();
if (val > min && val < max) {
return val;
}
return d3.randomUniform(min, max)();
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/addons/p5.dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.0/seedrandom.min.js"></script>
<script src="tracery.js"></script>
<script src="https://d3js.org/d3-random.v1.min.js"></script>
<script language="javascript" type="text/javascript" src="focusedRandom.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="bot.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
body {padding: 0; margin: 0;}
ul li {
list-style:none;
overflow:hidden;
border:1px solid #dedede;
margin:5px;
padding:5px;
}
.media img {
max-width:440px;
max-height:220px;
}
</style>
</head>
<body style="background-color:white">
<div id="canvasContainer">
</div>
<pre>
<p style="font-size:18px"id="tweet_text">
</p>
</pre>
<hr>
<div id="tweetExamples"></div>
</body>
var rndSeed;
var bot;
var renderReady = false;
function preload() {
bot = new bot();
bot.preload();
}
function setup () {
var main_canvas = createCanvas(440, 220);
main_canvas.parent('canvasContainer');
rndSeed = random(1024);
bot.setup();
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
}
function reportRenderReady() {
finalDiv = createDiv('(render ready)');
finalDiv.id("render_ready")
}
function draw() {
background(204);
// randomSeed(0);
resetFocusedRandom(rndSeed);
message = bot.respond();
var text = select('#tweet_text');
text.html(message);
if(renderReady == false) {
if(bot.isDone()) {
reportRenderReady();
renderReady = true;
}
}
}
/**
* @author Kate Compton
*/
var tracery = {
utilities : {}
};
(function() {
function inQuotes(s) {
return '"' + s + '"';
};
function parseAction(action) {
return action;
};
// tag format
// a thing to expand, plus actions
function parseTag(tag) {
var errors = [];
var prefxns = [];
var postfxns = [];
var lvl = 0;
var start = 0;
var inPre = true;
var symbol,
mods;
function nonAction(end) {
if (start !== end) {
var section = tag.substring(start, end);
if (!inPre) {
errors.push("multiple possible expansion symbols in tag!" + tag);
} else {
inPre = false;
var split = section.split(".");
symbol = split[0];
mods = split.slice(1, split.length);
}
}
start = end;
};
for (var i = 0; i < tag.length; i++) {
var c = tag.charAt(i);
switch(c) {
case '[':
if (lvl === 0) {
nonAction(i);
}
lvl++;
break;
case ']':
lvl--;
if (lvl === 0) {
var section = tag.substring(start + 1, i);
if (inPre)
prefxns.push(parseAction(section));
else
postfxns.push(parseAction(section));
start = i + 1;
}
break;
default:
if (lvl === 0) {
}
break;
}
}
nonAction(i);
if (lvl > 0) {
var error = "Too many '[' in rule " + inQuotes(tag);
errors.push(error);
}
if (lvl < 0) {
var error = "Too many ']' in rule " + inQuotes(tag);
errors.push(error);
}
return {
preActions : prefxns,
postActions : postfxns,
symbol : symbol,
mods : mods,
raw : tag,
errors : errors,
};
};
// Split a rule into sections
function parseRule(rule) {
var sections = [];
var errors = [];
if (!( typeof rule == 'string' || rule instanceof String)) {
errors.push("Cannot parse non-string rule " + rule);
sections.errors = errors;
return sections;
}
if (rule.length === 0) {
return [];
}
var lvl = 0;
var start = 0;
var inTag = false;
function createSection(end) {
var section = rule.substring(start, end);
if (section.length > 0) {
if (inTag)
sections.push(parseTag(section));
else
sections.push(section);
}
inTag = !inTag;
start = end + 1;
}
for (var i = 0; i < rule.length; i++) {
var c = rule.charAt(i);
switch(c) {
case '[':
lvl++;
break;
case ']':
lvl--;
break;
case '#':
if (lvl === 0) {
createSection(i);
}
break;
default:
break;
}
}
if (lvl > 0) {
var error = "Too many '[' in rule " + inQuotes(rule);
errors.push(error);
}
if (lvl < 0) {
var error = "Too many ']' in rule " + inQuotes(rule);
errors.push(error);
}
if (inTag) {
var error = "Odd number of '#' in rule " + inQuotes(rule);
errors.push(error);
}
createSection(rule.length);
sections.errors = errors;
return sections;
};
function testParse(rule, shouldFail) {
console.log("-------");
console.log("Test parse rule: " + inQuotes(rule) + " " + shouldFail);
var parsed = parseRule(rule);
if (parsed.errors && parsed.errors.length > 0) {
for (var i = 0; i < parsed.errors.length; i++) {
console.log(parsed.errors[i]);
}
}
}
function testParseTag(tag, shouldFail) {
console.log("-------");
console.log("Test parse tag: " + inQuotes(tag) + " " + shouldFail);
var parsed = parseTag(tag);
if (parsed.errors && parsed.errors.length > 0) {
for (var i = 0; i < parsed.errors.length; i++) {
console.log(parsed.errors[i]);
}
}
}
tracery.testParse = testParse;
tracery.testParseTag = testParseTag;
tracery.parseRule = parseRule;
tracery.parseTag = parseTag;
function spacer(size) {
var s = "";
for (var i = 0; i < size * 3; i++) {
s += " ";
}
return s;
}
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
function extend(destination, source) {
for (var k in source) {
if (source.hasOwnProperty(k)) {
destination[k] = source[k];
}
}
return destination;
}
// Inspired by base2 and Prototype
(function() {
var initializing = false,
fnTest = /xyz/.test(function() { xyz;
}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function() {
};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) {
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) : prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
/**
* @author Kate
*/
var Rule = function(raw) {
this.raw = raw;
this.sections = parseRule(raw);
};
Rule.prototype.getParsed = function() {
if (!this.sections)
this.sections = parseRule(raw);
return this.sections;
};
Rule.prototype.toString = function() {
return this.raw;
};
Rule.prototype.toJSONString = function() {
return this.raw;
};
/**
* @author Kate
*/
var RuleWeighting = Object.freeze({
RED : 0,
GREEN : 1,
BLUE : 2
});
var RuleSet = function(rules) {
// is the rules obj an array? A RuleSet, or a string?
if (rules.constructor === Array) {
// make a copy
rules = rules.slice(0, rules.length);
} else if (rules.prototype === RuleSet) {
// clone
} else if ( typeof rules == 'string' || rules instanceof String) {
var args = Array.prototype.slice.call(arguments);
rules = args;
} else {
console.log(rules);
throw ("creating ruleset with unknown object type!");
}
// create rules and their use counts
this.rules = rules;
this.parseAll();
this.uses = [];
this.startUses = [];
this.totalUses = 0;
for (var i = 0; i < this.rules.length; i++) {
this.uses[i] = 0;
this.startUses[i] = this.uses[i];
this.totalUses += this.uses[i];
}
};
//========================================================
// Iterating over rules
RuleSet.prototype.parseAll = function(fxn) {
for (var i = 0; i < this.rules.length; i++) {
if (this.rules[i].prototype !== Rule)
this.rules[i] = new Rule(this.rules[i]);
}
};
//========================================================
// Iterating over rules
RuleSet.prototype.mapRules = function(fxn) {
return this.rules.map(function(rule, index) {
return fxn(rule, index);
});
};
RuleSet.prototype.applyToRules = function(fxn) {
for (var i = 0; i < this.rules.length; i++) {
fxn(this.rules[i], i);
}
};
//========================================================
RuleSet.prototype.get = function() {
var index = this.getIndex();
return this.rules[index];
};
RuleSet.prototype.getRandomIndex = function() {
return Math.floor(this.uses.length * Math.random());
};
RuleSet.prototype.getIndex = function() {
// Weighted distribution
// Imagine a bar of length 1, how to divide the length
// s.t. a random dist will result in the dist we want?
var index = this.getRandomIndex();
// What if the uses determine the chance of rerolling?
var median = this.totalUses / this.uses.length;
var count = 0;
while (this.uses[index] > median && count < 20) {
index = this.getRandomIndex();
count++;
}
// reroll more likely if index is too much higher
return index;
};
RuleSet.prototype.decayUses = function(pct) {
this.totalUses = 0;
for (var i = 0; i < this.uses; i++) {
this.uses[index] *= 1 - pct;
this.totalUses += this.uses[index];
}
};
RuleSet.prototype.testRandom = function() {
console.log("Test random");
var counts = [];
for (var i = 0; i < this.uses.length; i++) {
counts[i] = 0;
}
var testCount = 10 * this.uses.length;
for (var i = 0; i < testCount; i++) {
var index = this.getIndex();
this.uses[index] += 1;
counts[index]++;
this.decayUses(.1);
}
for (var i = 0; i < this.uses.length; i++) {
console.log(i + ":\t" + counts[i] + " \t" + this.uses[i]);
}
};
RuleSet.prototype.getSaveRules = function() {
var jsonRules = this.rules.map(function(rule) {
return rule.toJSONString();
});
return jsonRules;
};
/**
* @author Kate Compton
*/
var Action = function(node, raw) {
this.node = node;
this.grammar = node.grammar;
this.raw = raw;
};
Action.prototype.activate = function() {
var node = this.node;
node.actions.push(this);
// replace any hashtags
this.amended = this.grammar.flatten(this.raw);
var parsed = parseTag(this.amended);
var subActionRaw = parsed.preActions;
if (subActionRaw && subActionRaw.length > 0) {
this.subactions = subActionRaw.map(function(action) {
return new Action(node, action);
});
}
if (parsed.symbol) {
var split = parsed.symbol.split(":");
if (split.length === 2) {
this.push = {
symbol : split[0],
// split into multiple rules
rules : split[1].split(","),
};
// push
node.grammar.pushRules(this.push.symbol, this.push.rules);
} else
throw ("Unknown action: " + parsed.symbol);
}
if (this.subactions) {
for (var i = 0; i < this.subactions.length; i++) {
this.subactions[i].activate();
}
}
};
Action.prototype.deactivate = function() {
if (this.subactions) {
for (var i = 0; i < this.subactions.length; i++) {
this.subactions[i].deactivate();
}
}
if (this.push) {
this.node.grammar.popRules(this.push.symbol, this.push.rules);
}
};
/**
* @author Kate Compton
*/
var isConsonant = function(c) {
c = c.toLowerCase();
switch(c) {
case 'a':
return false;
case 'e':
return false;
case 'i':
return false;
case 'o':
return false;
case 'u':
return false;
}
return true;
};
function endsWithConY(s) {
if (s.charAt(s.length - 1) === 'y') {
return isConsonant(s.charAt(s.length - 2));
}
return false;
};
var universalModifiers = {
capitalizeAll : function(s) {
return s.replace(/(?:^|\s)\S/g, function(a) {
return a.toUpperCase();
});
},
capitalize : function(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
},
inQuotes : function(s) {
return '"' + s + '"';
},
comma : function(s) {
var last = s.charAt(s.length - 1);
if (last === ",")
return s;
if (last === ".")
return s;
if (last === "?")
return s;
if (last === "!")
return s;
return s + ",";
},
beeSpeak : function(s) {
// s = s.replace("s", "zzz");
s = s.replace(/s/, 'zzz');
return s;
},
a : function(s) {
if (!isConsonant(s.charAt()))
return "an " + s;
return "a " + s;
},
s : function(s) {
var last = s.charAt(s.length - 1);
switch(last) {
case 'y':
// rays, convoys
if (!isConsonant(s.charAt(s.length - 2))) {
return s + "s";
}
// harpies, cries
else {
return s.slice(0, s.length - 1) + "ies";
}
break;
// oxen, boxen, foxen
case 'x':
return s.slice(0, s.length - 1) + "xen";
case 'z':
return s.slice(0, s.length - 1) + "zes";
case 'h':
return s.slice(0, s.length - 1) + "hes";
default:
return s + "s";
};
},
ed : function(s) {
var index = s.indexOf(" ");
var s = s;
var rest = "";
if (index > 0) {
rest = s.substring(index, s.length);
s = s.substring(0, index);
}
var last = s.charAt(s.length - 1);
switch(last) {
case 'y':
// rays, convoys
if (isConsonant(s.charAt(s.length - 2))) {
return s.slice(0, s.length - 1) + "ied" + rest;
}
// harpies, cries
else {
return s + "ed" + rest;
}
break;
case 'e':
return s + "d" + rest;
break;
default:
return s + "ed" + rest;
};
}
};
/**
* @author Kate Compton
*/
// A tracery expansion node
var nodeCount = 0;
var ExpansionNode = Class.extend({
init : function() {
this.depth = 0;
this.id = nodeCount;
nodeCount++;
this.childText = "[[UNEXPANDED]]";
},
setParent : function(parent) {
if (parent) {
this.depth = parent.depth + 1;
this.parent = parent;
this.grammar = parent.grammar;
}
},
expand : function() {
// do nothing
return "???";
},
expandChildren : function() {
if (this.children) {
this.childText = "";
for (var i = 0; i < this.children.length; i++) {
this.children[i].expand();
this.childText += this.children[i].finalText;
}
this.finalText = this.childText;
}
},
createChildrenFromSections : function(sections) {
var root = this;
this.children = sections.map(function(section) {
if ( typeof section == 'string' || section instanceof String) {
// Plaintext
return new TextNode(root, section);
} else {
return new TagNode(root, section);
}
});
}
});
var RootNode = ExpansionNode.extend({
init : function(grammar, rawRule) {
this._super();
this.grammar = grammar;
this.parsedRule = parseRule(rawRule);
},
expand : function() {
var root = this;
this.createChildrenFromSections(this.parsedRule);
// expand the children
this.expandChildren();
},
});
function simpleExtend(a, b){
for(var key in b)
if(b.hasOwnProperty(key))
a[key] = b[key];
return a;
}
var TagNode = ExpansionNode.extend({
init : function(parent, parsedTag) {
this._super();
if (!(parsedTag !== null && typeof parsedTag === 'object')) {
if ( typeof parsedTag == 'string' || parsedTag instanceof String) {
console.warn("Can't make tagNode from unparsed string!");
parsedTag = parseTag(parsedTag);
} else {
console.log("Unknown tagNode input: ", parsedTag);
throw ("Can't make tagNode from strange tag!");
}
}
this.setParent(parent);
// NOTE: removed jquery dependency here
// $.extend(this, parsedTag);
simpleExtend(this, parsedTag);
},
expand : function() {
if (tracery.outputExpansionTrace)
console.log(r.sections);
this.rule = this.grammar.getRule(this.symbol);
this.actions = [];
// Parse the rule if it hasn't been already
this.createChildrenFromSections(this.rule.getParsed());
// Do any pre-expansion actions!
for (var i = 0; i < this.preActions.length; i++) {
var action = new Action(this, this.preActions[i]);
action.activate();
}
// Map each child section to a node
if (!this.rule.sections)
console.log(this.rule);
this.expandChildren();
for (var i = 0; i < this.actions.length; i++) {
this.actions[i].deactivate();
}
this.finalText = this.childText;
for (var i = 0; i < this.mods.length; i++) {
this.finalText = this.grammar.applyMod(this.mods[i], this.finalText);
}
},
toLabel : function() {
return this.symbol;
},
toString : function() {
return "TagNode '" + this.symbol + "' mods:" + this.mods + ", preactions:" + this.preActions + ", postactions" + this.postActions;
}
});
var TextNode = ExpansionNode.extend({
isLeaf : true,
init : function(parent, text) {
this._super();
this.setParent(parent);
this.text = text;
this.finalText = text;
},
expand : function() {
// do nothing
},
toLabel : function() {
return this.text;
}
});
/**
* @author Kate Compton
*/
function Symbol(grammar, key) {
this.grammar = grammar;
this.key = key;
this.currentRules = undefined;
this.ruleSets = [];
};
Symbol.prototype.loadFrom = function(rules) {
rules = this.wrapRules(rules);
this.baseRules = rules;
this.ruleSets.push(rules);
this.currentRules = this.ruleSets[this.ruleSets.length - 1];
};
//========================================================
// Iterating over rules
Symbol.prototype.mapRules = function(fxn) {
return this.currentRules.mapRules(fxn);
};
Symbol.prototype.applyToRules = function(fxn) {
this.currentRules.applyToRules(fxn);
};
//==================================================
// Rule pushpops
Symbol.prototype.wrapRules = function(rules) {
if (rules.prototype !== RuleSet) {
if (Array.isArray(rules)) {
return new RuleSet(rules);
} else if ( typeof rules == 'string' || rules instanceof String) {
return new RuleSet(rules);
} else {
throw ("Unknown rules type: " + rules);
}
}
// already a ruleset
return rules;
};
Symbol.prototype.pushRules = function(rules) {
rules = this.wrapRules(rules);
this.ruleSets.push(rules);
this.currentRules = this.ruleSets[this.ruleSets.length - 1];
};
Symbol.prototype.popRules = function() {
var exRules = this.ruleSets.pop();
if (this.ruleSets.length === 0) {
//console.warn("No more rules for " + this + "!");
}
this.currentRules = this.ruleSets[this.ruleSets.length - 1];
};
// Clear everything and set the rules
Symbol.prototype.setRules = function(rules) {
rules = this.wrapRules(rules);
this.ruleSets = [rules];
this.currentRules = rules;
};
Symbol.prototype.addRule = function(rule) {
this.currentRules.addRule(seed);
};
//========================================================
// selection
Symbol.prototype.select = function() {
this.isSelected = true;
};
Symbol.prototype.deselect = function() {
this.isSelected = false;
};
//==================================================
// Getters
Symbol.prototype.getRule = function(seed) {
return this.currentRules.get(seed);
};
//==================================================
Symbol.prototype.toString = function() {
return this.key + ": " + this.currentRules + "(overlaying " + (this.ruleSets.length - 1) + ")";
};
Symbol.prototype.toJSON = function() {
var rules = this.baseRules.rules.map(function(rule) {
return '"' + rule.raw + '"';
});
return '"' + this.key + '"' + ": [" + rules.join(", ") + "]";
};
Symbol.prototype.toHTML = function(useSpans) {
var keySpan = '"' + this.key + '"';
if (useSpans)
keySpan = "<span class='symbol symbol_" + this.key + "'>" + keySpan + "</span>";
var rules = this.baseRules.rules.map(function(rule) {
// replace any anglebrackets for html
var cleaned = rule.raw.replace(/&/g, "&amp;");
cleaned = cleaned.replace(/>/g, "&gt;");
cleaned = cleaned.replace(/</g, "&lt;");
var s = '"' + cleaned + '"';
if (useSpans)
s = "<span class='rule'>" + s + "</span>";
return s;
});
return keySpan + ": [" + rules.join(", ") + "]";
};
/**
* @author Kate Compton
*/
function Grammar() {
this.clear();
};
Grammar.prototype.clear = function() {
// Symbol library
this.symbols = {};
this.errors = [];
// Modifier library
this.modifiers = {};
// add the universal mods
for (var mod in universalModifiers) {
if (universalModifiers.hasOwnProperty(mod))
this.modifiers[mod] = universalModifiers[mod];
}
};
//========================================================
// Loading
Grammar.prototype.loadFrom = function(obj) {
var symbolSrc;
this.clear();
if (obj.symbols !== undefined) {
symbolSrc = obj.symbols;
} else {
symbolSrc = obj;
}
// get all json keys
var keys = Object.keys(symbolSrc);
this.symbolNames = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
this.symbolNames.push(key);
this.symbols[key] = new Symbol(this, key);
this.symbols[key].loadFrom(symbolSrc[key]);
}
};
Grammar.prototype.toHTML = function(useSpans) {
// get all json keys
var keys = Object.keys(this.symbols);
this.symbolNames = [];
var lines = [];
var count = 0;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var symbol = this.symbols[key];
if (symbol && symbol.baseRules) {
lines.push(" " + this.symbols[key].toHTML(useSpans));
}
};
var s;
s = lines.join(",</p><p>");
s = "{<p>" + s + "</p>}";
return s;
};
Grammar.prototype.toJSON = function() {
// get all json keys
var keys = Object.keys(this.symbols);
this.symbolNames = [];
var lines = [];
var count = 0;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var symbol = this.symbols[key];
if (symbol && symbol.baseRules) {
lines.push(" " + this.symbols[key].toJSON());
}
};
var s;
s = lines.join(",\n");
s = "{\n" + s + "\n}";
return s;
};
//========================================================
// selection
Grammar.prototype.select = function() {
this.isSelected = true;
};
Grammar.prototype.deselect = function() {
this.isSelected = false;
};
//========================================================
// Iterating over symbols
Grammar.prototype.mapSymbols = function(fxn) {
var symbols = this.symbols;
return this.symbolNames.map(function(name) {
return fxn(symbols[name], name);
});
};
Grammar.prototype.applyToSymbols = function(fxn) {
for (var i = 0; i < this.symbolNames.length; i++) {
var key = this.symbolNames[i];
fxn(this.symbols[key], key);
}
};
//========================================================
Grammar.prototype.addOrGetSymbol = function(key) {
if (this.symbols[key] === undefined)
this.symbols[key] = new Symbol(key);
return this.symbols[key];
};
Grammar.prototype.pushRules = function(key, rules) {
var symbol = this.addOrGetSymbol(key);
symbol.pushRules(rules);
};
Grammar.prototype.popRules = function(key, rules) {
var symbol = this.addOrGetSymbol(key);
var popped = symbol.popRules();
if (symbol.ruleSets.length === 0) {
// remove symbol
this.symbols[key] = undefined;
}
};
Grammar.prototype.applyMod = function(modName, text) {
if (!this.modifiers[modName]) {
console.log(this.modifiers);
throw ("Unknown mod: " + modName);
}
return this.modifiers[modName](text);
};
//============================================================
Grammar.prototype.getRule = function(key, seed) {
var symbol = this.symbols[key];
if (symbol === undefined) {
var r = new Rule("{{" + key + "}}");
r.error = "Missing symbol " + key;
return r;
}
var rule = symbol.getRule();
if (rule === undefined) {
var r = new Rule("[" + key + "]");
console.log(r.sections);
r.error = "Symbol " + key + " has no rule";
return r;
}
return rule;
};
//============================================================
// Expansions
Grammar.prototype.expand = function(raw) {
// Start a new tree
var root = new RootNode(this, raw);
root.expand();
return root;
};
Grammar.prototype.flatten = function(raw) {
// Start a new tree
var root = new RootNode(this, raw);
root.expand();
return root.childText;
};
//===============
Grammar.prototype.analyze = function() {
this.symbolNames = [];
for (var name in this.symbols) {
if (this.symbols.hasOwnProperty(name)) {
this.symbolNames.push(name);
}
}
// parse every rule
for (var i = 0; i < this.symbolNames.length; i++) {
var key = this.symbolNames[i];
var symbol = this.symbols[key];
// parse all
for (var j = 0; j < symbol.baseRules.length; j++) {
var rule = symbol.baseRules[j];
rule.parsed = tracery.parse(rule.raw);
// console.log(rule);
}
}
};
Grammar.prototype.selectSymbol = function(key) {
console.log(this);
var symbol = this.get(key);
};
/**
* @author Kate Compton
*/
tracery.createGrammar = function(obj) {
var grammar = new Grammar();
grammar.loadFrom(obj);
return grammar;
};
tracery.test = function() {
console.log("==========================================");
console.log("test tracery");
// good
tracery.testParse("", false);
tracery.testParse("fooo", false);
tracery.testParse("####", false);
tracery.testParse("#[]#[]##", false);
tracery.testParse("#someSymbol# and #someOtherSymbol#", false);
tracery.testParse("#someOtherSymbol.cap.pluralize#", false);
tracery.testParse("#[#do some things#]symbol.mod[someotherthings[and a function]]#", false);
tracery.testParse("#[fxn][fxn][fxn[subfxn]]symbol[[fxn]]#", false);
tracery.testParse("#[fxn][#fxn#][fxn[#subfxn#]]symbol[[fxn]]#", false);
tracery.testParse("#hero# ate some #color# #animal.s#", false);
tracery.testParseTag("[action]symbol.mod1.mod2[postAction]", false);
// bad
tracery.testParse("#someSymbol# and #someOtherSymbol", true);
tracery.testParse("#[fxn][fxn][fxn[subfxn]]symbol[fxn]]#", true);
// bad
tracery.testParseTag("stuff[action]symbol.mod1.mod2[postAction]", true);
tracery.testParseTag("[action]symbol.mod1.mod2[postAction]stuff", true);
tracery.testParse("#hero# ate some #color# #animal.s#", true);
tracery.testParse("#[#setPronouns#][#setOccupation#][hero:#name#]story#", true);
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment