final boolean USE_RANDOM_SEED = false;
final float WINDOW_SIZE = 1.0;
final float SORT_ANIMATION_SPEED = 5.0;
final float MINIMUM_NODE_SIZE = 0.4;
final float MAXIMUM_NODE_SIZE = 0.4;
final float MINIMUM_NODE_FRICTION = 0.0;
final float MAXIMUM_NODE_FRICTION = 1.0;
final float GRAVITY = 0.005;
final float AIR_FRICTION = 0.95;
final float MUTABILITY_FACTOR = 2.5;
boolean haveGround = true;
final Rectangle[] RECTANGLES = {
int histBarsPerMeter = 10;
ArrayList<Float[]> percentile = new ArrayList<Float[]>(0);
ArrayList<Integer[]> barCounts = new ArrayList<Integer[]>(0);
ArrayList<Integer[]> speciesCounts = new ArrayList<Integer[]>(0);
ArrayList<Integer> topSpeciesCounts = new ArrayList<Integer>(0);
ArrayList<Creature> creatureDatabase = new ArrayList<Creature>(0);
ArrayList<Rectangle> rects = new ArrayList<Rectangle>(0);
final float FRICTION = 4;
int minBar = int(histMinValue*histBarsPerMeter);
int maxBar = int(histMaxValue*histBarsPerMeter);
int barLen = maxBar-minBar;
boolean justGotBack = false;
int[] fontSizes = {50,36,25,20,16,14,11,9};
boolean miniSimulation = false;
int creatureWatching = 0;
int[] creaturesInPosition = new int[1000];
int[] p = {0,10,20,30,40,50,60,70,80,90,
100,200,300,400,500,600,700,800,900,910,920,930,940,950,960,970,980,990,999};
float inter(int a, int b, float offset){
return float(a)+(float(b)-float(a))*offset;
return pow(random(-1,1),19);
return int(random(-0.01,1.01));
Rectangle(float tx1, float ty1, float tx2, float ty2){
float x, y, vx, vy, m, f;
Node(float tx, float ty, float tvx, float tvy, float tm, float tf){
void applyGravity(int i){
void hitWalls(int index){
if(dif >= 0 && haveGround){
ni.vx -= ni.f*dif*FRICTION;
ni.vx += ni.f*dif*FRICTION;
for(int i = 0; i < rects.size(); i++){
Rectangle r = rects.get(i);
if(abs(ni.x-(r.x1+r.x2)/2) <= (r.x2-r.x1+ni.m)/2 && abs(ni.y-(r.y1+r.y2)/2) <= (r.y2-r.y1+ni.m)/2){
if(ni.x >= r.x1 && ni.x < r.x2 && ni.y >= r.y1 && ni.y < r.y2){
if(d1 < d2 && d1 < d3 && d1 < d4){
}else if(d2 < d3 && d2 < d4){
float distance = dist(ni.x,ni.y,px,py);
if(distance <= 0.00000001){
wallAngle = PI/4.0 + section*PI/4.0;
wallAngle = 5*PI/4.0 + (8-section)*PI/4.0;
}else if(section == 5 || section == 4){
wallAngle = atan2(py-ni.y,px-ni.x);
if(distance < rad || flip){
float multi = rad/distance;
ni.x = (ni.x-px)*multi+px;
ni.y = (ni.y-py)*multi+py;
float veloAngle = atan2(ni.vy,ni.vx);
float veloMag = dist(0,0,ni.vx,ni.vy);
float relAngle = veloAngle-wallAngle;
float relY = sin(relAngle)*veloMag*dif*FRICTION;
ni.vx = -sin(relAngle)*relY;
ni.vy = cos(relAngle)*relY;
return (new Node(x,y,0,0,m,f));
Node modifyNode(float mutability){
float newX = x+r()*0.5*mutability*MUTABILITY_FACTOR;
float newY = y+r()*0.5*mutability*MUTABILITY_FACTOR;
float newM = m+r()*0.1*mutability*MUTABILITY_FACTOR;
newM = min(max(newM,MINIMUM_NODE_SIZE),MAXIMUM_NODE_SIZE);
float newF = f+r()*0.1*mutability*MUTABILITY_FACTOR;
newF = min(max(newF,MINIMUM_NODE_FRICTION),MAXIMUM_NODE_FRICTION);
return (new Node(newX,newY,0,0,newM,newF));
float contractTime,contractLength, extendTime, extendLength;
Muscle(int tperiod, int tc1, int tc2, float tcontractTime,
float textendTime, float tcontractLength, float textendLength, boolean tcontracted, float trigidity){
contractTime = tcontractTime;
extendTime = textendTime;
contractLength = tcontractLength;
extendLength = textendLength;
contracted = tcontracted;
void applyForce(int i, float target){
float distance = dist(ni1.x,ni1.y,ni2.x,ni2.y);
float angle = atan2(ni1.y-ni2.y,ni1.x-ni2.x);
force = min(max(1-(distance/target),-0.4),0.4);
ni1.vx += cos(angle)*force*rigidity/ni1.m;
ni1.vy += sin(angle)*force*rigidity/ni1.m;
ni2.vx -= cos(angle)*force*rigidity/ni2.m;
ni2.vy -= sin(angle)*force*rigidity/ni2.m;
return new Muscle(period,c1,c2,contractTime,extendTime,
contractLength,extendLength,contracted,rigidity);
Muscle modifyMuscle(int nodeNum,float mutability){
if(random(0,1)<0.02*mutability*MUTABILITY_FACTOR){
newc1 = int(random(0,nodeNum));
if(random(0,1)<0.02*mutability*MUTABILITY_FACTOR){
newc2 = int(random(0,nodeNum));
float newR = min(max(rigidity*(1+r()*0.9*mutability*MUTABILITY_FACTOR),0.01),0.08);
float maxMuscleChange = 1+0.025/newR;
float newCL = min(max(contractLength+r()*mutability*MUTABILITY_FACTOR,0.4),2);
float newEL = min(max(extendLength+r()*mutability*MUTABILITY_FACTOR,0.4),2);
float newCL2 = min(newCL,newEL);
float newEL2 = min(max(newCL,newEL),newCL2*maxMuscleChange);
float newCT = contractTime;
float newET = extendTime;
newCT = ((contractTime-extendTime)*r()*mutability*MUTABILITY_FACTOR+newCT+1)%1;
newET = ((extendTime-contractTime)*r()*mutability*MUTABILITY_FACTOR+newET+1)%1;
return new Muscle(max(period+rInt(),0),
newc1,newc2,newCT,newET,newCL2,newEL2,isItContracted(newCT,newET),newR);
Creature(int tid, ArrayList<Node> tn, ArrayList<Muscle> tm, float td, boolean talive, float tct, float tmut){
Creature modified(int id){
Creature modifiedCreature = new Creature(id,
new ArrayList<Node>(0),new ArrayList<Muscle>(0),0,true,
creatureTimer+r()*16*mutability*MUTABILITY_FACTOR,min(mutability*MUTABILITY_FACTOR*random(0.8,1.25),2));
for(int i = 0; i < n.size(); i++){
modifiedCreature.n.add(n.get(i).modifyNode(mutability));
for(int i = 0; i < m.size(); i++){
modifiedCreature.m.add(m.get(i).modifyMuscle(n.size(),mutability));
if(random(0,1) < 0.04*mutability*MUTABILITY_FACTOR || n.size() <= 2){
modifiedCreature.addRandomNode();
if(random(0,1) < 0.04*mutability*MUTABILITY_FACTOR){
modifiedCreature.addRandomMuscle(-1,-1);
if(random(0,1) < 0.04*mutability*MUTABILITY_FACTOR && modifiedCreature.n.size() >= 4){
modifiedCreature.removeRandomNode();
if(random(0,1) < 0.04*mutability*MUTABILITY_FACTOR && modifiedCreature.m.size() >= 2){
modifiedCreature.removeRandomMuscle();
modifiedCreature.checkForOverlap();
modifiedCreature.checkForLoneNodes();
ArrayList<Integer> bads = new ArrayList<Integer>();
for(int i = 0; i < m.size(); i++){
for(int j = i+1; j < m.size(); j++){
if(m.get(i).c1 == m.get(j).c1 && m.get(i).c2 == m.get(j).c2){
}else if(m.get(i).c1 == m.get(j).c2 && m.get(i).c2 == m.get(j).c1){
}else if(m.get(i).c1 == m.get(i).c2){
for(int i = bads.size()-1; i >= 0; i--){
void checkForLoneNodes(){
for(int i = 0; i < n.size(); i++){
for(int j = 0; j < m.size(); j++){
connectedTo = m.get(j).c2;
}else if(m.get(j).c2 == i){
connectedTo = m.get(j).c1;
int newConnectionNode = floor(random(0,n.size()));
while(newConnectionNode == i || newConnectionNode == connectedTo){
newConnectionNode = floor(random(0,n.size()));
addRandomMuscle(i,newConnectionNode);
int parentNode = floor(random(0,n.size()));
float ang1 = random(0,2*PI);
float distance = sqrt(random(0,1));
float x = n.get(parentNode).x+cos(ang1)*0.5*distance;
float y = n.get(parentNode).y+sin(ang1)*0.5*distance;
n.add(new Node(x,y,0,0,random(MINIMUM_NODE_SIZE,MAXIMUM_NODE_SIZE),
random(MINIMUM_NODE_FRICTION,MAXIMUM_NODE_FRICTION)));
for(int i = 0; i < n.size()-1; i++){
if(sqrt(dx*dx+dy*dy) < record){
record = sqrt(dx*dx+dy*dy);
addRandomMuscle(parentNode,n.size()-1);
addRandomMuscle(nextClosestNode,n.size()-1);
void addRandomMuscle(int tc1, int tc2){
tc1 = int(random(0,n.size()));
while(tc2 == tc1 && n.size() >= 2){
tc2 = int(random(0,n.size()));
float rlength1 = random(0.5,1.5);
float rlength2 = random(0.5,1.5);
float rtime1 = random(0,1);
float rtime2 = random(0,1);
float distance = dist(n.get(tc1).x,n.get(tc1).y,n.get(tc2).x,n.get(tc2).y);
float ratio = random(0.01,0.2);
rlength1 = distance*(1-ratio);
rlength2 = distance*(1+ratio);
m.add(new Muscle(int(random(1,3)),tc1,tc2,rtime1,rtime2,
min(rlength1,rlength2),max(rlength1,rlength2),isItContracted(rtime1,rtime2),random(0.02,0.08)));
int choice = floor(random(0,n.size()));
if(m.get(i).c1 == choice || m.get(i).c2 == choice){
for(int j = 0; j < m.size(); j++){
if(m.get(j).c1 >= choice){
if(m.get(j).c2 >= choice){
void removeRandomMuscle(){
int choice = floor(random(0,m.size()));
Creature copyCreature(int newID){
ArrayList<Node> n2 = new ArrayList<Node>(0);
ArrayList<Muscle> m2 = new ArrayList<Muscle>(0);
for(int i = 0; i < n.size(); i++){
n2.add(n.get(i).copyNode());
for(int i = 0; i < m.size(); i++){
m2.add(m.get(i).copyMuscle());
return new Creature(newID,n2,m2,d,alive,creatureTimer,mutability);
void drawGround(int toImage){
if(haveGround) rect(0,windowHeight*0.8,windowWidth,windowHeight*0.2);
for(int i = 0; i < rects.size(); i++){
Rectangle r = rects.get(i);
rect(r.x1/camzoom-cam/camzoom+windowWidth/2,r.y1/camzoom+windowHeight*0.8,(r.x2-r.x1)/camzoom,(r.y2-r.y1)/camzoom);
popUpImage.fill(0,130,0);
if(haveGround) popUpImage.rect(0,360,450,90);
for(int i = 0; i < rects.size(); i++){
Rectangle r = rects.get(i);
popUpImage.rect(r.x1/camzoom-cam/camzoom+ww/2,r.y1/camzoom+wh*0.8,(r.x2-r.x1)/camzoom,(r.y2-r.y1)/camzoom);
void drawNode(Node ni, float x, float y,int toImage){
color c = color(512-int(ni.f*512),0,0);
c = color(255,255-int(ni.f*512),255-int(ni.f*512));
ellipse(ni.x/camzoom+x,ni.y/camzoom+y,ni.m/camzoom,ni.m/camzoom);
screenImage.ellipse(ni.x/camzoom+x,ni.y/camzoom+y,ni.m/camzoom,ni.m/camzoom);
popUpImage.ellipse(ni.x/camzoom+x,ni.y/camzoom+y,ni.m/camzoom,ni.m/camzoom);
void drawMuscle(Muscle mi, Node ni1, Node ni2, float x,float y,int toImage){
boolean c = mi.contracted;
stroke(70,35,0,mi.rigidity*3000);
line(ni1.x/camzoom+x, ni1.y/camzoom+y, ni2.x/camzoom+x, ni2.y/camzoom+y);
screenImage.strokeWeight(w);
screenImage.stroke(70,35,0,mi.rigidity*3000);
screenImage.line(ni1.x/camzoom+x, ni1.y/camzoom+y, ni2.x/camzoom+x, ni2.y/camzoom+y);
popUpImage.strokeWeight(w);
popUpImage.stroke(70,35,0,mi.rigidity*3000);
popUpImage.line(ni1.x/camzoom+x, ni1.y/camzoom+y, ni2.x/camzoom+x, ni2.y/camzoom+y);
void drawPosts(int toImage){
for(int i = int((-cam*camzoom-windowWidth/2)/5)-1;
i <= int((-cam*camzoom+windowWidth/2)/5)+1; i++){
rect(windowWidth/2+(i*5-cam-0.1)/camzoom,windowHeight*0.8-3/camzoom,0.2/camzoom,3/camzoom);
rect(windowWidth/2+(i*5-cam-1)/camzoom,windowHeight*0.8-3/camzoom,2/camzoom,1/camzoom);
text(i+" m",windowWidth/2+(i*5-cam)/camzoom,windowHeight*0.8-2.17/camzoom);
popUpImage.textAlign(CENTER);
popUpImage.textFont(font, 0.96/camzoom);
for(int i = int((-cam*camzoom-w/2)/5)-1;
i <= int((-cam*camzoom+w/2)/5)+1; i++){
popUpImage.rect(w/2+(i*5-cam-0.1)/camzoom,h*0.8-3/camzoom,0.2/camzoom,3/camzoom);
popUpImage.rect(w/2+(i*5-cam-1)/camzoom,h*0.8-3/camzoom,2/camzoom,1/camzoom);
popUpImage.text(i+" m",w/2+(i*5-cam)/camzoom,h*0.8-2.17/camzoom);
rect(windowWidth/2+(x-cam-1.7)/camzoom,windowHeight*0.8-4.8/camzoom,3.4/camzoom,1.1/camzoom);
vertex(windowWidth/2+(x-cam)/camzoom,windowHeight*0.8-3.2/camzoom);
vertex(windowWidth/2+(x-cam-0.5)/camzoom,windowHeight*0.8-3.7/camzoom);
vertex(windowWidth/2+(x-cam+0.5)/camzoom,windowHeight*0.8-3.7/camzoom);
text((float(round(x*2))/10)+" m",windowWidth/2+(x-cam)/camzoom,windowHeight*0.8-3.91/camzoom);
image(graphImage,50,180,650,380);
image(segBarImage,50,580,650,100);
float genWidth = float(610)/gen;
float lineX = 90+genSelected*genWidth;
line(lineX,180,lineX,500+180);
Integer[] s = speciesCounts.get(genSelected);
for(int i = 1; i < 101; i++){
float y = ((s[i]+s[i-1])/2)/1000.0*100+573;
if(i-1 == topSpeciesCounts.get(genSelected)){
fill(getColor(i-1,true));
text("S"+floor((i-1)/10)+""+((i-1)%10)+": "+c,lineX+11,y+12);
color getColor(int i, boolean adjust){
float col = (i*1.618034)%1;
if(abs(col-0.333) <= 0.18 && adjust){
return color(col,1.0,light);
void drawGraph(int graphWidth, int graphHeight){
drawLines(60,int(graphHeight*0.05),graphWidth-60,int(graphHeight*0.9));
drawSegBars(60,0,graphWidth-60,150);
void drawLines(int x, int y, int graphWidth, int graphHeight){
graphImage.background(220);
float gh = float(graphHeight);
float genWidth = float(graphWidth)/gen;
float worst = extreme(-1);
float meterHeight = float(graphHeight)/(best-worst);
float zero = (best/(best-worst))*gh;
float unit = setUnit(best, worst);
graphImage.strokeWeight(2);
graphImage.textFont(font, 18);
graphImage.textAlign(RIGHT);
for(float i = ceil((worst-(best-worst)/18.0)/unit)*unit; i < best+(best-worst)/18.0;i+=unit){
float lineY = y-i*meterHeight+zero;
graphImage.line(x,lineY,graphWidth+x,lineY);
graphImage.text(showUnit(i,unit)+" m",x-5,lineY+4);
for(int i = 0; i < 29; i++){
graphImage.stroke(255,0,0,255);
graphImage.strokeWeight(5);
if(k == 0 || k == 28 || (k >= 10 && k <= 18)){
graphImage.strokeWeight(3);
graphImage.strokeWeight(1);
for(int j = 0; j < gen; j++){
graphImage.line(x+j*genWidth,(-percentile.get(j)[k])*meterHeight+zero+y,
x+(j+1)*genWidth,(-percentile.get(j+1)[k])*meterHeight+zero+y);
void drawSegBars(int x, int y, int graphWidth, int graphHeight){
segBarImage.colorMode(HSB, 1);
segBarImage.background(0,0,0.5);
float genWidth = float(graphWidth)/gen;
int gensPerBar = floor(gen/500)+1;
for(int i = 0; i < gen; i+=gensPerBar){
int i2 = min(i+gensPerBar,gen);
float barX1 = x+i*genWidth;
float barX2 = x+i2*genWidth;
for(int j = 0; j < 100; j++){
segBarImage.fill(getColor(j,false));
segBarImage.beginShape();
segBarImage.vertex(barX1,y+speciesCounts.get(i)[j]/1000.0*graphHeight);
segBarImage.vertex(barX1,y+speciesCounts.get(i)[j+1]/1000.0*graphHeight);
segBarImage.vertex(barX2,y+speciesCounts.get(i2)[j+1]/1000.0*graphHeight);
segBarImage.vertex(barX2,y+speciesCounts.get(i2)[j]/1000.0*graphHeight);
float extreme(float sign){
for(int i = 0; i < gen; i++){
float toTest = percentile.get(i+1)[int(14-sign*14)];
if(toTest*sign > record*sign){
float setUnit(float best, float worst){
float unit2 = 3*log(best-worst)/log(10)-3.3;
return pow(10,int(unit2/3));
}else if((unit2+100)%3 < 2){
return pow(10,int((unit2-1)/3))*2;
return pow(10,int((unit2-2)/3))*5;
String showUnit(float i, float unit){
ArrayList<Creature> quickSort(ArrayList<Creature> c){
ArrayList<Creature> less = new ArrayList<Creature>();
ArrayList<Creature> more = new ArrayList<Creature>();
ArrayList<Creature> equal = new ArrayList<Creature>();
for(int i = 1; i < c.size(); i++){
ArrayList<Creature> total = new ArrayList<Creature>();
total.addAll(quickSort(more));
total.addAll(quickSort(less));
boolean isItContracted(float rtime1, float rtime2){
void toStableConfiguration(int nodeNum, int muscleNum){
for(int j = 0; j < 200; j++){
for(int i = 0; i < muscleNum; i++){
target = mi.contractLength;
target = mi.extendLength;
for(int i = 0; i < nodeNum; i++){
for(int i = 0; i < nodeNum; i++){
void adjustToCenter(int nodeNum){
for(int i = 0; i < nodeNum; i++){
for(int i = 0; i < nodeNum; i++){
void setGlobalVariables(Creature thisCreature){
for(int i = 0; i < thisCreature.n.size(); i++){
n.add(thisCreature.n.get(i).copyNode());
for(int i = 0; i < thisCreature.m.size(); i++){
m.add(thisCreature.m.get(i).copyMuscle());
cTimer = thisCreature.creatureTimer;
for(int i = 0; i < m.size(); i++){
mi.thruPeriod = ((float(timer)/cTimer)/float(mi.period))%float(1);
if((mi.thruPeriod <= mi.extendTime && mi.extendTime <= mi.contractTime) ||
(mi.contractTime <= mi.thruPeriod && mi.thruPeriod <= mi.extendTime) ||
(mi.extendTime <= mi.contractTime && mi.contractTime <= mi.thruPeriod)){
target = mi.contractLength;
target = mi.extendLength;
for(int i = 0; i < n.size(); i++){
for(int i = 0; i < n.size(); i++){
average = average/n.size();
ArrayList<Node> n = new ArrayList<Node>();
ArrayList<Muscle> m = new ArrayList<Muscle>();
Creature[] c = new Creature[1000];
ArrayList<Creature> c2 = new ArrayList<Creature>();
void mouseWheel(MouseEvent event) {
int delta = event.getCount();
textFont(font, 0.96/camzoom);
textFont(font, 0.96/camzoom);
float mX = mouseX/WINDOW_SIZE;
float mY = mouseY/WINDOW_SIZE;
if(menu == 1 && gen >= 1 && abs(mY-365) <= 25 && abs(mX-sliderX-25) <= 25){
void openMiniSimulation(){
cj = creatureDatabase.get((genSelected-1)*3+statusWindow+3);
float mX = mouseX/WINDOW_SIZE;
float mY = mouseY/WINDOW_SIZE;
if(menu == 0 && abs(mX-windowWidth/2) <= 200 && abs(mY-400) <= 100){
}else if(menu == 1 && gen == -1 && abs(mX-120) <= 100 && abs(mY-300) <= 50){
}else if(menu == 1 && gen >= 0 && abs(mX-990) <= 230){
}else if(menu == 3 && abs(mX-1030) <= 130 && abs(mY-684) <= 20){
}else if(menu == 7 && abs(mX-1030) <= 130 && abs(mY-684) <= 20){
}else if(menu == 9 && abs(mX-1030) <= 130 && abs(mY-690) <= 20){
}else if(menu == 11 && abs(mX-1130) <= 80 && abs(mY-690) <= 20){
}else if(menu == 13 && abs(mX-1130) <= 80 && abs(mY-690) <= 20){
void drawScreenImage(int stage){
screenImage.background(220,253,102);
for(int j = 0; j < 1000; j++){
if(stage == 3) cj = c[cj.id-(gen*1000)-1001];
creaturesInPosition[j2] = j;
drawCreatureWhole(cj,x*30+55,y*25+40,1);
screenImage.textAlign(CENTER);
screenImage.textFont(font, 24);
screenImage.fill(100,100,200);
screenImage.rect(900,664,260,40);
screenImage.text("We've tested everybody. Let's sort!",windowWidth/2-200,690);
screenImage.text("Go!",windowWidth-250,690);
screenImage.rect(900,670,260,40);
screenImage.text("We have the best creatures here.",windowWidth/2,30);
screenImage.text("These are the worst.",windowWidth/2-200,700);
screenImage.text("Kill 50% of population.",windowWidth-250,700);
screenImage.rect(1050,670,160,40);
screenImage.text("The faster creatures are more likely to survive then die, as they can outrun enemies, thus slow ones get eaten and die.",windowWidth/2,30);
screenImage.text("All because of RNG, a few fast creatures die, while a few slow survive.",windowWidth/2-130,700);
screenImage.text("Have babies!",windowWidth-150,700);
for(int j = 0; j < 1000; j++){
drawCreatureWhole(cj,x*30+55,y*25+40,0);
screenImage.rect(x*30+40,y*25+17,30,25);
screenImage.rect(1050,670,160,40);
screenImage.text("These are the people of the next generation, Gen #"+(gen+2)+".",windowWidth/2,30);
screenImage.text("What perils and challenges will these creatures face? Find out next generation!",windowWidth/2-130,700);
screenImage.text("Back to Main Menu",windowWidth-150,700);
cam += (average-cam)*0.1;
if(simulationTimer < 900){
popUpImage.background(120,200,255);
popUpImage.background(60,100,128);
drawCreature(n,m,-cam/camzoom+450/2, 450*0.8,2);
void drawCreatureWhole(Creature cj, float x, float y, int toImage){
for(int i = 0; i < cj.m.size(); i++){
drawMuscle(mi,cj.n.get(mi.c1),cj.n.get(mi.c2),x,y,toImage);
for(int i = 0; i < cj.n.size(); i++){
drawNode(cj.n.get(i),x,y,toImage);
void drawCreature(ArrayList<Node> n, ArrayList<Muscle> m, float x, float y, int toImage){
for(int i = 0; i < m.size(); i++){
drawMuscle(mi,n.get(mi.c1),n.get(mi.c2),x,y,toImage);
for(int i = 0; i < n.size(); i++){
drawNode(n.get(i),x,y,toImage);
void drawHistogram(int x, int y, int hw, int hh){
for(int i = 0; i < barLen; i++){
if(barCounts.get(genSelected)[i] > maxH){
maxH = barCounts.get(genSelected)[i];
float barW = (float)hw/barLen;
float multiplier = (float)hh/maxH*0.9;
if(maxH < 300) unit = 50;
if(maxH < 100) unit = 20;
for(int i = 0; i < hh/multiplier; i += unit){
float theY = y+hh-i*multiplier;
for(int i = minBar; i <= maxBar; i ++){
float theX = x+(i-minBar)*barW;
text(nf((float)i/histBarsPerMeter,0,1),theX,y+hh+14);
for(int i = 0; i < barLen; i++){
float h = min(barCounts.get(genSelected)[i]*multiplier,hh);
if(i+minBar == floor(percentile.get(min(genSelected,percentile.size()-1))[14]*histBarsPerMeter)){
rect(x+i*barW,y+hh-h,barW,h);
int rank = (statusWindow+1);
stroke(abs(overallTimer%30-15)*17);
cj = c2.get(statusWindow);
int id = ((cj.id-1)%1000);
y = floor(statusWindow/40)+1;
rect(x*30+40,y*25+17,30,25);
cj = creatureDatabase.get((genSelected-1)*3+statusWindow+3);
x = 760+(statusWindow+3)*160;
int[] ranks = {1000,500,1};
rank = ranks[statusWindow+3];
text("ID code: "+cj.id,px,py+24);
text("Length: "+nf(cj.d,0,3),px,py+36);
int sp = (cj.n.size()%10)*10+(cj.m.size()%10);
text("Species: C"+(cj.n.size()%10)+""+(cj.m.size()%10),px,py+48);
int px2 = min(max(px-90,10),970);
image(popUpImage,px2,py2,300,300);
rect(px2+240,py2+10,50,30);
rect(px2+10,py2+10,100,30);
text(int(simulationTimer/60),px2+285,py2+36);
text(nf(average/5.0,0,3),px2+15,py2+36);
int shouldBeWatching = statusWindow;
cj = creatureDatabase.get((genSelected-1)*3+statusWindow+3);
shouldBeWatching = cj.id;
if(creatureWatching != shouldBeWatching){
Float[] beginPercentile = new Float[29];
Integer[] beginBar = new Integer[barLen];
Integer[] beginSpecies = new Integer[101];
for(int i = 0; i < 29; i++){
beginPercentile[i] = 0.0;
for(int i = 0; i < barLen; i++){
for(int i = 0; i < 101; i++){
percentile.add(beginPercentile);
speciesCounts.add(beginSpecies);
graphImage = createGraphics(975,570,P2D);
screenImage = createGraphics(1280,720,P2D);
popUpImage = createGraphics(450,450,P2D);
segBarImage = createGraphics(975,150,P2D);
font = loadFont("Helvetica-Bold-96.vlw");
for(int i = 0; i < RECTANGLES.length; i++){
rects.add(RECTANGLES[i]);
rect(windowWidth/2-200,300,400,200);
text("Welcome to Evolution Simulator!", windowWidth/2,200);
text("Let's get started.", windowWidth/2,430);
text("Generation "+max(genSelected,0),20,100);
text("Right off the bat, we need to make 1000 creatures!",20,160);
text("They will either be created with advantages or defects.",20,200);
text("Create 1K Creatures!",56,312);
text("See all the creatures one at a time!",770,50);
text("See the creatures finish right away.",770,100);
text("See the diversity.",770,150);
text("Currently going long.",996,136);
text("Click ANYWHERE on the screen to stop.",996,153);
text("Go into ALAP mode.",1000,150);
text("Average Distance:",50,160);
text(float(round(percentile.get(min(genSelected,percentile.size()-1))[14]*1000))/1000+" m",700,160);
drawHistogram(760,410,460,280);
for(int y = 0; y < 25; y++){
for(int x = 0; x < 40; x++){
int nodeNum = int(random(3,6));
int muscleNum = int(random(nodeNum-1,nodeNum*3-6));
for(int i = 0; i < nodeNum; i++){
n.add(new Node(random(-1,1),random(-1,1),0,0,
random(MINIMUM_NODE_SIZE,MAXIMUM_NODE_SIZE),
random(MINIMUM_NODE_FRICTION,MAXIMUM_NODE_FRICTION)));
for(int i = 0; i < muscleNum; i++){
tc1 = int(random(0,nodeNum));
tc2 = int(random(0,nodeNum));
float rlength1 = random(0.5,1.5);
float rlength2 = random(0.5,1.5);
float rtime1 = random(0,1);
float rtime2 = random(0,1);
m.add(new Muscle(int(random(1,3)),tc1,tc2,rtime1,rtime2,
min(rlength1,rlength2),max(rlength1,rlength2),isItContracted(rtime1,rtime2),random(0.02,0.08)));
toStableConfiguration(nodeNum,muscleNum);
float heartbeat = random(40,80);
c[y*40+x] = new Creature(y*40+x+1,new ArrayList<Node>(n),new ArrayList<Muscle>(m),0,true,heartbeat,1.0);
c[y*40+x].checkForOverlap();
c[y*40+x].checkForLoneNodes();
drawCreatureWhole(c[y*40+x],x*30+55,y*25+30,0);
text("Here are the creatures. Find out how they move with a step by step generation!",windowWidth/2-200,690);
text("Back",windowWidth-250,690);
setGlobalVariables(c[creaturesTested]);
if(creaturesTested <= 4){
speed = max(creaturesTested,1);
speed = min(creaturesTested*3-9,1000);
for(int i = 0; i < 1000; i++){
setGlobalVariables(c[i]);
for(int s = 0; s < 900; s++){
textFont(font, 0.96/camzoom);
for(int s = 0; s < speed; s++){
for(int s = 0; s < speed; s++){
cam += (average-cam)*0.03;
drawCreature(n,m,-cam/camzoom+windowWidth/2, windowHeight*0.8,0);
text("Creature ID code: "+id,windowWidth-10,32);
timeShow = int((timer+creaturesTested*37)/60)%15;
timeShow = round(timeShow);
text("Time: "+timeShow+" / 15 sec.",windowWidth-10,64);
text("Speed: x"+speed,windowWidth-10,96);
rect(0,0,windowWidth,windowHeight);
rect(windowWidth/2-500,200,1000,240);
text("Length Traveled From Center:",windowWidth/2,300);
text(float(round(average*200))/1000 + " meters",windowWidth/2,400);
c[creaturesTested].d = average*0.2;
if(creaturesTested == 1000){
c2 = new ArrayList<Creature>(0);
for(int i = 0; i < 1000; i++){
percentile.add(new Float[29]);
for(int i = 0; i < 29; i++){
percentile.get(gen+1)[i] = c2.get(p[i]).d;
creatureDatabase.add(c2.get(999).copyCreature(-1));
creatureDatabase.add(c2.get(499).copyCreature(-1));
creatureDatabase.add(c2.get(0).copyCreature(-1));
Integer[] beginBar = new Integer[barLen];
for(int i = 0; i < barLen; i++){
Integer[] beginSpecies = new Integer[101];
for(int i = 0; i < 101; i++){
for(int i = 0; i < 1000; i++){
int bar = floor(c2.get(i).d*histBarsPerMeter-minBar);
if(bar >= 0 && bar < barLen){
barCounts.get(gen+1)[bar]++;
int species = (c2.get(i).n.size()%10)*10+c2.get(i).m.size()%10;
speciesCounts.add(new Integer[101]);
speciesCounts.get(gen+1)[0] = 0;
for(int i = 0; i < 100; i++){
speciesCounts.get(gen+1)[i+1] = cum;
if(beginSpecies[i] > record){
record = beginSpecies[i];
topSpeciesCounts.add(holder);
float transition = 0.5-0.5*cos(min(float(timer)/60,PI));
for(int j = 0; j < 1000; j++){
int j2 = cj.id-(gen*1000)-1;
float x3 = inter(x1,x2,transition);
float y3 = inter(y1,y2,transition);
drawCreatureWhole(cj,x3*30+55,y3*25+40,0);
timer += 1*SORT_ANIMATION_SPEED;
timer += 3*SORT_ANIMATION_SPEED;
float mX = mouseX/WINDOW_SIZE;
float mY = mouseY/WINDOW_SIZE;
if(abs(menu-9) <= 2 && gensToDo == 0 && !drag){
if(abs(mX-639.5) <= 599.5){
if(menu == 7 && abs(mY-329) <= 312){
statusWindow = creaturesInPosition[floor((mX-40)/30)+floor((mY-17)/25)*40];
}else if(menu >= 9 && abs(mY-354) <= 312){
statusWindow = floor((mX-40)/30)+floor((mY-42)/25)*40;
}else if(menu == 1 && genSelected >= 1 && gensToDo == 0 && !drag){
float modX = (mX-760)%160;
statusWindow = floor((mX-760)/160)-3;
for(int j = 0; j < 500; j++){
float rand = (pow(random(-1,1),3)+1)/2;
Creature cj = c2.get(j2);
Creature ck = c2.get(j3);
for(int j = 0; j < 500; j++){
if(!c2.get(j).alive) j2 = 999-j;
Creature cj = c2.get(j2);
Creature cj2 = c2.get(999-j2);
c2.set(999-j2,cj.modified(cj2.id+1000));
toStableConfiguration(n.size(),m.size());
adjustToCenter(n.size());
c2.set(j2,cj.copyCreature(cj.id+1000));
for(int j = 0; j < 1000; j++){
c[cj.id-(gen*1000)-1001] = cj.copyCreature(-1);
if(menu%2 == 1 && abs(menu-10) <= 3){
image(screenImage,0,0,windowWidth,windowHeight);
if(menu == 1 || gensToDo >= 1){
genSelected = round((sliderX-760)*(gen-1)/410)+1;
genSelected = round((sliderX-760)*gen/410);
if(drag) sliderX = min(max(sliderX+(mX-25-sliderX)*0.2,760),1170);
fs = floor(log(genSelected)/log(10));
fontSize = fontSizes[fs];
text(genSelected,sliderX+25,366+fontSize*0.3333);
for(int k = 0; k < 3; k++){
rect(760+k*160,180,140,140);
drawCreatureWhole(creatureDatabase.get((genSelected-1)*3+k),830+160*k,290,0);
text("Worst of the Worst",830,310);
text("Average Creature",990,310);
text("Greatest Creature!",1150,310);
if(justGotBack) justGotBack = false;
if(statusWindow >= -3 && !miniSimulation){