// Ben Turner // NYU-ITP, Intro to Computational Media // // documentation: // // http://blog.benturner.com/2011/12/08/genetic-crossings-icm-final-project-presentation/ // http://blog.benturner.com/2011/11/10/icm-final-project-genetic-crossing/ // http://blog.benturner.com/2011/10/16/icm-genetic-crossing-part-2/ // http://blog.benturner.com/2011/10/13/icm-genetic-crossings/ // If you add traits or variables to Person.person, you must add variables to 4 places, found by searching // #PeopleChange (3 in main, 1 in MatingDance). // need these functions for all the vars and walking thru them // (used these to play with, ended up wishing I just used integer variables & a switch{} function to define them) import java.util.Enumeration; import java.util.Hashtable; long iterationCount = 0; // # of draw()s int currentYear = 0; // keeps track of years since sketch start Person person[]; // init Person object array Person god; // init God Nation nation[]; Religion religion[]; DrawFuncs drawFuncs = new DrawFuncs(); GetFuncs getFuncs = new GetFuncs(); MatingDance matingDance = new MatingDance(); Evolutions evolutions = new Evolutions(); Death death = new Death(); boolean toggleNoLoop = false; // toggles space bar for stopping/starting loop int numCharacteristics = 31; // total characteristics per person (see Person class) int numPeople = 5; // initialize starting # of ppl & counter for names of new people int populationSize = 5; // size of current population int equilibriumPopulation = 40; // so babies will be born after people die, keeps population fresh up to maxPeople int maxPeople = 90; // so it won't go nuts; don't forget to limit and/or raise this when needed int maxReproductiveAge = 50; // how old a woman can be and still have children int deathAgeBegin = 60; // when death functions kick in to see if people will die int flirter1, flirter2; // picks random flirters int globalLabelS = 9; // text size of labels int chemistryTolerance = 4; // max limit of attraction during flirting/chemistry int chemistryAppearanceTolerance = 1; // max difference in peoples' appearance int chemistryMoneyTolerance = 2; // max diff in peoples' money int chemistryReligiosityTolerance = 1; // max diff in peoples' religiosity int gestationRate = 5; // minimum "years" between babies int yearLength = 20; // length of "years" int personNodeSize = 10; // size of black circle representing each person int numNationCharacteristics = 13; int numNations = 5; // starting # of nations int maxNations = 10; // so won't go out of bounds int nationNodeSize=200; // size of nation blocs int nationBoxSize = 10; int nationSpacing = 200; // max distance traits can be from nation int numReligionCharacteristics = 4; int numReligions = 7; // starting # of nations int maxReligions = 10; // so won't go out of bounds int religionNodeSize=200; // size of nation blocs int religionBoxSize = 10; int religionSpacing = 200; // max distance traits can be from religion int[][] colorArray = new int[numCharacteristics][3]; // need colors for all characteristics int[] characteristicsArray = new int[numCharacteristics]; // button layouts int buttonX = 15; int buttonY = 30; int buttonSizeX = 153; int buttonSizeY = 25; int karyogramPush = 0; int karyogramButtonUpX = 520; int karyogramButtonUpY = 600; int karyogramButtonDownX = 520; int karyogramButtonDownY = 650; int karyogramButtonSize = 30; int scrollingAmount = 15; // controls whether on the genetic map screen or the stats screen boolean geneticMap = true; void setup() { size(1200, 700); smooth(); person = new Person[maxPeople]; nation = new Nation[maxNations]; religion = new Religion[maxReligions]; // #PeopleChange init all person objects & nations for (int i=0;i width) { randomX = width + (width + randomX - 30); } return randomX; } // calc random y position relative to person's nationality int randomY(int _nation) { int randomY = nation[_nation].getYPos() + int(random(-nationSpacing, nationSpacing)); if (randomY > height) { randomY = height + (height + randomY - 30); } return randomY; } public void draw() { // determines speed of time, and ages people each "year" if they're alive if (iterationCount % yearLength == 0) { currentYear++; for (int i=0;i= buttonX) && (mouseX <= buttonX+buttonSizeX) && (mouseY >= buttonY) && (mouseY <= buttonY+buttonSizeY)) { if (geneticMap == true) { geneticMap = false; redraw(); } else { geneticMap = true; redraw(); } } // make font larger if ((mouseX >= buttonX + 155) && (mouseX <= buttonX+175) && (mouseY >= buttonY) && (mouseY <= buttonY + 25)) { globalLabelS -= 1; } // make font smaller if ((mouseX >= buttonX + 180) && (mouseX <= buttonX+200) && (mouseY >= buttonY) && (mouseY <= buttonY + 25)) { globalLabelS += 1; } // move karyograms down if (geneticMap == false && (mouseX >= karyogramButtonDownX) && (mouseX <= karyogramButtonDownX + karyogramButtonSize) && (mouseY >= karyogramButtonDownY) && (mouseY <= karyogramButtonDownY + karyogramButtonSize)) { karyogramPush += scrollingAmount; } // move karyograms up if (geneticMap == false && (mouseX >= karyogramButtonUpX) && (mouseX <= karyogramButtonUpX + karyogramButtonSize) && (mouseY >= karyogramButtonUpY) && (mouseY <= karyogramButtonUpY + karyogramButtonSize)) { karyogramPush -= scrollingAmount; } } public class Death { Death() { } // checks if it's time to die if someone's alive (important so you don't also do already dead people) void deathVisit() { for (int i=0;i 115 && person[i].alive == true) { killPerson(i); } else { if (person[i].age > deathAgeBegin && person[i].alive == true) { int deathCalling = person[i].age + (int)(Float.parseFloat(person[i].trait.get("stress").toString())); int deathAversion = (int)(Float.parseFloat(person[i].trait.get("health").toString())) + (int)(Float.parseFloat(person[i].trait.get("luck").toString())) - (int)((person[i].age-77) / 2); int randomDeathRoll = (int)random(0, 14.99); if (deathAversion < randomDeathRoll) { killPerson(i); } } } } } void killPerson(int _personID) { person[_personID].alive = false; person[_personID].display(1); populationSize--; } } public class DrawFuncs { DrawFuncs() { } void drawPeople() { // only draw actual people, not empty objects for (int i=0;i= person[i].xPos-(int(personNodeSize/2)) && mouseX <= person[i].xPos+(int(personNodeSize/2)) && mouseY >= person[i].yPos-(int(personNodeSize/2)) && mouseY <= person[i].yPos+(int(personNodeSize/2))) { drawFamilyLines(i, 255); person[i].display(255); if (mousePressed) { textSize(10); int drawBoxX = mouseX; int drawBoxY = mouseY; int drawBoxWidth = 180; int drawBoxHeight = 400; if ((drawBoxY + drawBoxHeight) > height) { drawBoxY = drawBoxY - 15 - abs(height-(drawBoxY + drawBoxHeight)); } fill(255); stroke(0); rect(drawBoxX+35, drawBoxY+15, drawBoxWidth, drawBoxHeight); fill(0); int pHeight = round(person[i].pHeight * 5 * person[i].age / 100); int pWeight = round(person[i].pWeight * 2 * person[i].age / 100); if (pHeight > person[i].pHeight) { pHeight = person[i].pHeight; } if (pWeight > person[i].pWeight) { pWeight = person[i].pWeight; } int pFeet = round(pHeight / 12); int pInches = pHeight % 12; mbti = getFuncs.getMBTI(person[i].mbti); text(person[i].namePerson + " (" + person[i].gender + ", " + person[i].age + "yo)\n" + getFuncs.getNationality(person[i].nationality) + ", " + getFuncs.getReligion(person[i].religion) + "\n" + mbti[0] + ", " + mbti[1] + "\n" + pWeight + "lbs, " + pFeet + "'" + pInches + "\"", drawBoxX+45, drawBoxY+30); int j = 0; int k = 0; // distance between each item in the legend // draws popup window for values from each person node Object characteristic; for (Enumeration e = person[1].trait.keys() ; e.hasMoreElements() ;) { characteristic = e.nextElement(); fill(colorArray[j][0], colorArray[j][1], colorArray[j][2]); text(characteristic.toString(), drawBoxX+75, drawBoxY+95+k); String _characteristic = person[i].trait.get(characteristic).toString(); int potentialTrait = int(_characteristic); if ((characteristic.toString() == "strength") && (characteristic.toString() == "wisdom") && (characteristic.toString() == "education")) { int _actualTrait = ceil(potentialTrait * person[i].age * 2 / 100); if (potentialTrait < _actualTrait) { actualTrait = Integer.toString(potentialTrait); } } else { actualTrait = Integer.toString(potentialTrait); } text(actualTrait, drawBoxX+45, drawBoxY+95+k); j++; k += 15; } } } } } } // when you mouseover a node, some basic data is displayed void drawPopUpBoxNations() { for (int i=0;i= nation[i].xPos-int(nationBoxSize/2)) && (mouseX <= nation[i].xPos+int(nationBoxSize/2)) && (mouseY >= nation[i].yPos-int(nationBoxSize/2)) && (mouseY <= nation[i].yPos+int(nationBoxSize/2))) { nation[i].display(150); textSize(14); int drawBoxX = mouseX; int drawBoxY = mouseY; int drawBoxWidth = 180; int drawBoxHeight = 250; if ((drawBoxY + drawBoxHeight) > height) { drawBoxY = drawBoxY - 15 - abs(height-(drawBoxY + drawBoxHeight)); } fill(255); stroke(0); rect(drawBoxX+15, drawBoxY+15, drawBoxWidth, drawBoxHeight); fill(0); text(nation[i].nameNation, drawBoxX+30, drawBoxY+40); int j = 0; int k = 0; // distance between each item in the legend // draws popup window for values from each person node Object characteristic; int z = 0; for (Enumeration e = nation[1].trait.keys() ; e.hasMoreElements() ;) { characteristic = e.nextElement(); fill(0); text(characteristic.toString(), drawBoxX+45, drawBoxY+75+k); fill(nation[i].colorBaseArraySquares[z][0], nation[i].colorBaseArraySquares[z][1], nation[i].colorBaseArraySquares[z][2]); text(nation[i].trait.get(characteristic).toString(), drawBoxX+20, drawBoxY+75+k); j++; z++; k += 15; } } } } } // when you mouseover a node, some basic data is displayed void drawPopUpBoxReligions() { for (int i=0;i= religion[i].xPos) && (mouseX <= religion[i].xPos+religionBoxSize) && (mouseY >= religion[i].yPos) && (mouseY <= religion[i].yPos+religionBoxSize)) { religion[i].display(150); textSize(14); int drawBoxX = mouseX; int drawBoxY = mouseY; int drawBoxWidth = 150; int drawBoxHeight = 150; if ((drawBoxY + drawBoxHeight) > height) { drawBoxY = drawBoxY + 15 - abs(height-(drawBoxY + drawBoxHeight)); } fill(255); stroke(0); rect(drawBoxX+15, drawBoxY+15, drawBoxWidth, drawBoxHeight); fill(0); text(religion[i].nameReligion, drawBoxX+30, drawBoxY+40); int j = 0; int k = 0; // distance between each item in the legend // draws popup window for values from each person node Object characteristic; int z = 0; for (Enumeration e = religion[1].trait.keys() ; e.hasMoreElements() ;) { characteristic = e.nextElement(); fill(0); text(characteristic.toString(), drawBoxX+45, drawBoxY+75+k); fill(religion[i].colorBaseArraySquares[z][0], religion[i].colorBaseArraySquares[z][1], religion[i].colorBaseArraySquares[z][2]); text(religion[i].trait.get(characteristic).toString(), drawBoxX+20, drawBoxY+75+k); j++; z++; k += 15; } } } } } void drawInterface() { fill(255); textSize(globalLabelS); text("blue = parent -> child, green = 2 parents, yellow = nationality, turquoise = religion", 15, 15); // buttons noStroke(); // chromosomal stainings/time universe if ((mouseX >= buttonX) && (mouseX <= buttonX+buttonSizeX) && (mouseY >= buttonY) && (mouseY <= buttonY+buttonSizeY)) { fill(#FFD95D); } else { fill(#FFC400); } rect(buttonX, buttonY, buttonSizeX, buttonSizeY); textSize(10); fill(0); text("stats & chromosome stainings", buttonX+4, buttonY+15); // make font bigger if ((mouseX >= buttonX + 155) && (mouseX <= buttonX+175) && (mouseY >= buttonY) && (mouseY <= buttonY + 25)) { fill(#FFD95D); } else { fill(#FFC400); } rect(buttonX + 155, buttonY, 20, 25); textSize(10); fill(0); text("f", buttonX+163, buttonY+15); // make font smaller if ((mouseX >= buttonX + 180) && (mouseX <= buttonX+200) && (mouseY >= buttonY) && (mouseY <= buttonY + 25)) { fill(#FFD95D); } else { fill(#FFC400); } rect(buttonX + 180, buttonY, 20, 25); textSize(10); fill(0); text("F", buttonX+188, buttonY+15); } // loads chromosomal stainings view void drawChromosomalStainings() { noStroke(); if ((mouseX >= buttonX) && (mouseX <= buttonX+buttonSizeX) && (mouseY >= buttonY) && (mouseY <= buttonY+buttonSizeY)) { fill(#FFD95D); } else { fill(#FFC400); } rect(buttonX, buttonY, buttonSizeX, buttonSizeY); textSize(10); fill(0); text("view genetic/time map", buttonX+8, buttonY+15); int i = 0; // iterator for which characteristic to print for the legend int j = 20; // distance between each item in the legend for (int h=0;h= karyogramButtonDownX) && (mouseX <= karyogramButtonDownX + karyogramButtonSize) && (mouseY >= karyogramButtonDownY) && (mouseY <= karyogramButtonDownY + karyogramButtonSize)) { fill(#FFD95D); } else { fill(#FFC400); } rect(karyogramButtonUpX, karyogramButtonUpY, karyogramButtonSize, karyogramButtonSize); textSize(10); fill(0); text("up", karyogramButtonUpX+8, karyogramButtonUpY+17); // push karyograms up if ((mouseX >= karyogramButtonUpX) && (mouseX <= karyogramButtonUpX + karyogramButtonSize) && (mouseY >= karyogramButtonUpY) && (mouseY <= karyogramButtonUpY + karyogramButtonSize)) { fill(#FFD95D); } else { fill(#FFC400); } rect(karyogramButtonDownX, karyogramButtonDownY, karyogramButtonSize, karyogramButtonSize); textSize(10); fill(0); text("down", karyogramButtonDownX+3, karyogramButtonDownY+17); } void drawStats() { fill(255); int avgAgeTotal = 0; int mostChildren = 0; int mostChildrenId = 0; int livePeople = 0; int[] mbti = new int[16]; int[] personCharsRawTotal = new int[numPeople]; for (int i=0;i mostChildren) { mostChildren = person[i].children; mostChildrenId = i; } } // avg age int avgAge; if (livePeople > 0) { avgAge = int(avgAgeTotal / livePeople); } else { avgAge = 0; } text("average age: " + avgAge, 10, 80); // most offspring text("most children: " + person[mostChildrenId].namePerson + ", " + mostChildren, 10, 100); // jack-of-all-trades winner int highestCharsTotal = 0; int highestCharsId = -1; for (int i=1;i highestCharsTotal) { highestCharsId = i; highestCharsTotal = personCharsRawTotal[i]; } } int personCharsAvg = int(personCharsRawTotal[highestCharsId] / numCharacteristics); text("jack of all trades award: ", 10, 120); text(" " + person[highestCharsId].namePerson + " (" + personCharsRawTotal[highestCharsId] + ", avg: " + personCharsAvg + ")", 10, 135); // myers-briggs count text("personality types:", 10, 155); for (int i=0;i gestationRate) && (person[_flirter1].age >= 18) && (person[_flirter1].age <= maxReproductiveAge) && (person[_flirter2].age >= 18)) { fertile = true; } } else if (person[_flirter2].gender == "female" && person[_flirter1].alive == true) { female = 2; if ((currentYear - person[_flirter2].lastBaby > gestationRate) && (person[_flirter2].age >= 18) && (person[_flirter2].age <= maxReproductiveAge) && (person[_flirter1].age >= 18)) { fertile = true; } } return fertile; } int punnettSquare(int comp1, int comp2) { int mutation = (int)random(0, 9.99); int offspringTraitVal = ceil((comp1 + comp2) / 2); if (mutation < 3) { offspringTraitVal += (int)random(-2, 2); } if (offspringTraitVal < 1) { offspringTraitVal = 1; } if (offspringTraitVal > 10) { offspringTraitVal = 10; } //System.out.println(comp1 + " " + comp2 + " " + offspringTraitVal); return offspringTraitVal; } } public class Nation { Hashtable trait = new Hashtable(); int uniqueID, security, innovation, jobOpportunity, immigrationPolicy,lifeExpectancy, education, sanitation, standardOfLiving,pollution,biodiversity,crime,politicalFreedom,nutrition; private int xPos; private int yPos; String nameNation; int[] colorBaseArray = new int[3]; // need base colors for each nation int[][] colorBaseArraySquares = new int[numNationCharacteristics][3]; int[][] traitPosArray = new int[numNationCharacteristics][2]; // save x,y for all characteristics Nation(int _uniqueID, String _nameNation, int _xPos, int _yPos, int _security, int _innovation, int _jobOpportunity, int _immigrationPolicy, int _lifeExpectancy, int _education, int _sanitation, int _standardOfLiving, int _pollution, int _biodiversity, int _crime, int _politicalFreedom, int _nutrition) { trait.put("security", _security); trait.put("innovation", _innovation); trait.put("jobOpportunity", _jobOpportunity); trait.put("immigrationPolicy", _immigrationPolicy); trait.put("lifeExpectancy", _lifeExpectancy); trait.put("education", _education); trait.put("sanitation", _sanitation); trait.put("standardOfLiving", _standardOfLiving); trait.put("pollution", _pollution); trait.put("biodiversity", _biodiversity); trait.put("crime", _crime); trait.put("politicalFreedom", _politicalFreedom); trait.put("nutrition", _nutrition); uniqueID = _uniqueID; nameNation = _nameNation; security = _security; innovation = _innovation; jobOpportunity = _jobOpportunity; immigrationPolicy = _immigrationPolicy; lifeExpectancy = _lifeExpectancy; education = _education; sanitation = _sanitation; standardOfLiving = _standardOfLiving; pollution = _pollution; biodiversity = _biodiversity; crime = _crime; politicalFreedom = _politicalFreedom; nutrition = _nutrition; xPos = _xPos; yPos = _yPos; // each Nation object has unique color base for (int j=0;j<3;j++) { colorBaseArray[j] = int(random(255)); } colorMode(HSB); for (int j=0;j pHeight) { _pHeight = pHeight; } if (_pWeight > pWeight) { _pWeight = pWeight; } int pFeet = round(_pHeight / 12); int pInches = _pHeight % 12; fill(255,200); if (namePerson == "God") { text(namePerson, xPos+15, yPos+15); } else { text(namePerson + " (" + gender + ", " + age + "yo, " + getFuncs.getNationality(nationality) + ")", xPos+15, yPos+15); text(_pWeight + "lbs, " + pFeet + "'" + pInches + "\"", xPos+15, yPos+25); } } // display for Person } // end Person class public class Religion { Hashtable trait = new Hashtable(); int uniqueID, commercial, morality, hierarchy,portability; private int xPos; private int yPos; String nameReligion; int[] colorBaseArray = new int[3]; // need base colors for each religion int[][] colorBaseArraySquares = new int[numReligionCharacteristics][3]; int[][] traitPosArray = new int[numReligionCharacteristics][2]; // save x,y for all characteristics Religion(int _uniqueID, String _nameReligion, int _xPos, int _yPos, int _commercial, int _morality, int _hierarchy, int _portability) { trait.put("commercial", _commercial); trait.put("morality", _morality); trait.put("hierarchy", _hierarchy); trait.put("portability", _portability); uniqueID = _uniqueID; nameReligion = _nameReligion; commercial = _commercial; morality = _morality; hierarchy = _hierarchy; portability = _portability; xPos = _xPos; yPos = _yPos; // each religion object has unique color base for (int j=0;j<3;j++) { colorBaseArray[j] = int(random(255)); } colorMode(HSB); for (int j=0;j