!include #1000522 // image helper functions sclass Best { S desc; double score; Renderer renderer; BWImage image; *() {} *(S *desc, double *score, BWImage *image) {} *(S *desc, double *score, Renderer *renderer, BWImage *image) {} int l() { ret main.l(desc); } } static O rendererMaker; // optional maker function (S -> Renderer) sclass Reproducing { BWImage bw; // original ImageSurface imageSurfaceToUpdateWithBest; new LinkedBlockingQueue newProducts; int maxQueueLength = 10; volatile Best shortest100, best; int pivotLength = -1; // no length punishment at start int pivotStep = 1; int fullGrabLength; // length of full grab for reference O startProduction; // optional runnable that starts production int descPrintLength = 100; void push(S product) { if (product == null) ret; while (newProducts.size() >= maxQueueLength && mayRun()) sleep(100); newProducts.add(product); } double formula(S desc, double pixelScore) { int lengthPunishment = pivotLength < 0 ? 0 : max(0, l(desc)-pivotLength); ret pixelScore-lengthPunishment; } void loadShortest100() { S shortest = shortest100(); if (shortest != null) shortest100 = new Best(shortest, 100, null); } void reproduceOpenEnd() { loadShortest100(); best = null; fullGrabLength = l(fullGrab(bw)); long lastPrint = 0, lastN = 0; for (long ntry = 1; ; ntry++) { ping(); long now = now(); if (now >= lastPrint+1000) { long tps = (ntry-lastN)*1000/(now-lastPrint); lastPrint = now; lastN = ntry; String s = "Try " + ntry + " (" + tps + "/s)"; if (best == null) print(s); else { print("Best: " + shorten(best.desc, descPrintLength)); print(s + ", score: " + formatDouble(best.score, 2) + "%, l=" + l(best.desc) + ", pivotL=" + pivotLength + "/" + fullGrabLength + (shortest100 == null ? "" : ", shortest100=" + shortest100.l())); } } S desc; try { desc = grabFromQueue(newProducts); } catch e { print("Production failed: " + exceptionToStringShort(e)); continue; } Renderer p; try { p = makeRenderer(desc); } catch { print("Can't unstructure: " + desc); continue; } BWImage rendering = render(p, bw); double pixelScore = 100*(1-diff(bw, rendering)); double score = formula(desc, pixelScore); if (best == null || p != null && score > getScore(best)) { //System.out.println("New best! " + score); best = new Best(desc, score, p, rendering); if (pixelScore >= 100 && (shortest100 == null || shortest100.l() > l(desc))) { shortest100 = new Best(desc, pixelScore, rendering); saveTextFile(getProgramFile("shortest100.txt"), bw.getWidth() + " " + bw.getHeight() + " " + desc); } imageSurfaceToUpdateWithBest.setImage(best.image.getBufferedImage()); } if (solved()) { print("Solved! l=" + best.l()); print(shorten(best.desc, descPrintLength)); break; } } } bool solved() { ret getScore(best) >= 100.0; } S bestDesc() { ret getDesc(best); } BufferedImage descToImage(S desc) { try { ret makeRenderer(desc).render(bw.getWidth(), bw.getHeight()).getBufferedImage(); } catch { fail(desc); } } void produce() { callF(startProduction); } void findShortest100_openEnd() { produce(); reproduceOpenEnd(); while (solved()) { pivotLength = best.l() - pivotStep; print("Trying pivot length " + pivotLength); produce(); reproduceOpenEnd(); } } } static class FullGrab extends Renderer { int dw, dh; byte[] data; BWImage render(int w, int h) { if (w != dw || h != dh) fail("size: \*w*/ \*h*/ \*dw*/ \*dh*/"); ret new BWImage(w, h, data); } } static class HRepeat extends Renderer { int width; S inner; BWImage render(int w, int h) { BWImage img = new BWImage(w, h); BWImage clip = ((Renderer) unstructure(inner)).render(width, h); for (int x = 0; x < w; x += width) copy(clip, 0, 0, img, x, 0, width, h); ret img; } } static S fullGrab(BWImage img) { DynamicObject d = new DynamicObject("FullGrab"); int w = img.getWidth(), h = img.getHeight(); d.put("dw", w); d.put("dh", h); byte[] data = new byte[w*h]; for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) data[y*w+x] = img.getByte(x, y); d.put("data", data); ret structure(d); } static S hrepeat(BWImage img, int width) { int h = img.getHeight(); BWImage clip = img.clip(0, 0, width, h); ret structure(dynamicObject("HRepeat", "width", width, "inner", fullGrab(clip))); } static S varyFloat(S s) { L tok = javaTok(s); int i = tok.indexOf("f"); if (i < 0) null; float f = Float.parseFloat(unquote(tok.get(i+2))); f = (float) (f+random(-0.1, 0.1)); tok.set(i+2, quote(str(f))); ret join(tok); } static BWImage render(Renderer p, BWImage original) { ret p.render(original.getWidth(), original.getHeight()); } static interface Reproducer { public S reproduce(BWImage original); } static class Solid extends Renderer { float col; BWImage render(int w, int h) { ret new BWImage(w, h, col); } } static class RandomSolid implements Reproducer { int n = -1; public S reproduce(BWImage original) { ++n; DynamicObject p = new DynamicObject("Solid"); if (n % 2 == 0) { p.put("col", randomBrightness()); } else { p.put("col", probeRandomPixel(original)); } ret structure(p); } } static abstract class Renderer { abstract BWImage render(int w, int h); } static S shortest100() { ret loadTextFile(getProgramFile("shortest100.txt")); } static BufferedImage renderShortest100() { ret render(shortest100()); } static double getScore(Best b) { ret b == null ? 0 : b.score; } static S getDesc(Best b) { ret b == null ? null : b.desc; } static Renderer makeRenderer(S desc) { if (rendererMaker != null) { Renderer r = cast callF(rendererMaker, desc); if (r != null) ret r; } ret (Renderer) unstructure(desc); } static BufferedImage render(S fullDesc) { if (fullDesc == null) null; new Matches m; assertTrue(jmatchStart("* *", fullDesc, m)); int w = m.psi(0), h = m.psi(1); S desc = m.unq(2); ret makeRenderer(desc).render(w, h).getBufferedImage(); }