//
// Duncan Boehle
// Emulation of 13/9/65 - Nake
//
int minCols = 6;
int maxCols = 8;
int minRows = 8;
int maxRows = 12;
int minCircles = 4;
int maxCircles = 8;
int minRadius = 3;
int maxRadius = 50;
float vertProb = 0.25f;
float crossProb = 0.35f;
int sideSize = 550;
int sideBuffer = 8;
ArrayList heightRows;
// ArrayList of rows, which is length "rows", and each
// element is an ArrayList of length "cols"
// each element of this inner ArrayList is a Box
Box[][] boxes;
int numRows;
int numCols;
int[] colMinXs;
int[] rowStartYs;
ArrayList circles;
void setup() {
size(566, 566);
smooth();
stroke(0);
strokeWeight(1.5);
noFill();
drawNake();
}
public void drawNake() {
background(255);
heightRows = new ArrayList();
numRows = int(random(minRows, maxRows));
numCols = int(random(minCols, maxCols));
boxes = new Box[numRows][numCols];
colMinXs = makePosArray(numCols, sideBuffer, sideSize + sideBuffer, 1.0f, 3.0f);
rowStartYs = makePosArray(numRows, sideBuffer, sideSize + sideBuffer, 1.0f, 2.5f);
for (int y = 0; y <= numRows; y++) {
ArrayList row = new ArrayList();
int rowHeight = y < numRows ? rowStartYs[y] : (sideSize + sideBuffer);
row.add(rowHeight);
for (int x = 0; x 0 && y < numRows) {
rowHeight += int(random(-12, 12));
}
row.add(rowHeight);
}
heightRows.add(row);
}
rect(sideBuffer, sideBuffer, sideSize, sideSize);
for (int y = 0; y < numRows; y++) {
ArrayList topRowHeightRow = (ArrayList)heightRows.get(y);
ArrayList botRowHeightRow = (ArrayList)heightRows.get(y + 1);
for (int x = 0; x < numCols; x++) {
int minX = colMinXs[x];
int maxX = (x < numCols - 1) ? colMinXs[x + 1] : (sideSize + sideBuffer);
int ulY = (Integer)topRowHeightRow.get(x);
int urY = (Integer)topRowHeightRow.get(x + 1);
int blY = (Integer)botRowHeightRow.get(x);
int brY = (Integer)botRowHeightRow.get(x + 1);
line(minX, ulY, maxX, urY);
//line(minX, ulY, minX, blY);
//line(maxX, urY, maxX, brY);
line(minX, blY, maxX, brY);
float rand = random(0.0f, 1.0f);
int type = Box.TYPE_EMPTY;
if (rand < vertProb)
type = Box.TYPE_VERTICAL;
else if (rand 0) {
Box boxAbove = boxes[y - 1][x];
if (type == Box.TYPE_VERTICAL && boxAbove.type == Box.TYPE_VERTICAL) {
newBox = boxAbove;
}
}
if (newBox == null) {
newBox = new Box(type, int(random(1, 5)));
}
newBox.draw(minX, maxX, ulY, urY, blY, brY);
boxes[y][x] = newBox;
}
}
int numCircles = int(random(minCircles, maxCircles));
circles = new ArrayList();
for (int i = 0; i < numCircles; i++) {
int rad = int(random(minRadius, maxRadius));
int x = int(random(2 * sideBuffer + rad, sideSize - rad));
int y = int(random(2 * sideBuffer + rad, sideSize - rad));
Circle circle = new Circle(x, y, rad);
boolean intersects = false;
for (int c = 0; c < circles.size(); c++) {
Circle otherCircle = (Circle)circles.get(c);
if (circle.intersects(otherCircle)) {
intersects = true;
break;
}
}
if (!intersects) {
circles.add(circle);
ellipse(x, y, rad * 2, rad * 2);
}
}
}
public int[] makePosArray(int num, int minN, int maxN, float minRat, float maxRat) {
float[] ratioList = new float[num];
float totalRat = 0.0f;
for (int i = 0; i < num; i++) {
float ratio = random(minRat, maxRat);
ratioList[i] = ratio;
totalRat += ratio;
}
int curN = minN;
int[] pixelList = new int[num];
for (int i = 0; i < num; i++) {
pixelList[i] = curN;
float ratio = ratioList[i];
ratio /= totalRat;
curN += ratio * (maxN - minN);
}
return pixelList;
}
void draw() {
if (keyPressed) {
drawNake();
}
}
class Box {
public static final int TYPE_EMPTY = 0;
public static final int TYPE_VERTICAL = 1;
public static final int TYPE_CROSSED = 2;
public int type;
public int maxDegree;
public ArrayList topRow;
public ArrayList bottomRow;
public Box(int type, int maxDegree) {
this.type = type;
this.maxDegree = maxDegree;
topRow = new ArrayList();
bottomRow = new ArrayList();
switch (type) {
case TYPE_EMPTY:
break;
case TYPE_VERTICAL:
fillRow(topRow, 2, 16);
break;
case TYPE_CROSSED:
fillRow(topRow, 2, 16);
fillRow(bottomRow, 2, 16);
break;
default:
break;
}
}
public void draw(int minX, int maxX, int ulY, int urY, int blY, int brY) {
switch (type) {
case TYPE_EMPTY:
break;
case TYPE_VERTICAL:
// for each point along the line, draw a vertical line to the bottom
for (int i = 0; i < topRow.size(); i++) {
float n = (Float)topRow.get(i);
float x = lerp(minX, maxX, n);
float topY = lerp(ulY, urY, n);
float bottomY = lerp(blY, brY, n);
line(x, topY, x, bottomY);
}
break;
case TYPE_CROSSED:
// for each point along the top row, draw a random number of lines
// to points in the bottom row
for (int i = 0; i < topRow.size(); i++) {
float topN = (Float)topRow.get(i);
float topX = lerp(minX, maxX, topN);
float topY = lerp(ulY, urY, topN);
int outDegree = int(random(1, maxDegree));
for (int j = 0; j < outDegree; j++) {
int randIndex = int(random(0, bottomRow.size()));
float botN = (Float)bottomRow.get(randIndex);
float botX = lerp(minX, maxX, botN);
float botY = lerp(blY, brY, botN);
line(topX, topY, botX, botY);
}
}
break;
default:
break;
}
}
public void fillRow(ArrayList inList, int minEls, int maxEls) {
int numEls = (int)random(minEls, maxEls);
inList.clear();
for (int i = 0; i < numEls; i++) {
inList.add(random(0.0f, 1.0f));
}
return;
}
}
class Circle {
public int x;
public int y;
public int rad;
public Circle(int x, int y, int rad) {
this.x = x;
this.y = y;
this.rad = rad;
}
public boolean intersects(Circle other) {
int xdiff = other.x - x;
int ydiff = other.y - y;
float distance = sqrt(xdiff * xdiff + ydiff * ydiff);
return distance < (other.rad + rad);
}
} |