Created
January 1, 2021 20:36
-
-
Save elbosso/2b1e525d116ba0f78356d08608fa9eab to your computer and use it in GitHub Desktop.
Generator for tilings using the 13 example tiles from the wikipedia article https://de.wikipedia.org/wiki/Wang-Parkettierung
This file contains hidden or 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
/* | |
* Copyright (c) 2021. | |
* | |
* Juergen Key. Alle Rechte vorbehalten. | |
* | |
* Weiterverbreitung und Verwendung in nichtkompilierter oder kompilierter Form, | |
* mit oder ohne Veraenderung, sind unter den folgenden Bedingungen zulaessig: | |
* | |
* 1. Weiterverbreitete nichtkompilierte Exemplare muessen das obige Copyright, | |
* die Liste der Bedingungen und den folgenden Haftungsausschluss im Quelltext | |
* enthalten. | |
* 2. Weiterverbreitete kompilierte Exemplare muessen das obige Copyright, | |
* die Liste der Bedingungen und den folgenden Haftungsausschluss in der | |
* Dokumentation und/oder anderen Materialien, die mit dem Exemplar verbreitet | |
* werden, enthalten. | |
* 3. Weder der Name des Autors noch die Namen der Beitragsleistenden | |
* duerfen zum Kennzeichnen oder Bewerben von Produkten, die von dieser Software | |
* abgeleitet wurden, ohne spezielle vorherige schriftliche Genehmigung verwendet | |
* werden. | |
* | |
* DIESE SOFTWARE WIRD VOM AUTOR UND DEN BEITRAGSLEISTENDEN OHNE | |
* JEGLICHE SPEZIELLE ODER IMPLIZIERTE GARANTIEN ZUR VERFUEGUNG GESTELLT, DIE | |
* UNTER ANDEREM EINSCHLIESSEN: DIE IMPLIZIERTE GARANTIE DER VERWENDBARKEIT DER | |
* SOFTWARE FUER EINEN BESTIMMTEN ZWECK. AUF KEINEN FALL IST DER AUTOR | |
* ODER DIE BEITRAGSLEISTENDEN FUER IRGENDWELCHE DIREKTEN, INDIREKTEN, | |
* ZUFAELLIGEN, SPEZIELLEN, BEISPIELHAFTEN ODER FOLGENDEN SCHAEDEN (UNTER ANDEREM | |
* VERSCHAFFEN VON ERSATZGUETERN ODER -DIENSTLEISTUNGEN; EINSCHRAENKUNG DER | |
* NUTZUNGSFAEHIGKEIT; VERLUST VON NUTZUNGSFAEHIGKEIT; DATEN; PROFIT ODER | |
* GESCHAEFTSUNTERBRECHUNG), WIE AUCH IMMER VERURSACHT UND UNTER WELCHER | |
* VERPFLICHTUNG AUCH IMMER, OB IN VERTRAG, STRIKTER VERPFLICHTUNG ODER | |
* UNERLAUBTE HANDLUNG (INKLUSIVE FAHRLAESSIGKEIT) VERANTWORTLICH, AUF WELCHEM | |
* WEG SIE AUCH IMMER DURCH DIE BENUTZUNG DIESER SOFTWARE ENTSTANDEN SIND, SOGAR, | |
* WENN SIE AUF DIE MOEGLICHKEIT EINES SOLCHEN SCHADENS HINGEWIESEN WORDEN SIND. | |
* | |
*/ | |
//https://de.wikipedia.org/wiki/Wang-Parkettierung | |
//This is brute-forcing it - therefore sometimes the program does not find a solution and | |
//I added safety measures against endless loops because that would increase the universes | |
//entropy hastening its heat death and nobody would want that. | |
//Unchanged, it tries to create 10 tilings. | |
package de.elbosso.scratch.algorithms.graphics; | |
import java.awt.*; | |
import java.awt.geom.AffineTransform; | |
import java.awt.image.BufferedImage; | |
import java.io.IOException; | |
public enum WangDomino | |
{ | |
A(Color.GREEN, Color.GREEN, Color.BLUE, Color.RED), | |
B(java.awt.Color.GREEN,java.awt.Color.BLUE,java.awt.Color.GREEN,java.awt.Color.RED), | |
C(java.awt.Color.GREEN,java.awt.Color.BLUE,java.awt.Color.BLUE,java.awt.Color.GREEN), | |
D(java.awt.Color.RED,java.awt.Color.RED,java.awt.Color.GREEN,java.awt.Color.GREEN), | |
E(java.awt.Color.RED,java.awt.Color.RED,java.awt.Color.BLUE,java.awt.Color.BLUE), | |
F(java.awt.Color.RED,java.awt.Color.GREEN,java.awt.Color.GREEN,java.awt.Color.BLUE), | |
G(Color.YELLOW,java.awt.Color.YELLOW,java.awt.Color.RED,java.awt.Color.YELLOW), | |
H(java.awt.Color.BLUE,java.awt.Color.YELLOW,java.awt.Color.GREEN,java.awt.Color.YELLOW), | |
I(java.awt.Color.GREEN, Color.GRAY,java.awt.Color.RED,java.awt.Color.YELLOW), | |
J(java.awt.Color.GREEN,java.awt.Color.GRAY,java.awt.Color.YELLOW,java.awt.Color.YELLOW), | |
K(java.awt.Color.YELLOW,java.awt.Color.GRAY,java.awt.Color.RED,java.awt.Color.GRAY), | |
L(java.awt.Color.BLUE,java.awt.Color.GRAY,java.awt.Color.GREEN,java.awt.Color.GRAY), | |
M(java.awt.Color.GREEN,java.awt.Color.YELLOW,java.awt.Color.GREEN,java.awt.Color.GRAY); | |
private final static int NORTH=0; | |
private final static int EAST=1; | |
private final static int SOUTH=2; | |
private final static int WEST=3; | |
private final java.awt.Color[] colorsStartingAtNorthGoingClockwise=new java.awt.Color[4]; | |
WangDomino(Color north, Color east, Color south, Color west) | |
{ | |
colorsStartingAtNorthGoingClockwise[NORTH] = north; | |
colorsStartingAtNorthGoingClockwise[EAST] = east; | |
colorsStartingAtNorthGoingClockwise[SOUTH] = south; | |
colorsStartingAtNorthGoingClockwise[WEST] = west; | |
} | |
public java.awt.Color getNorth(int rotatedByQuadrants) | |
{ | |
return(colorsStartingAtNorthGoingClockwise[(NORTH+rotatedByQuadrants)%colorsStartingAtNorthGoingClockwise.length]); | |
} | |
public java.awt.Color getEast(int rotatedByQuadrants) | |
{ | |
return(colorsStartingAtNorthGoingClockwise[(EAST+rotatedByQuadrants)%colorsStartingAtNorthGoingClockwise.length]); | |
} | |
public java.awt.Color getSouth(int rotatedByQuadrants) | |
{ | |
return(colorsStartingAtNorthGoingClockwise[(SOUTH+rotatedByQuadrants)%colorsStartingAtNorthGoingClockwise.length]); | |
} | |
public java.awt.Color getWest(int rotatedByQuadrants) | |
{ | |
return(colorsStartingAtNorthGoingClockwise[(WEST+rotatedByQuadrants)%colorsStartingAtNorthGoingClockwise.length]); | |
} | |
public java.awt.image.BufferedImage getRotatedImageWithSize(int size,int rotatedByQuadrants,java.awt.Color line) | |
{ | |
java.awt.image.BufferedImage bimg=new java.awt.image.BufferedImage(size,size, BufferedImage.TYPE_INT_ARGB); | |
java.awt.Graphics2D g2=bimg.createGraphics(); | |
int middlex=size/2; | |
int middley=middlex; | |
g2.setTransform(AffineTransform.getQuadrantRotateInstance(-rotatedByQuadrants,middlex,middley)); | |
g2.setPaint(colorsStartingAtNorthGoingClockwise[NORTH]); | |
int[] xPoints=new int[4]; | |
int[] yPoints=new int[4]; | |
xPoints[0]=middlex; | |
yPoints[0]=middley; | |
xPoints[1]=size; | |
yPoints[1]=0; | |
xPoints[2]=0; | |
yPoints[2]=0; | |
xPoints[3]=middlex; | |
yPoints[3]=middley; | |
g2.fillPolygon(xPoints,yPoints,xPoints.length); | |
if(line!=null) | |
{ | |
g2.setPaint(line); | |
g2.drawPolygon(xPoints, yPoints, xPoints.length); | |
} | |
g2.setPaint(colorsStartingAtNorthGoingClockwise[EAST]); | |
xPoints[2]=size; | |
yPoints[2]=size; | |
g2.fillPolygon(xPoints,yPoints,xPoints.length); | |
if(line!=null) | |
{ | |
g2.setPaint(line); | |
g2.drawPolygon(xPoints, yPoints, xPoints.length); | |
} | |
g2.setPaint(colorsStartingAtNorthGoingClockwise[SOUTH]); | |
xPoints[1]=0; | |
yPoints[1]=size; | |
g2.fillPolygon(xPoints,yPoints,xPoints.length); | |
if(line!=null) | |
{ | |
g2.setPaint(line); | |
g2.drawPolygon(xPoints, yPoints, xPoints.length); | |
} | |
g2.setPaint(colorsStartingAtNorthGoingClockwise[WEST]); | |
xPoints[2]=0; | |
yPoints[2]=0; | |
g2.fillPolygon(xPoints,yPoints,xPoints.length); | |
if(line!=null) | |
{ | |
g2.setPaint(line); | |
g2.drawPolygon(xPoints, yPoints, xPoints.length); | |
} | |
g2.dispose(); | |
return bimg; | |
} | |
public static WangDomino random(java.util.Random rand) | |
{ | |
return values()[rand.nextInt(values().length)]; | |
} | |
public static WangDomino[] randomizedValues() | |
{ | |
java.util.List<WangDomino> shuffled=java.util.Arrays.asList(values()); | |
java.util.Collections.shuffle(shuffled); | |
return shuffled.toArray(new WangDomino[0]); | |
} | |
static class Configuration | |
{ | |
private final int rotatedByQuadrants; | |
private final WangDomino wangDomino; | |
public Configuration(WangDomino wangDomino,int rotatedByQuadrants) | |
{ | |
this.rotatedByQuadrants = rotatedByQuadrants; | |
this.wangDomino = wangDomino; | |
} | |
public int getRotatedByQuadrants() | |
{ | |
return rotatedByQuadrants; | |
} | |
public WangDomino getWangDomino() | |
{ | |
return wangDomino; | |
} | |
public java.awt.Color getNorth() | |
{ | |
return wangDomino.getNorth(rotatedByQuadrants); | |
} | |
public java.awt.Color getEast() | |
{ | |
return wangDomino.getEast(rotatedByQuadrants); | |
} | |
public java.awt.Color getSouth() | |
{ | |
return wangDomino.getSouth(rotatedByQuadrants); | |
} | |
public java.awt.Color getWest() | |
{ | |
return wangDomino.getWest(rotatedByQuadrants); | |
} | |
public java.awt.image.BufferedImage getImageWithSize(int size,java.awt.Color line) | |
{ | |
return wangDomino.getRotatedImageWithSize(size,rotatedByQuadrants,line); | |
} | |
} | |
static class Grid | |
{ | |
private final java.awt.Dimension dim; | |
private final Configuration[] configurations; | |
public Grid(Dimension dim) | |
{ | |
this.dim = dim; | |
configurations=new Configuration[dim.width*dim.height]; | |
} | |
private int getTileIndex(int x, int y) { | |
int index=-1; | |
if (x >= dim.width || y >= dim.height || x < 0 || y < 0) | |
;//throw new IllegalArgumentException("Tile outside bounds: (" + x + ", " + y + ")"); | |
else | |
index=dim.width * y + x; | |
return index; | |
} | |
public Configuration get(int x, int y) | |
{ | |
Configuration rv=null; | |
int index=getTileIndex(x,y); | |
if(index>-1) | |
rv=configurations[index]; | |
return rv; | |
} | |
public void set(int x, int y, Configuration configuration) | |
{ | |
int index=getTileIndex(x,y); | |
if(index>-1) | |
configurations[index]=configuration; | |
} | |
int getWidth() | |
{ | |
return dim.width; | |
} | |
int getHeight() | |
{ | |
return dim.height; | |
} | |
} | |
public static void main(java.lang.String[] args) throws IOException | |
{ | |
int tilesize=128; | |
java.util.Random rand=new java.util.Random(System.currentTimeMillis()); | |
int loopCounter=0; | |
while(true) | |
{ | |
try | |
{ | |
Grid grid = new Grid(new java.awt.Dimension(35, 24)); | |
int expcouter=0; | |
for (int y = 0; y < grid.getHeight(); ++y) | |
{ | |
for (int x = 0; x < grid.getWidth(); ++x) | |
{ | |
Configuration configuration = new Configuration(WangDomino.random(rand), rand.nextInt(4)); | |
while(true) | |
{ | |
try | |
{ | |
grid.set(x, y, null); | |
if (x + 1 < grid.getWidth()) | |
grid.set(x + 1, y, null); | |
configuration = findMatchingTileConfiguration(grid, x, y, rand); | |
grid.set(x, y, configuration); | |
break; | |
} catch (IndexOutOfBoundsException exp) | |
{ | |
--y; | |
if(y<0) | |
{ | |
++y; | |
x-=2; | |
if(x<-1) | |
break; | |
} | |
++expcouter; | |
if(expcouter>10) | |
throw exp; | |
} | |
} | |
} | |
} | |
java.awt.image.BufferedImage bimg = new java.awt.image.BufferedImage(grid.getWidth() * tilesize, grid.getHeight() * tilesize, BufferedImage.TYPE_INT_ARGB); | |
java.awt.Graphics2D g2 = bimg.createGraphics(); | |
for (int y = 0; y < grid.getHeight(); ++y) | |
{ | |
for (int x = 0; x < grid.getWidth(); ++x) | |
{ | |
if(grid.get(x,y)!=null) | |
{ | |
g2.drawImage(grid.get(x, y).getImageWithSize(tilesize, Color.BLACK), x * tilesize, y * tilesize, null); | |
} | |
} | |
} | |
g2.dispose(); | |
java.io.File f = java.io.File.createTempFile("tiled_", ".png"); | |
javax.imageio.ImageIO.write(bimg, "png", f); | |
++loopCounter; | |
if (loopCounter > 10) | |
break; | |
} | |
catch (IndexOutOfBoundsException exp) | |
{ | |
System.err.println("tried and failed..."); | |
} | |
} | |
} | |
private static Configuration findMatchingTileConfiguration(Grid grid, int x, int y,java.util.Random rand) | |
{ | |
java.util.List<Configuration> candidates=new java.util.LinkedList(); | |
WangDomino[] randomized=WangDomino.randomizedValues(); | |
Configuration configuration=grid.get(x,y-1); | |
java.awt.Color north=configuration!=null?configuration.getSouth():null; | |
configuration=grid.get(x+1,y); | |
java.awt.Color east=configuration!=null?configuration.getWest():null; | |
configuration=grid.get(x,y+1); | |
java.awt.Color south=configuration!=null?configuration.getNorth():null; | |
configuration=grid.get(x-1,y); | |
java.awt.Color west=configuration!=null?configuration.getEast():null; | |
for(WangDomino wangDomino:randomized) | |
{ | |
for(int i=0;i<4;++i) | |
{ | |
Configuration sample=new Configuration(wangDomino,i); | |
if(((north==null)||(north.equals(sample.getNorth())))&& | |
((east==null)||(east.equals(sample.getEast())))&& | |
((south==null)||(south.equals(sample.getSouth())))&& | |
((west==null)||(west.equals(sample.getWest())))) | |
{ | |
candidates.add(sample); | |
} | |
} | |
} | |
java.util.Collections.shuffle(candidates); | |
return candidates.get(0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment