Permalink
Browse files

holy shit, wave function collapse works.

  • Loading branch information...
IJDykeman committed Mar 17, 2017
1 parent fa2f3bc commit 01bc61b6866a9d2a0c0db7eb87a3923c39f7f462
Showing with 425 additions and 37 deletions.
  1. +2 −34 ConstrainedMap.pde
  2. +87 −0 Map.pde
  3. +6 −0 TileLoc.pde
  4. +192 −0 TileProbabilityDistribution.pde
  5. +134 −0 WaveCollapseMap.pde
  6. +4 −3 wangTiles.pde
View
@@ -1,6 +1,4 @@
class ConstrainedMap extends Map {
ConstrainedMap(int imapWidth, int itileWidth) {
tilesImage = loadImage(FILENAME);
mapWidth = imapWidth;
@@ -23,8 +21,8 @@ class ConstrainedMap extends Map {
void update() {
int numIterations = 1;
if (timeSinceMapBuild>10) {
numIterations = 20;
if (timeSinceMapBuild>7) {
numIterations = 5;
}
// if the simulation has been running a long time,
// up the amount of modification done per frame.
@@ -93,35 +91,5 @@ class ConstrainedMap extends Map {
}
ArrayList<Tile> validTilesAt(int tileX, int tileY) {
ArrayList<Tile> result = new ArrayList<Tile>();
for (Tile test : wangTiles) {
if (isValidPlacement(test, tileX, tileY)) {
result.add(test);
}
}
return result;
}
boolean isValidPlacement(Tile tile, int tileX, int tileY) {
boolean result =
isValidNeighbor(tile, tileX, tileY, tileX+1, tileY) &&
isValidNeighbor(tile, tileX, tileY, tileX-1, tileY) &&
isValidNeighbor(tile, tileX, tileY, tileX, tileY+1) &&
isValidNeighbor(tile, tileX, tileY, tileX, tileY-1);
return result;
}
boolean isValidNeighbor(Tile tile, int tileX, int tileY, int neighborX, int neighborY) {
if (neighborX>=mapWidth || neighborY>=mapWidth || neighborX<0 || neighborY<0) {
return true;
} else {
Directions direction = getDirectionFromDelta(neighborX-tileX, neighborY-tileY);
return tile.isValidNeighbor(tiles[neighborX][neighborY], direction);
}
}
}
View
87 Map.pde
@@ -1,3 +1,5 @@
class Map {
Tile[][] tiles;
int tileWidth;
@@ -57,5 +59,90 @@ class Map {
Collections.shuffle(tileLocs);
return tileLocs;
}
ArrayList<Tile> validTilesAt(int tileX, int tileY) {
ArrayList<Tile> result = new ArrayList<Tile>();
for (Tile test : wangTiles) {
if (isValidPlacement(test, tileX, tileY)) {
result.add(test);
}
}
return result;
}
boolean tileListContains(ArrayList<TileLoc> l, TileLoc t){
for(TileLoc o : l){
if(o.x == t.x && o.y == t.y){
return true;
}
}
return false;
}
ArrayList<TileLoc> BfsFrom(TileLoc startLoc){
// println("up");
ArrayList<TileLoc> queue = new ArrayList<TileLoc>();
ArrayList<TileLoc> visited = new ArrayList<TileLoc>();
// HashSet<TileLoc> visited = new HashSet<TileLoc>();
queue.add(startLoc);
while (queue.size() > 0){
TileLoc current = queue.remove(0);
visited.add(current);
queue.remove(current);
for (TileLoc neighbor : getNeighbors(current)){
if (! tileListContains(visited, neighbor)){
queue.add(neighbor);
}
}
}
println("here");
return visited;
}
ArrayList<TileLoc> getNeighbors(TileLoc from){
ArrayList<TileLoc> results = new ArrayList<TileLoc>();
if (from.x < mapWidth - 1){
results.add(new TileLoc(from.x + 1, from.y));
}
if (from.x >= 1){
results.add(new TileLoc(from.x - 1, from.y));
}
if (from.y < mapWidth - 1){
results.add(new TileLoc(from.x, from.y + 1));
}
if (from.y >= 1){
results.add(new TileLoc(from.x, from.y - 1));
}
return results;
}
boolean isValidPlacement(Tile tile, int tileX, int tileY) {
boolean result =
isValidNeighbor(tile, tileX, tileY, tileX+1, tileY) &&
isValidNeighbor(tile, tileX, tileY, tileX-1, tileY) &&
isValidNeighbor(tile, tileX, tileY, tileX, tileY+1) &&
isValidNeighbor(tile, tileX, tileY, tileX, tileY-1);
return result;
}
boolean isValidNeighbor(Tile tile, int tileX, int tileY, int neighborX, int neighborY) {
if (neighborX>=mapWidth || neighborY>=mapWidth || neighborX<0 || neighborY<0) {
return true;
} else {
Directions direction = getDirectionFromDelta(neighborX-tileX, neighborY-tileY);
return tile.isValidNeighbor(tiles[neighborX][neighborY], direction);
}
}
boolean isValidNeighbor(Tile tile, int tileX, int tileY, Tile neighbor, int neighborX, int neighborY) {
if (neighborX>=mapWidth || neighborY>=mapWidth || neighborX<0 || neighborY<0) {
return true;
} else {
Directions direction = getDirectionFromDelta(neighborX-tileX, neighborY-tileY);
return tile.isValidNeighbor(neighbor, direction);
}
}
}
View
@@ -5,4 +5,10 @@ class TileLoc{
x= nx;
y = ny;
}
public boolean equals(Object o){
int ox = ((TileLoc)o).x;
int oy = ((TileLoc)o).y;
return x == ox && y == oy;
}
}
@@ -0,0 +1,192 @@
class TileProbabilityDistribution{
Random rand = new Random();
HashMap<Tile, Double> logits = new HashMap<Tile, Double>();
TileProbabilityDistribution(ArrayList<Tile> tiles, ArrayList<Double> probabilities){
for (int i = 0; i < tiles.size(); i++){
logits.put(tiles.get(i), probabilities.get(i));
}
}
TileProbabilityDistribution(ArrayList<Tile> tiles, double uniform){
for (int i = 0; i < tiles.size(); i++){
logits.put(tiles.get(i), uniform);
}
}
TileProbabilityDistribution(HashMap<Tile, Double> _logits){
logits = _logits;
}
void printDist(){
println("Distribution:");
for (Tile tile : logits.keySet()){
print(" ");
println(logits.get(tile));
}
}
float getTotalProbability(){
float sum = 0;
for (Tile tile : logits.keySet()){
sum += logits.get(tile);
}
return sum;
}
Tile highestProbabilityTile(){
double highest = -1;
Tile best = null;
for (Tile tile : logits.keySet()){
double p = logits.get(tile);
if (p > highest){
highest = p;
best = tile;
}
}
return best;
}
Tile weightedTileSelect(){
double r = rand.nextFloat();
assert(r <= 1);
for (Tile tile : logits.keySet()){
double p = logits.get(tile);
r-=p;
if (r <= 0){
return tile;
}
}
return null;
}
void normalize(){
float sum = getTotalProbability();
assert(sum > 0);
for (Tile tile : logits.keySet()){
logits.put(tile, logits.get(tile) / sum);
}
}
double getProbability(Tile tile){
// println(tile);
// println(logits);
assert(logits != null);
assert(tile != null);
return logits.get(tile);
}
double setProbability(Tile tile, double val){
return logits.put(tile, val);
}
double entropy(){
double sum = 0;
for (Tile tile : logits.keySet()){
if(logits.get(tile) != 0){
sum += logits.get(tile)*Math.log(logits.get(tile));
}
}
return -sum;
}
}
TileProbabilityDistribution multiply(TileProbabilityDistribution a, TileProbabilityDistribution b){
HashMap<Tile, Double> result = new HashMap<Tile, Double>();
for (Tile tile : a.logits.keySet()){
result.put(tile, a.getProbability(tile) * b.getProbability(tile));
}
return new TileProbabilityDistribution(result);
}
TileProbabilityDistribution add(TileProbabilityDistribution a, TileProbabilityDistribution b){
HashMap<Tile, Double> result = new HashMap<Tile, Double>();
for (Tile tile : a.logits.keySet()){
result.put(tile, a.getProbability(tile) + b.getProbability(tile));
}
return new TileProbabilityDistribution(result);
}
class TileProbabilitySphere extends Map{
TileProbabilityDistribution[][] tileDistributions;
Tile centralTile;
TileProbabilitySphere(Tile _centralTile, ArrayList<Tile> _wangTiles){
wangTiles = _wangTiles;
mapWidth = 9;
tileDistributions = new TileProbabilityDistribution[mapWidth][mapWidth];
centralTile = _centralTile;
// tiles[tileWidth/2][tileWidth/2] = centralTile;
for (TileLoc cur : BfsFrom(new TileLoc(mapWidth/2,mapWidth/2))){
tileDistributions[cur.x][cur.y] = calcDistAt(cur);
// print(cur.x); print(" "); println(cur.y);
// tileDistributions[cur.x][cur.y].printDist();
// delay(400);
}
}
TileProbabilityDistribution getDistributionAt(TileLoc loc){
loc.x = loc.x - mapWidth / 2;
loc.y = loc.y - mapWidth / 2;
if (loc.x < mapWidth && loc.y < mapWidth && loc.x >= 0 && loc.y >=0 ){
return tileDistributions[loc.x][loc.y];
}
else{
TileProbabilityDistribution result = new TileProbabilityDistribution(wangTiles, 1d);
result.normalize();
return result;
}
}
TileProbabilityDistribution calcDistAt(TileLoc loc){
if(loc.x == mapWidth/2 && loc.y == mapWidth/2){
TileProbabilityDistribution result = new TileProbabilityDistribution(wangTiles, 0d);
result.setProbability(centralTile, 1d);
return result;
}
TileProbabilityDistribution result = new TileProbabilityDistribution(wangTiles, 0.000001d);
for (TileLoc neighbor : getNeighbors(loc)){
if(tileDistributions[neighbor.x][neighbor.y] != null){
TileProbabilityDistribution dist = transitionDistribution(neighbor, loc);
result = add(result, dist);
}
else{
// result = add(result, new TileProbabilityDistribution(wangTiles, 1d));
}
}
result.normalize();
return result;
}
TileProbabilityDistribution transitionDistribution(TileLoc from, TileLoc to){
// println("getting trans dist...");
ArrayList<Double> probabilities = new ArrayList<Double>();
for (Tile tileTo : wangTiles){
double p = 0d;
for (Tile tileFrom : wangTiles){
double valid = isValidNeighbor(tileTo, to.x, to.y, tileFrom, from.x, from.y) ? 1d : 0d;
p += tileDistributions[from.x][from.y].getProbability(tileFrom) * valid;
}
probabilities.add(p);
}
// println("got trans dist");
return new TileProbabilityDistribution(wangTiles, probabilities);
}
}
Oops, something went wrong.

0 comments on commit 01bc61b

Please sign in to comment.