Created
February 14, 2014 00:16
-
-
Save tprynn/8986754 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ISTA 303 Assignment 1 | |
* Tanner Prynn | |
* communities.pde | |
* Implements a signal-passing automata based on a random graph. | |
* Some notes: | |
* - Nodes are connected according to their relative distances. | |
* - Communication between nodes in the same community is shown in green, | |
* communication between different communities is shown in red. | |
* - Nodes are more likely to communicate within their own communities. | |
* - Messages spread outward from their origination point. | |
* - Larger Nodes are more likely to communicate (based on Perlin noise) | |
* - Inactive nodes are transparent, active nodes are opaque | |
*/ | |
import java.util.List; | |
import java.util.ArrayList; | |
import java.util.Set; | |
import java.util.HashSet; | |
import java.util.HashMap; | |
// Variables controlling the creation of the graph | |
static final int CLUSTERS = 12; | |
static final int NODES_PER_CLUSTER = 70; | |
static final int COMMUNITY_RADIUS = 100; | |
// Variables controlling the behavior of the message passing | |
static final float NEW_MESSAGE_RATE = 0.1; | |
static final float DISTANCE_RATIO_INNER = 0.25; | |
static final float DISTANCE_RATIO_OUTER = 0.15; | |
static final int FRAME_RATE = 5; | |
// Map from community centers to a list of their child nodes | |
HashMap<Node, ArrayList<Node>> centers; | |
// Display variables | |
static final int WIDTH = 500; | |
static final int HEIGHT = 500; | |
static final float OPACITY = 200; | |
// Debug variables | |
static final boolean DEBUG_DRAW_CONNECTIONS = false; | |
void setup() { | |
frameRate(FRAME_RATE); | |
smooth(); | |
size(WIDTH, HEIGHT); | |
background(0); | |
centers = new HashMap<Node, ArrayList<Node>>(); | |
for (int i = 0; i < CLUSTERS; i++) { | |
float x = random(width); | |
float y = random(height); | |
color col = color(random(255),random(255),random(255)); | |
Node c = new Node(x, y, col); | |
centers.put(c, new ArrayList<Node>()); | |
for (int j = 0; j < NODES_PER_CLUSTER; j++) { | |
float theta = random((float)(2*Math.PI)); | |
float r = random(COMMUNITY_RADIUS); | |
float x1 = x + r*cos(theta); | |
float y1 = y + r*sin(theta); | |
centers.get(c).add(new Node(x1, y1, noise(x1, y1), c)); | |
} | |
} | |
// Connect the nodes of the graph based on distance | |
for (Node center : centers.keySet()) { | |
for (Node c1 : centers.get(center)) { | |
// Connect nodes within the community | |
for (Node c2 : centers.get(center)) { | |
if(c1.equals(c2)) continue; | |
if(dist(c1.x, c1.y, c2.x, c2.y) < (COMMUNITY_RADIUS*DISTANCE_RATIO_INNER)) { | |
c1.addNeighbor(c2); | |
} | |
} | |
// Connect to nodes outside the community | |
for (Node otherCenter : centers.keySet()) { | |
if(center.equals(otherCenter)) continue; | |
for(Node c2 : centers.get(otherCenter)) { | |
if(dist(c1.x, c1.y, c2.x, c2.y) < (COMMUNITY_RADIUS*DISTANCE_RATIO_OUTER)) { | |
c1.addNeighbor(c2); | |
} | |
} | |
} | |
} | |
} | |
} | |
void draw() { | |
if(DEBUG_DRAW_CONNECTIONS) { | |
debug_drawConnections(); | |
noLoop(); | |
return; | |
} | |
background(255); | |
// Draw the lines connecting nodes in the graph | |
stroke(0); | |
for (Node center : centers.keySet()) { | |
for (Node c1 : centers.get(center)) { | |
for (Node c2 : c1.neighbors) { | |
line(c1.x, c1.y, c2.x, c2.y); | |
} | |
} | |
} | |
// Draw the nodes and pass messages between them | |
noStroke(); | |
for(Node center : centers.keySet()) { | |
for(Node c : centers.get(center)) { | |
if(c.active()) { | |
c.message_out(); | |
fill(center.c); | |
c.draw(); | |
} | |
else { | |
fill(center.c, OPACITY); | |
c.draw(); | |
} | |
} | |
if(random(1) < NEW_MESSAGE_RATE) { | |
ArrayList<Node> Nodes = centers.get(center); | |
Nodes.get(int(random(Nodes.size()))).message_in(); | |
} | |
} | |
} | |
class Node { | |
private static final int RETRANSMISSION_DELAY = 10; | |
private static final int ACTIVE_TRANSMISSION_PERIOD = 30; | |
private static final int REFRACTORY_PERIOD = 90; | |
private static final float TRANSMISSION_PROB_INSIDER = 0.5; | |
private static final float TRANSMISSION_PROB_OUTSIDER = 0.3; | |
private static final int SCALE = 30; | |
public Set<Node> neighbors; | |
private Node parent; | |
public float x; | |
public float y; | |
public float n; | |
public color c; | |
private int lastFrameActivated = | |
-(RETRANSMISSION_DELAY+ACTIVE_TRANSMISSION_PERIOD+REFRACTORY_PERIOD); | |
/* Default Node | |
* Has an x,y location, Perlin noise value, and parent Node | |
*/ | |
public Node(float x, float y, float n, Node parent) { | |
this.x = x; | |
this.y = y; | |
this.n = n; | |
this.parent = parent; | |
neighbors = new HashSet<Node>(); | |
} | |
/* Invisible Parent Node | |
* Center of each community has an x,y location and a color | |
*/ | |
public Node(float x, float y, color c) { | |
this.x = x; | |
this.y = y; | |
this.c = c; | |
} | |
public void addNeighbor(Node other) { | |
neighbors.add(other); | |
other.neighbors.add(this); | |
} | |
/* Communicate a message to this cell */ | |
public void message_in() { | |
if(lastFrameActivated + | |
RETRANSMISSION_DELAY + | |
ACTIVE_TRANSMISSION_PERIOD + | |
REFRACTORY_PERIOD | |
< frameCount) { | |
lastFrameActivated = frameCount; | |
} | |
} | |
/* Communicate a message from this cell to its neighbors */ | |
public void message_out() { | |
for(Node neighbor : neighbors) { | |
if(parent.equals(neighbor.parent)) { | |
if(n*random(1) < TRANSMISSION_PROB_INSIDER) { | |
neighbor.message_in(); | |
stroke(0,255,0); | |
line(x, y, neighbor.x, neighbor.y); | |
noStroke(); | |
} | |
} | |
else if(n*random(1) < TRANSMISSION_PROB_OUTSIDER) { | |
neighbor.message_in(); | |
stroke(255,0,0); | |
line(x, y, neighbor.x, neighbor.y); | |
noStroke(); | |
} | |
} | |
} | |
/* Return true if this cell is actively communicating */ | |
public boolean active() { | |
int state = frameCount - lastFrameActivated; | |
return state < (ACTIVE_TRANSMISSION_PERIOD + RETRANSMISSION_DELAY) | |
&& state > RETRANSMISSION_DELAY; | |
} | |
public void draw() { | |
ellipse(x, y, n*SCALE, n*SCALE); | |
} | |
} | |
/* Debugging method that only shows the graph with no activity | |
* Set DEBUG_DRAW_CONNECTIONS to true to activate | |
*/ | |
void debug_drawConnections() { | |
background(255); | |
noStroke(); | |
for (Node center : centers.keySet()) { | |
fill(center.c, 200); | |
for (Node c : centers.get(center)) { | |
c.draw(); | |
} | |
} | |
stroke(0); | |
for (Node center : centers.keySet()) { | |
for (Node c1 : centers.get(center)) { | |
for (Node c2 : c1.neighbors) { | |
line(c1.x, c1.y, c2.x, c2.y); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment