color debugcolor; //07 Broad-Leaved Woodland_ Late Sprin.m4a ladybug lady; int numAphids = 20; int maxAphids = 20; //int oldMX; //int oldMY; //int mouseMoveCount = 0; bug[] aphids = new bug[maxAphids]; PFont fontScore,fontWin,fontData; int score = 0; float aphidsPerSecond = 0; int flag = 1; int avgAge = 0; int maxAge = 0; int boardWidth = 500; int sideWidth = 500; int boardHeight = 500; int numLeaves = 500; PGraphics leavesPG; int numWeights = 10; // 3 inputs * 2 outputs int ladybugBehavior = 1; color targetColor; int aphidCaptureCount = 0; // counts aphids per 10 seconds float aphidsPerMinute = 0; float aphidPerMinuteStart = 0; // counts 10 seconds // arrays for aphid data int dataEvery = 20; int maxRecords = 1000; int records = 0; // records index int[] redData = new int[maxRecords]; int[] greenData= new int[maxRecords]; int[] blueData= new int[maxRecords]; int[] alphaData= new int[maxRecords]; int[] speedData= new int[maxRecords]; //bug[] bugData = new bug[maxRecords]; color[][] colorData = new color[maxAphids][maxRecords]; int allAlphaData[][] = new int[maxAphids][maxRecords]; int counter = 0; boolean PAUSE = false; int targetAphid = -1; // used to track which aphid the ladybug is targeting PGraphics pg; void setup(){ pg = createGraphics(sideWidth,boardHeight/3,P2D); frameRate(30); noiseSeed(0); size(boardWidth+sideWidth,boardHeight); background(255,255,255); lady = new ladybug(250,250,40); for(int i =0; i 10000){ // times up, recalc aphids per minute aphidsPerMinute(); } plotStats(); if(!PAUSE){ counter++; } // image(pg,boardWidth,boardHeight-200); ladybugBehaviorButtons(); checkHover(); // must come after all other data drawing to avoid being hidden } void checkHover(){ if(mouseX < boardWidth) // not over data region return; if(mouseY > (2*(boardHeight/3))){ // bottom 3rd textFont(fontData); fill(255,255,255,100); rect(boardWidth+sideWidth/3, 4*(boardHeight/5),sideWidth/3+20,40); fill(0,0,0); text("Historical Aphid Data and\n Average Transparency (black line)", boardWidth+sideWidth/3+10, 4*(boardHeight/5)+18); } else if(mouseY > ((boardHeight/3))){ // middle 3rd textFont(fontData); fill(255,255,255,100); rect(boardWidth+sideWidth/4, (boardHeight/2)-20,sideWidth/2,40); fill(0,0,0); text("Lines are avg. aphid Red, Blue, Green levels \n Background is avg. aphid color", boardWidth+sideWidth/4+10, (boardHeight/2)-20+18); } } void mousePressed(){ int leftXedge = boardWidth+5; int buttonHeight = 40; int numButtons = 4; int buttonWidth = (sideWidth-10)/numButtons; if(mouseX < leftXedge) return; // reset button if(mouseX < leftXedge+4*buttonWidth && mouseX > leftXedge+3*buttonWidth && mouseY < buttonHeight+10 && mouseY > 10){ reset(); } // pause button if(mouseX < leftXedge+3*buttonWidth && mouseX > leftXedge+2*buttonWidth && mouseY < buttonHeight+10 && mouseY > 10){ PAUSE = !PAUSE; } // pause button if(mouseY< ((boardHeight/3) - buttonHeight-15) || mouseY> ((boardHeight/3)-15)){ // see ladybugBehaviorButtons return; } if(mouseX < leftXedge+buttonWidth){ lady.setBehavior(1); // user controlled } else if(mouseX < leftXedge+2*buttonWidth){ lady.setBehavior(3); // forward } else if(mouseX < leftXedge+3*buttonWidth){ lady.setBehavior(2); // left,right lady.switchLadybugSide(); } else if(mouseX < leftXedge+4*buttonWidth){ // ladybugBehavior = 3; // forward still targetColor = get(mouseX,mouseY); addLeaves(targetColor); } } void ladybugBehaviorButtons(){ // draws buttons int numButtons = 4; int leftXedge = boardWidth+5; int buttonHeight = 40; int buttonTop = (boardHeight/3) - buttonHeight - 15; int buttonWidth = (sideWidth-10)/numButtons; for(int i=0;i 255) newRed = 255; newGreen = green(s.c)+random(-1*crange,crange)*random(-1*crange,crange); if(newGreen < 0) newGreen = 0; if(newGreen > 255) newGreen = 255; newBlue = blue(s.c)+random(-1*crange,crange)*random(-1*crange,crange); if(newBlue < 0) newBlue = 0; if(newBlue > 255) newBlue = 255; c = color(newRed,newGreen,newBlue); alphaC = alphaC+int(random(-1*crange,crange)); if(alphaC < 10) alphaC = 10; // can't go completely invisible if(alphaC > 255) alphaC = 255; } float get_radius(){ return radius; } void replace(){ int parent; int flag=0; boolean allGone = true; for(int i =0; i < maxAphids; i++){ if(aphids[i] != null){ allGone = false; break; } } if(allGone == true) return; // no aphids left, keep playing until restart do{ parent = int(random(maxAphids)); if(aphids[parent] != null){ if(random(maxAge) < (aphids[parent].age+1)) flag = 1; } }while(flag == 0); mutCopy(aphids[parent]); } void move(){ runNN(); age++; x+=(v*sin(theta)); y+=(v*cos(theta)); if(x < 0) x = boardWidth; if(x>boardWidth) x = 0; if(y < 0) y = boardHeight; if(y>boardHeight) y = 0; } void display(){ noStroke(); fill(0,0,0,alphaC); ellipse(x+(radius*0.5)*sin(theta-0.2),y+(radius*0.5)*cos(theta-0.2),radius*.25,radius*.25); ellipse(x+(radius*0.5)*sin(theta+0.2),y+(radius*0.5)*cos(theta+0.2),radius*.25,radius*.25); fill(c,alphaC); ellipse(x,y,radius,radius); } } void calcStats(){ float avgV = 0; int count = 0; avgAge = 0; maxAge = 0; textFont(fontData); for(int i = 0; i < maxAphids; i++){ if(aphids[i] != null){ avgAge+=aphids[i].age; count++; avgV+=aphids[i].v; if(aphids[i].age > maxAge){ maxAge = aphids[i].age; } } } avgV /= count; } void calcPlotStats(){ int avgR = 0; int avgG = 0; int avgB = 0; int avgAlpha = 0; int avgSpeed = 0; int aphidCount = 0; for(int i = 0; i < maxAphids; i++){ if(aphids[i] != null){ aphidCount++; avgR += red(aphids[i].c); avgG += green(aphids[i].c); avgB += blue(aphids[i].c); avgSpeed += aphids[i].maxV; avgAlpha += aphids[i].alphaC; colorData[i][records] = aphids[i].c; allAlphaData[i][records] = aphids[i].alphaC; } } avgR /= aphidCount; avgB /= aphidCount; avgG /= aphidCount; avgAlpha /= aphidCount; avgSpeed /= aphidCount; redData[records] = avgR; greenData[records] = avgG; blueData[records] = avgB; alphaData[records] = avgAlpha; speedData[records] = avgSpeed; records++; if(records >= maxRecords) records = 0; // print(records + " " + avgAlpha + "\n"); } void plotStats(){ float dataSize = 3.0; float yStretch = boardHeight/dataSize; float yScaling = (255/yStretch); float baseY = (dataSize-1)*boardHeight/dataSize-10; float leftXEdge = boardWidth+5; float xStep = (sideWidth-10)/float(records-1); if(records > 1){ strokeWeight(2); for(int i =0; i < records-1; i++){ stroke(255,0,0); line(leftXEdge+(i*xStep),baseY-redData[i]/yScaling, leftXEdge+((i+1)*xStep),baseY-redData[i+1]/yScaling); stroke(0,255,0); line(leftXEdge+(i*xStep),baseY-greenData[i]/yScaling, leftXEdge+((i+1)*xStep),baseY-greenData[i+1]/yScaling); stroke(0,0,255); line(leftXEdge+(i*xStep),baseY-blueData[i]/yScaling, leftXEdge+((i+1)*xStep),baseY-blueData[i+1]/yScaling); // stroke(0,0,0); // line(leftXEdge+(i*xStep),baseY-alphaData[i]/yScaling, leftXEdge+((i+1)*xStep),baseY-alphaData[i+1]/yScaling); // stroke(0,0,0); // line(leftXEdge+(i*xStep),baseY-speedData[i]*5, leftXEdge+((i+1)*xStep),baseY-speedData[i+1]*5); noStroke(); fill(redData[i],greenData[i],blueData[i],alphaData[i]); rect((leftXEdge+(i*xStep)),baseY-yStretch,(xStep),yStretch); } strokeWeight(1); } float yScalingPop = (boardHeight/dataSize)/maxAphids; if(records > 1){ // image(leavesPG,leftXEdge,2*boardHeight/3,sideWidth-10,boardHeight/3-15); pg.beginDraw(); for(int i =0; i < records-1; i++){ for(int j = 1; j < maxAphids; j++){ pg.fill(color(colorData[j][i]),allAlphaData[j][i]); pg.noStroke(); pg.rect((5+(i*xStep)),boardHeight/3-(yScalingPop*(j+1)),(xStep),yScalingPop); } } pg.stroke(0,0,0); pg.strokeWeight(1.5); for(int i =0; i < records-1; i++){ // add alpha line pg.line(5+(i*xStep),boardHeight/3-alphaData[i]/yScaling, 5+((i+1)*xStep),boardHeight/3-alphaData[i+1]/yScaling); } pg.endDraw(); image(pg,boardWidth,2*(boardHeight/dataSize)-5); } } // --------------------------------------------------------------------------------- class ladybug{ float dx; float dy; float x; float y; float angle; float radius; float circleAngle = 0; float circleRadius = boardWidth/3; float deltaRadius = -0.5; float maxSpeed; int behavior; int ladybugSide = 1; // 1=left, 0=right ladybug(float ix,float iy, float ir){ // initialize the ladybug x = ix; y=iy; radius = ir; maxSpeed = 10; behavior = 1; // playe controls } float chanceToHide(int a){ color c,aphidC; if(aphids[a] == null) return 0.0; c = leavesPG.get(int(aphids[a].x),int(aphids[a].y)); aphidC = aphids[a].c; float diffcolor; diffcolor = sqrt( (red(c)-red(aphidC))*(red(c)-red(aphidC)) + (green(c)-green(aphidC))*(green(c)-green(aphidC)) + (blue(c)-blue(aphidC))*(blue(c)-blue(aphidC)) ); diffcolor /= sqrt(3*255*255.0); // to normalize diffcolor *= ((255-aphids[a].alphaC)/255.0); // account for transparency // print(diffcolor + "\n"); return (diffcolor); } /* float avoidColor(int a){ color c,aphidC; if(aphids[a] == null) return 0.0; aphidC = aphids[a].c; float diffcolor; diffcolor = sqrt( (255-red(aphidC))*(255-red(aphidC)) + (0-green(aphidC))*(0-green(aphidC)) + (0-blue(aphidC))*(0-blue(aphidC)) ); diffcolor /= sqrt(3*255*255.0); // to normalize diffcolor *= ((255-(aphids[a].alphaC))/255.0); // account for transparency // print(diffcolor + "\n"); return (diffcolor); } */ void setBehavior(int b){ behavior = b; } void switchLadybugSide(){ ladybugSide = (ladybugSide+1)%2; } int getLadybugSide(){ return ladybugSide; } void behaviorMove(){ switch(behavior){ case 1: lady.userMove(); break; case 2: lady.bounceMove(); break; case 3: lady.forwardAphidMove(); break; default: lady.forwardAphidMove(); } move(); } void move(){ if(dx > maxSpeed) dx = maxSpeed; if(dx < -1*maxSpeed) dx = -1*maxSpeed; if(dy > maxSpeed) dy = maxSpeed; if(dy < -1 * maxSpeed) dy = -1 * maxSpeed; x += dx; y += dy; if(x < 0 || x > boardWidth){ dx *=-1; x += dx; } if(y < 0 || y > boardHeight){ dy *=-1; y += dy; } } void circleMove(){ maxSpeed = 20; dx = ((boardWidth/2)+circleRadius*sin(circleAngle)) - x; dy = ((boardHeight/2)+circleRadius*cos(circleAngle)) - y; circleAngle+=0.1; } void spiralMove(){ maxSpeed = 20; dx = ((boardWidth/2)+circleRadius*sin(circleAngle)) - x; dy = ((boardHeight/2)+circleRadius*cos(circleAngle)) - y; circleAngle+=0.1; circleRadius += deltaRadius; if(circleRadius < 75) deltaRadius *= -1; if(circleRadius > (boardWidth/2 - radius)) deltaRadius *= -1; } void bounceMove(){ // left half of the screen only maxSpeed = 20; forwardAphidMove(); int sign; if(ladybugSide == 0 && x > boardWidth/2 && dx > 0) // ladybuSide=0:left ; 1:right dx*=-1; if(ladybugSide == 1 && x < boardWidth/2 && dx < 0) // ladybuSide=0:left ; 1:right dx*=-1; /* if(random(0.0,20.0) < 1){ sign = 1; if(random(0,1) < 0.5) sign = -1; dx = 5 + 5*random(0,1)*sign; sign = 1; if(random(0,1) < 0.5) sign = -1; dy = 5+ 5*random(0,1)*sign; } */ } void forwardAphidMove(){ maxSpeed = 16; // how fast the aphid can move; float angle = atan(lady.dx/lady.dy); // calculate the ladybug angle if(lady.dy<0) angle=angle+PI; float aphidAngle; float deltaX,deltaY; float probOfSeen; float distance,closestDistance = 1000; int closest = -1; // int mostObvious = -1; // float obviousness = 0; for(int i =0; i < maxAphids; i++){ if(aphids[i] != null){ deltaX = (aphids[i].x-x); deltaY = (aphids[i].y-y); aphidAngle = atan(deltaX/deltaY); // calculate aphid angle if(deltaY<0) aphidAngle+= PI; if(abs(angle-aphidAngle) < PI/3.0){ // nearly forward, ok to be closest probOfSeen = chanceToHide(i); if(i == targetAphid){ // same as last seen probOfSeen *= 3.0; // much more likely to see same aphid } /* if(probOfSeen > obviousness){ mostObvious = i; obviousness = probOfSeen; } */ if(random(0.0,1.0) < probOfSeen){ // can it hide distance = sqrt(deltaX*deltaX+deltaY*deltaY); if(distance < closestDistance){ closestDistance = distance; closest = i; } } } } } if(closest != -1){ deltaX = (aphids[closest].x-x); deltaY = (aphids[closest].y-y); dx = maxSpeed * deltaX * (deltaX*deltaX)/((deltaX*deltaX)+(deltaY*deltaY)); dy = maxSpeed * deltaY * (deltaY*deltaY)/((deltaX*deltaX)+(deltaY*deltaY)); } targetAphid = closest; } void userMove(){ maxSpeed = 20; int adjustMouseX = mouseX; if(adjustMouseX > boardWidth) adjustMouseX = boardWidth; // avoids ladybug wrapping right dx=0.3*(adjustMouseX-x); dy=0.3*(mouseY-y); } void randMove(){ maxSpeed = 10; dx += random(-0.3,0.3); dy += random(-0.3,0.3); } void eat(){ float dist; for(int i = 0; i < maxAphids;i++){ if(aphids[i] !=null){ dist = ((aphids[i].x-x)*(aphids[i].x-x)+(aphids[i].y-y)*(aphids[i].y-y)); if(sqrt(dist)<(radius*.6)){ aphids[i] = null; // erase old aphid score++; aphidCaptureCount++; } } } } float get_radius(){ return radius; } void displaylady (){ if(dy == 0.0) dy = 0.0001; float angle = atan(dx/dy); if(dy<0) angle=angle+PI; stroke(0,0,0); fill(255,0,0); if(ladybugBehavior == 4){ fill(targetColor); } ellipse(x,y,radius,radius); line(x+(radius-1)/2*sin(angle),y+(radius-1)/2*cos(angle),x-(radius-1)/2*sin(angle),y-(radius-1)/2*cos(angle)); fill(0,0,0); ellipse(x+(radius*0.5)*sin(angle),y+(radius*0.5)*cos(angle),radius*.25,radius*.25); ellipse(x+(radius)/4*sin(angle+PI/3),y+(radius)/4*cos(angle+PI/3),radius/5,radius/5); ellipse(x+(radius)/4*sin(angle-PI/3),y+(radius)/4*cos(angle-PI/3),radius/5,radius/5); ellipse(x+(radius)/4*sin(angle+2*PI/3),y+(radius)/4*cos(angle+2*PI/3),radius/5,radius/5); ellipse(x+(radius)/4*sin(angle-2*PI/3),y+(radius)/4*cos(angle-2*PI/3),radius/5,radius/5); // stroke(255,255,255); // line(x,y,x + 400*sin(angle-PI/4),y + 400*cos(angle-PI/4)); // line(x,y,x + 400*sin(angle+PI/4),y + 400*cos(angle+PI/4)); } } //--------------------------------------------------- void addLeaves(color baseC){ float x,y,r1,r2; int c1; color c; leavesPG.beginDraw(); leavesPG.stroke(baseC); leavesPG.fill(baseC); leavesPG.rect(0,0,boardWidth,height); for(int i =0; i < numLeaves; i++){ x = random(-10,boardWidth); y = random(-10,height); r1 = random(50,100); r2 = random(50,100); // c = color(int(random(0,50)),int(random(180,220)),int(random(0,50))); //c1 = 40; // int(random(20,80)); c = color(red(baseC)+int(random(-20,20)),green(baseC)+int(random(-20,20)),blue(baseC)+int(random(-20,20))); leavesPG.stroke(c); leavesPG.fill(c); leavesPG.ellipse(x,y,r1,r2); } leavesPG.endDraw(); }