click here for zip file of all 25 pdfs
"fortune cookies"
randomly generated advertisements for chinese restaurants with their own wacky fortune cookies
demonstrated through a p5js sketch:
Initially, I had no idea what I wanted to do for this project. I was really impressed by the examples we were shown in class and knew that I wanted to incorporate both generative text and generative imagery. In fact, I liked Lingdong's approach in his project "Fauna of Sloogia" where he focused more on generative imagery and the generative text aspect of his book was simply the names he gave to each generated creature.
With this in mind, I first thought of images I could generate. I needed objects that came in large batches/quantities but were not all exactly alike. Items that fit this category included snowflakes, fruits, etc. but these seemed unimaginative. Finally, I thought of fortune cookies and this idea immediately tied into what I wanted to create through generative text - strange fortunes and Chinese restaurant names - and from there, I developed a comprehensive plan for my generative chapter.
Process
This project was split into four parts: the fortune cookie, the takeout box, the restaurant name, and the fortune.
1. The fortune cookie:
For the fortune cookie, I first sketched a few cookies and determined the vertices they all had in common. I gave each cookie 9 vertices and graphed them on a 500x500 p5js canvas.
From there, I played around with bezier curves and shading to create each fortune cookie. Every cookie's vertices and bezier curves are randomized and thus generated by the computer every time.
2. The takeout box:
For the takeout box, I had a very similar approach as I did with the cookie; I sketched takeout boxes, determined the common vertices, and randomized the vertices within p5 so that no two takeout boxes would look alike. In addition, I added text onto the box. Two phrases - comprised of "Thank You" or "Enjoy" - appeared at random points on the box.
3. The restaurant name:
For the generated Chinese restaurant names, I drew inspiration from a discussion I had a few weeks ago about Chinese restaurants commonly being composed of similar words and language.
I put more thought and research into this idea and came up with five categories of words commonly found in Chinese restaurant names: places, adjective, nouns, food, and location. And depending on the length of the name, I would randomly choose one word from each of these categories in a predetermined order and generate names.
places: "Beijing", "Peking", "Szechuan", "Shanghai", "Hunan", "Canton", "Hong Kong", "Taipei", "China", "Taiwan", "Formosa"
adjectives: "Lucky", "Golden", "Gourmet", "Imperial", "Oriental", "Grand", "Mandarin", "Supreme", "Royal", "East", "Old", "Happy", "Hot", "Chinese"
nouns: "Cat", "Moon", "Sun", "Dragon", "Star", "Roll", "Panda", "Bamboo", "Chef", "King", "Empire", "Empress", "Emperor", "Phoenix", "Lion", "Tiger", "Jade", "Pearl"
foods: "Seafood", "Noodle", "Dim Sum", "Hot Pot", "Rice", "Ramen", "Hibachi"
locations: "Palace", "Garden", "Cafe", "Bistro", "Kitchen", "Restaurant", "Buffet", "House", "Wok", "Bowl", "Grill", "Cuisine", "Express"
For example, if I wanted to generate a Chinese restaurant name that was four words long and had a word order of adjective-food-place-location one example would be "Golden Noodle Szechuan Kitchen".
To finalize this, I gave each word length (from two words long to five words long) a chance of 20% (i.e. the chance of the generator returning a three word long name and a five word long name were both 20%). And within each word length, I thought of word orderings and manipulated the chances of each ordering.
To demonstrate the Chinese Restaurant Name Generator in action, click on the following sketch to generate names:
4. The fortune:
To generate the fortune, I first wrote down each fortune with blanks and filled in the blanks with random nouns, adverbs, adjectives, verbs, etc. using RiTa.
code
// COOKIE // points for the cookie var x1, x2, x3, x4, x5, x6, x7, x8, x9; // TAKEOUT BOX //variables for box points var tx1,ty1,tx2,ty1,tx3,ty3,tx4,ty4,tx5,ty5,tx6,ty6,tx7,ty7; //visible flap vertex points var fx, fy; //variablesfor handle points var hx1, hy1, hx2, hy2, hx3, hy3, hx4, hy4; //RiTA stuff var rg; var name, lengthChance, typeChance; // variables for generated restaurant name var myFont; // custom font var luckyNums = []; // array of lucky numbers var prediction = ''; // fortune cookie fortune/prediction var phoneNumber = ''; // phone number function preload() { myFont = loadFont('andale-mono.otf'); chineseFont = loadFont('chinese.ttf') } function setup() { createCanvas(500, 680); background(239, 50, 40); // red color background(240); noLoop(); // assign values to lengthChance and typeChance lengthChance = random(0,100); typeChance = random(0,100); // generate restaurant name name = generateRestaurantName(); // display restaurant name text displayRestaurantName(); // generate phone number generatePhoneNumber(); drawPhoneNumber(); // draw slip of paper drawPaper(); // generate lucky numbers generateLuckyNumbers(); drawLuckyNumbers(); // display the fortune drawFortune(); // generate and draw box generateBox(); drawBox(); // generate cookie generateCookie(); // draw the cookie drawCookie(); prediction = generateFortune(); // button to download json file createJSONFile(); } function mousePressed() { // generate new cookie, restaurant name, and fortune on mouse press setup(); } function generateRestaurantName() { // returns string of generated Restaurant name name = ""; // Places 11 var places = ["Beijing", "Peking", "Szechuan", "Shanghai", "Hunan", "Canton", "Hong Kong", "Taipei", "China", "Taiwan", "Formosa"] // Adjectives 14 var adj = ["Lucky", "Golden", "Gourmet", "Imperial", "Oriental", "Grand", "Mandarin", "Supreme", "Royal", "East", "Old", "Happy", "Hot", "Chinese"] // Nouns 18 var noun = ["Cat", "Moon", "Sun", "Dragon", "Star", "Roll", "Panda", "Bamboo", "Chef", "King", "Empire", "Empress", "Emperor", "Phoenix", "Lion", "Tiger", "Jade", "Pearl"] // Food 7 var food = ["Seafood", "Noodle", "Dim Sum", "Hot Pot", "Rice", "Ramen", "Hibachi"] // Last words 13 var last = ["Palace", "Garden", "Cafe", "Bistro", "Kitchen", "Restaurant", "Buffet", "House", "Wok", "Bowl", "Grill", "Cuisine", "Express"]; // Generate some random names if (lengthChance >= 0 && lengthChance <= 25) { // two word length if (typeChance >= 0 && typeChance <= 17) { name += places [floor(random(11))] + " "; name += noun [floor(random(18))]; } else if (typeChance > 17 && typeChance <= 34) { name += adj [floor(random(14))] + " "; name += noun [floor(random(18))]; } else if (typeChance > 34 && typeChance <= 51) { name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 51 && typeChance <= 68) { name += adj [floor(random(14))] + " "; name += last [floor(random(13))]; } else if (typeChance > 68 && typeChance <= 85) { name += adj [floor(random(14))] + " "; name += food [floor(random(7))]; } else if (typeChance > 85) { name += places [floor(random(11))] + " "; name += last [floor(random(13))]; } } else if (lengthChance > 25 && lengthChance <= 50) { // three word length if (typeChance >= 0) { name += places [floor(random(11))] + " "; name += noun [floor(random(18))] + " "; name += last [floor(random(13))]; } else if (typeChance > 17 && typeChance <= 34) { name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += last [floor(random(13))]; } else if (typeChance > 34 && typeChance <= 51) { name += adj [floor(random(14))] + " "; name += places [floor(random(11))] + " "; name += noun [floor(random(18))]; } else if (typeChance > 51 && typeChance <= 68) { name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += food [floor(random(7))]; } else if (typeChance > 68 && typeChance <= 85) { name += places [floor(random(11))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 85 ) { name += adj [floor(random(11))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } } else if (lengthChance > 50 && lengthChance <= 75 ) { // four word length if (typeChance >= 0 && typeChance <= 20) { name += places [floor(random(11))] + " "; name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += last [floor(random(13))]; } else if (typeChance > 20 && typeChance <= 40) { name += places [floor(random(11))] + " "; name += adj [floor(random(14))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 40 && typeChance <= 60) { name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 60 && typeChance <= 80) { name += places [floor(random(11))] + " "; name += noun [floor(random(18))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 80) { name += adj [floor(random(14))] + " "; name += food [floor(random(7))] + " "; name += places [floor(random(11))] + " "; name += last [floor(random(13))]; } } else if (lengthChance > 75) { // five word length if (typeChance >= 0 && typeChance <= 40) { name += places [floor(random(11))] + " "; name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 40 && typeChance <= 60) { name += adj [floor(random(14))] + " "; name += food [floor(random(7))] + " "; name += noun [floor(random(18))] + " "; name += places [floor(random(7))] + " "; name += last [floor(random(13))]; } else if (typeChance > 60) { name += adj [floor(random(14))] + " "; name += noun [floor(random(18))] + " "; name += places [floor(random(11))] + " "; name += food [floor(random(7))] + " "; name += last [floor(random(13))]; } } return name; } function displayRestaurantName() { textAlign(LEFT); textFont(myFont); fill(0); textSize(12); noStroke(); text(name, 40, 50); } function generateCookie() { // generate points for the cookie // generate random points for fortune cookie x1 = width/2 - random(15,25); y1 = random(50,80); x2 = random(60, 78); y2 = random(225, 245); x3 = x2 - random(10,15); y3 = random(360, 380); x4 = 260; y4 = random(420,440); x5 = 255; y5 = random(300,350); x6 = 252; y6 = y5 - 65; x7 = 250; y7 = random(140,160); x8 = random(380, 390); y8 = random(390, 420); x9 = x8 + random(20,35); y9 = y2 - 20; // bezier vertices b1x = x1 - random(90,130); b1y = y1 + random(8,13); b2x = x2 + random(40,50); b2y = y2 - random(40,60); b3x = x5 + random(5, 8); b3y = (y5 - y6) * 0.9 + y6 b4x = x6 - random(25,35); b4y = random(155,170); b5x = x7 + random(15,20); b5y = y7 + random(20,30); b6x = x6 + random(5,15); b6y = y6 - random(25,40); } function drawCookie() { push(); translate(80,280); scale(0.35); stroke(0); // fill(247, 237, 185); // beige color fill(255); strokeWeight(4); // left half of cookie beginShape(); vertex(x1, y1); bezierVertex(b1x, b1y, b2x, b2y, x2, y2); vertex(x2, y2); bezierVertex(x2,y2,x3,y3,x4,y4); vertex(x4, y4); vertex(x5, y5); bezierVertex(x5, y5, b3x, b3y, x6,y6); endShape(); // right half of cookie beginShape(); vertex(x5,y5); bezierVertex(x5,y5,(x5+x8)/2 - 10,(y5+y8)/2 + 10,x8,y8); vertex(x8, y8); bezierVertex(x8,y8, (x9-x8)*1.4+x8, (y8 - y9) * 0.9 + y9 ,x9,y9); vertex(x9, y9); bezierVertex(x9-80, y9 -50, x1 + 90, y1 + 20, x1, y1); vertex(x1, y1); endShape(); // inner crease beginShape(); fill(0); vertex(x6,y6); bezierVertex(x6,x6,b4x,b4y,x7,y7); vertex(x7,y7); bezierVertex(b5x,b5y,b6x,b6y,x6,y6); vertex(x6,y6); endShape(); // left fold of cookie fill(0); beginShape(); vertex(x2, y2); bezierVertex(x2,y2,x3,y3,x4,y4); vertex(x4, y4); bezierVertex(x4, y4, x4-20, y4-35, (x2+x4)/2 - 15, (y2+y4)/2 + 15); bezierVertex((x2+x4)/2 - 15, (y2+y4)/2 + 15, x2 +10, y2 +80, x2, y2); vertex(x2,y2); endShape(); // line connecting inner black ellipse and left vertex strokeWeight(3); line(x6,y6,x5,y5); pop(); } function generatePrediction() { } function generateLuckyNumbers() { for (var i = 0 ; i < 6; i++) { luckyNums[i] = String(floor(random(0,100))); } return luckyNums; } function drawLuckyNumbers() { luckynum1 = luckyNums[0]; luckynum2 = luckyNums[1]; luckynum3 = luckyNums[2]; luckynum4 = luckyNums[3]; luckynum5 = luckyNums[4]; luckynum6 = luckyNums[5]; fill(0); textSize(12); textFont(myFont); noStroke(); textAlign(CENTER); text("Lucky Numbers: " + luckynum1 + " " + luckynum2 + " " + luckynum3 + " " + luckynum4 + " " + luckynum5 + " " + luckynum6, width/2, 545); } function generatePhoneNumber() { phoneNumber = "(" + String(floor(random(1,10))) + String(floor(random(0,10))) + String(floor(random(0,10))) + ")-" + String(floor(random(0,10))) + String(floor(random(0,10))) + String(floor(random(0,10))) + "-" + String(floor(random(0,10))) + String(floor(random(0,10))) + String(floor(random(0,10))) + String(floor(random(0,10))) } function drawPhoneNumber() { textAlign(LEFT); textFont(myFont); fill(0); textSize(12); noStroke(); text("Call " + phoneNumber + " to order!", 40, 80); } function generateBox() { // box points tx1 = random(100,140); ty1 = random(150,190); tx2 = random(140,180); ty2 = random(430,500); tx3 = random(250,300); ty3 = ty2 + random(80,100); tx4 = random(480,510); ty4 = random(470,500); tx5 = random(500,530); ty5 = random(140,180); tx6 = random(320,360); ty6 = random(90,120); tx7 = tx3; ty7 = ty1 + random(40,60); //flap points fx = random((tx1 + 45)-15, (tx1 + 45) + 15); fy = random((ty1 + 120) - 10, (ty1 + 120) + 10); //handle points hx1 = floor((tx1 + tx7) / 2) hy1 = floor((ty1 + ty7) / 2) + 40; hx2 = hx1 - random(3,7); hy2 = hy1 - random(120,160); hx4 = floor((tx6 + tx5)/2) hy4 = floor((ty6 + ty5)/2) hx3 = floor((tx6 + tx5)/2) hy3 = hy4 - random(70,100); } function drawBox() { push(); scale(0.5); translate(260,300); fill(255); strokeWeight(2.6); stroke(0); //left face beginShape(); vertex(tx1, ty1); vertex(tx2, ty2); vertex(tx3, ty3); vertex(tx7, ty7); vertex(tx1, ty1); endShape(); //right face beginShape(); vertex(tx3,ty3); vertex(tx4,ty4); vertex(tx5, ty5); vertex(tx7, ty7); vertex(tx3,ty3); endShape(); //left folds //back flap beginShape(); vertex(tx1,ty1); vertex(235,310); vertex(tx2, ty2); vertex(tx1, ty1); endShape(); //front flap beginShape(); vertex(tx7,ty7); vertex(fx,fy); vertex(tx3, ty3); vertex(tx3, ty3); vertex(tx7, ty7); endShape(); //top face beginShape(); vertex(tx5,ty5); vertex(tx6,ty6); vertex(tx1,ty1); vertex(tx7,ty7); vertex(tx5,ty5); endShape(); //handle //left vertical strokeWeight(3); // line(hx1,hy1,hx2,hy2); beginShape(); noFill(); vertex(hx1, hy1); vertex(hx2,hy2+20); bezierVertex(hx2, hy2+20, hx2, hy2, hx2+20, hy2) vertex(hx2+20, hy2) vertex(hx3 - 20,hy3) bezierVertex(hx3-20, hy3, hx3, hy3, hx3, hy3+20) vertex(hx3, hy3+20) vertex(hx4, hy4) endShape(); //top horizontal // line(hx2,hy2,hx3,hy3); drawMessages(); pop(); } function drawMessages() { var messages = ["ENJOY", "THANK YOU"]; var i1 = floor(random(2)); var i2 = floor(random(2)); var m1 = messages[i1]; var m2 = messages[i2]; textFont(chineseFont); noStroke(); fill(0); textAlign(CENTER); textSize(25); x1 = floor((tx5-tx7)/2 + random(200,270)); y1 = floor((ty4-ty3)/2) + random(250,300); x2 = x1 + random(60,90); x2 = constrain(x2, tx1, tx4); y2 = y1 + random(90,140); y2 = constrain(y2, ty7, ty4); r1 = random(HALF_PI/10,HALF_PI/6) r2 = random(-HALF_PI/10, HALF_PI/10) push(); rotate(r1); text(m1, x1, y1); pop(); push(); rotate(r2); text(m2, x2, y2); pop(); } function drawPaper() { rectMode(CENTER) stroke(0); fill(210); rect(width/2, 525, 480, 90); } function generateFortune() { rg = new RiGrammar(); //baseline for fortune cookie fortunes rg.addRule('<start>', 'Whoever <V-Singular-Present> a <N-Singular> will never be <V-Past> \nby a <N-Singular>.', 1); rg.addRule('<start>', 'Life is too short to <V-Plural-Present> <N-Plural>.', 1); rg.addRule('<start>', 'Your greatest strength is that you are <Adjective>.', 1); rg.addRule('<start>', 'Your future seems <Adverb> <Adjective>.', 1); rg.addRule('<start>', 'Alas, life is but a <Adjective> <N-Singular>.', 1); rg.addRule('<start>', 'Your <N-Singular> shines on another.', 1); rg.addRule('<start>', 'You will overcome <Adjective> <N-Plural>.', 1); rg.addRule('<start>', 'It is not necessary to <V-Plural-Present> others your <N-Singular>; \nit will be obvious.', 1); rg.addRule('<start>', 'Sometimes you just need to <V-Plural-Present> the <N-Singular>.', 1); rg.addRule('<start>', 'See if you can <V-Plural-Present> anything from the <N-Plural>.', 1); rg.addRule('<start>', 'Make the <N-Singular> <V-Plural-Present> for you, not the other way around.', 1); rg.addRule('<start>', 'In the eyes of <N-Plural>, everything is <Adjective>.', 1); rg.addRule('<start>', 'People in your surroundings will be more <Adjective> than usual.', 1); rg.addRule('<start>', 'You will be successful at <V-ing> <N-Plural>.', 1); rg.addRule('<start>', 'Whenever possible, keep it <Adjective>.', 1); // rg.addRule('<start>', '', 1); var args1 = { tense: RiTa.PRESENT_TENSE, number: RiTa.SINGULAR, person: RiTa.THIRD_PERSON }; var args2 = { tense: RiTa.PRESENT_TENSE, number: RiTa.PLURAL, person: RiTa.THIRD_PERSON }; var args3 = { tense: RiTa.PAST_TENSE, number: RiTa.SINGULAR, person: RiTa.THIRD_PERSON }; //nouns rg.addRule('<N-Singular>', RiTa.randomWord("nn")); rg.addRule('<N-Plural>', RiTa.randomWord('nns')) //verbs var v = RiTa.randomWord('vb'); rg.addRule('<V-Singular-Present>', RiTa.conjugate(v, args1)); rg.addRule('<V-Plural-Present>', RiTa.conjugate(v, args2)); rg.addRule('<V-Past>', RiTa.conjugate(v, args3)); rg.addRule('<V-ing>', RiTa.randomWord('vbg')); //adjective rg.addRule('<Adjective>', RiTa.randomWord('jj')); //adverb rg.addRule('<Adverb>', RiTa.randomWord('rb')); //preposition // rg.addRule('<Preposition>', RiTa.randomWord('in')); result = rg.expand(); return result; } function drawFortune() { fill(0); textSize(12); textFont(myFont); noStroke(); textAlign(CENTER); text(prediction, width/2, 515); } function createJSONFile() { // Create a JSON Object, fill it with the restaurants. var myJsonObject = {}; myJsonObject.restaurantName = name; myJsonObject.phoneNumber = phoneNumber; myJsonObject.prediction = prediction; myJsonObject.luckyNumbers = luckyNums; // Make a button. When you press it, it will save the JSON file createButton('save') .position(width/2-20, height-50) .mousePressed(function() { saveJSON(myJsonObject, 'data.json'); }); } |