Java - Recursive Path
I start from a 2x3 closed path.
I scan each cell of the path and divide it into a new 3x3 sub-path. I try each time to choose the 3x3 sub-path that "looks like" the original picture.
I repeat the above process 4 times.
Here is the code:
package divide;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import snake.Image;
public class Divide {
private final static int MULT = 3;
private final static int ITERATIONS = 4;
public static void main(String[] args) throws IOException {
BufferedImage src = ImageIO.read(Image.class.getClassLoader().getResourceAsStream("input.png"));
BufferedImage dest = new BufferedImage(src.getWidth() * MULT, src.getHeight() * MULT, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < src.getHeight() * MULT; y++) {
for (int x = 0; x < src.getWidth() * MULT; x++) {
dest.getRaster().setPixel(x, y, new int [] {255, 255, 255});
}
}
List<String> tab = new ArrayList<String>();
tab.add("rg");
tab.add("||");
tab.add("LJ");
for (int k = 1; k <= ITERATIONS; k++) {
boolean choose = k>=ITERATIONS-1;
// multiply size by 3
tab = iterate(src, tab, choose);
// fill in the white space - if needed
expand(src, tab, " r", " L", "r-", "L-", choose);
expand(src, tab, "g ", "J ", "-g", "-J", choose);
expand(src, tab, "LJ", " ", "||", "LJ", choose);
expand(src, tab, " ", "rg", "rg", "||", choose);
expand(src, tab, "L-J", " ", "| |", "L-J", choose);
expand(src, tab, " ", "r-g", "r-g", "| |", choose);
expand(src, tab, "| |", "| |", "Lg|", "rJ|", choose);
expand(src, tab, "--", " ", "gr", "LJ", choose);
expand(src, tab, " ", "--", "rg", "JL", choose);
expand(src, tab, "| ", "| ", "Lg", "rJ", choose);
expand(src, tab, " |", " |", "rJ", "Lg", choose);
for (String s : tab) {
System.out.println(s);
}
System.out.println();
}
for (int j = 0; j < tab.size(); j++) {
String line = tab.get(j);
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
int xleft = i * dest.getWidth() / line.length();
int xright = (i+1) * dest.getWidth() / line.length();
int ytop = j * dest.getHeight() / tab.size();
int ybottom = (j+1) * dest.getHeight() / tab.size();
int x = (xleft + xright) / 2;
int y = (ytop + ybottom) / 2;
if (c == '|') {
drawLine(dest, x, ytop, x, ybottom);
}
if (c == '-') {
drawLine(dest, xleft, y, xright, y);
}
if (c == 'L') {
drawLine(dest, x, y, xright, y);
drawLine(dest, x, y, x, ytop);
}
if (c == 'J') {
drawLine(dest, x, y, xleft, y);
drawLine(dest, x, y, x, ytop);
}
if (c == 'r') {
drawLine(dest, x, y, xright, y);
drawLine(dest, x, y, x, ybottom);
}
if (c == 'g') {
drawLine(dest, x, y, xleft, y);
drawLine(dest, x, y, x, ybottom);
}
}
}
ImageIO.write(dest, "png", new File("output.png"));
}
private static void drawLine(BufferedImage dest, int x1, int y1, int x2, int y2) {
int dist = Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
for (int i = 0; i <= dist; i++) {
int x = (x1*(dist - i) + x2 * i) / dist;
int y = (y1*(dist - i) + y2 * i) / dist;
dest.getRaster().setPixel(x, y, new int [] {0, 0, 0});
}
}
private static void expand(BufferedImage src, List<String> tab, String p1, String p2, String r1, String r2, boolean choose) {
for (int k = 0; k < (choose ? 2 : 1); k++) {
while (true) {
boolean again = false;
for (int j = 0; j < tab.size() - 1; j++) {
String line1 = tab.get(j);
String line2 = tab.get(j+1);
int baseScore = evaluateLine(src, j, tab.size(), line1) + evaluateLine(src, j+1, tab.size(), line2);
for (int i = 0; i <= line1.length() - p1.length(); i++) {
if (line1.substring(i, i + p1.length()).equals(p1)
&& line2.substring(i, i + p2.length()).equals(p2)) {
String nline1 = line1.substring(0, i) + r1 + line1.substring(i + p1.length());
String nline2 = line2.substring(0, i) + r2 + line2.substring(i + p2.length());
int nScore = evaluateLine(src, j, tab.size(), nline1) + evaluateLine(src, j+1, tab.size(), nline2);
if (!choose || nScore > baseScore) {
tab.set(j, nline1);
tab.set(j+1, nline2);
again = true;
break;
}
}
}
if (again) break;
}
if (!again) break;
}
String tmp1 = r1;
String tmp2 = r2;
r1 = p1;
r2 = p2;
p1 = tmp1;
p2 = tmp2;
}
}
private static int evaluateLine(BufferedImage src, int j, int tabSize, String line) {
int [] color = {0, 0, 0};
int score = 0;
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
int x = i*src.getWidth() / line.length();
int y = j*src.getHeight() / tabSize;
src.getRaster().getPixel(x, y, color);
if (c == ' ' && color[0] >= 128) score++;
if (c != ' ' && color[0] < 128) score++;
}
return score;
}
private static List<String> iterate(BufferedImage src, List<String> tab, boolean choose) {
int [] color = {0, 0, 0};
List<String> tab2 = new ArrayList<String>();
for (int j = 0; j < tab.size(); j++) {
String line = tab.get(j);
String l1 = "", l2 = "", l3 = "";
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
List<String []> candidates = replace(c);
String [] choice = null;
if (choose) {
int best = 0;
for (String [] candidate : candidates) {
int bright1 = 0;
int bright2 = 0;
for (int j1 = 0; j1<3; j1++) {
int y = j*3+j1;
for (int i1 = 0; i1<3; i1++) {
int x = i*3+i1;
char c2 = candidate[j1].charAt(i1);
src.getRaster().getPixel(x*src.getWidth()/(line.length()*3), y*src.getHeight()/(tab.size()*3), color);
if (c2 != ' ') bright1++;
if (color[0] > 128) bright2++;
}
}
int score = Math.abs(bright1 - bright2);
if (choice == null || score > best) {
best = score;
choice = candidate;
}
}
} else {
choice = candidates.get(0);
}
//String [] r = candidates.get(rand.nextInt(candidates.size()));
String [] r = choice;
l1 += r[0];
l2 += r[1];
l3 += r[2];
}
tab2.add(l1);
tab2.add(l2);
tab2.add(l3);
}
return tab2;
}
private static List<String []> replace(char c) {
if (c == 'r') {
return Arrays.asList(
new String[] {
"r-g",
"| L",
"Lg "},
new String[] {
" ",
" r-",
" | "},
new String[] {
" ",
"r--",
"Lg "},
new String[] {
" rg",
" |L",
" | "},
new String[] {
" ",
" r",
" rJ"});
} else if (c == 'g') {
return Arrays.asList(
new String[] {
"r-g",
"J |",
" rJ"},
new String[] {
" ",
"-g ",
" | "},
new String[] {
" ",
"--g",
" rJ"},
new String[] {
"rg ",
"J| ",
" | "},
new String[] {
" ",
"g ",
"Lg "});
} else if (c == 'L') {
return Arrays.asList(
new String[] {
"rJ ",
"| r",
"L-J"},
new String[] {
" | ",
" L-",
" "},
new String[] {
"rJ ",
"L--",
" "},
new String[] {
" | ",
" |r",
" LJ"},
new String[] {
" Lg",
" L",
" "});
} else if (c == 'J') {
return Arrays.asList(
new String[] {
" Lg",
"g |",
"L-J"},
new String[] {
" | ",
"-J ",
" "},
new String[] {
" Lg",
"--J",
" "},
new String[] {
" | ",
"g| ",
"LJ "},
new String[] {
"rJ ",
"J ",
" "});
} else if (c == '-') {
return Arrays.asList(
new String[] {
" rg",
"g|L",
"LJ "},
new String[] {
"rg ",
"J|r",
" LJ"},
new String[] {
" ",
"---",
" "},
new String[] {
"r-g",
"J L",
" "},
new String[] {
" ",
"g r",
"L-J"},
new String[] {
"rg ",
"JL-",
" "},
new String[] {
" rg",
"-JL",
" "},
new String[] {
" ",
"gr-",
"LJ "},
new String[] {
" ",
"-gr",
" LJ"}
);
} else if (c == '|') {
return Arrays.asList(
new String[] {
" Lg",
"r-J",
"Lg "},
new String[] {
"rJ ",
"L-g",
" rJ"},
new String[] {
" | ",
" | ",
" | "},
new String[] {
" Lg",
" |",
" rJ"},
new String[] {
"rJ ",
"| ",
"Lg "},
new String[] {
" Lg",
" rJ",
" | "},
new String[] {
" | ",
" Lg",
" rJ"},
new String[] {
"rJ ",
"Lg ",
" | "},
new String[] {
" | ",
"rJ ",
"Lg "}
);
} else {
List<String []> ret = new ArrayList<String []>();
ret.add(
new String[] {
" ",
" ",
" "});
return ret;
}
}
}
The width of the line shall be constant throughout the whole image.
But still a useful hint \$\endgroup\$