!752 concepts. sclass TestCase { BufferedImage screen; Rect boardRect; RGBImage board; int boardW, boardH; *() { screen = loadBufferedImage("#1006074"); boardRect = pointRect(194, 179, 501, 485); board = new RGBImage(screen).clip(boardRect); boardW = board.w(); boardH = board.h(); } Rect square(int x, int y) { ret pointsRect( boardW*x/8, boardH*y/8, boardW*(x+1)/8, boardH*(y+1)/8); } Square realSquareType(int x, int y) { ret odd(x*8/boardW + y*8/boardH) ? Square.dark : Square.light; } void showBoard() { new L imgs; for y to 8: { new L l; for x to 8: l.add(square(x, y)); imgs.add(mergeImagePartsHorizontally(board, l)); } showImage(mergeImagesVertically(imgs)); } float testFunction(SquareDetector f) { int step = 5; // faster int n = 0; float points = 0; for (int y = 0; y < boardH; y++) for (int x = 0; x < boardW; x++) { ++n; Square s = f.squareType(board, x, y); Square real = realSquareType(x, y); if (s == real) ++points; else if (s == Square.unknown) points += 0.1f; } float score = points*100f/n; ret score; } } enum Square { light, dark, none, unknown }; // import static main.Square.*; << stupid Java doesn't want this sclass SquareDetector { Square squareType(RGBImage img, int x, int y) { ret Square.none; } } // dummy reference detector sclass AllUnknown extends SquareDetector { Square squareType(RGBImage img, int x, int y) { ret Square.unknown; } } sclass Detector1 extends SquareDetector { RGB colLight, colDark; *() {} *(RGB *colLight, RGB *colDark) {} *(Color colLight, Color colDark) { this.colLight = new RGB(colLight); this.colDark = new RGB(colDark); } Square squareType(RGBImage img, int x, int y) { RGB rgb = img.getPixel(x, y); float distLight = simpleRGBDistance(rgb, colLight); float distDark = simpleRGBDistance(rgb, colLight); ret distLight < distDark ? Square.light : Square.dark; } } sclass Detector2 extends SquareDetector { RGB colLight, colDark; float range = 0.1f; // area around colors that is accepted *() {} *(RGB *colLight, RGB *colDark) {} *(Color colLight, Color colDark) { this.colLight = new RGB(colLight); this.colDark = new RGB(colDark); } Square squareType(RGBImage img, int x, int y) { RGB rgb = img.getPixel(x, y); float distLight = simpleRGBDistance(rgb, colLight); float distDark = simpleRGBDistance(rgb, colLight); if (distLight < range) ret Square.light; if (distDark < range) ret Square.dark; ret Square.unknown; } } // modifies specimen, updates best svoid optimizeOneField(O tester, O specimen, S field, O varyField, Best best) { O varied = callF(varyField, get(specimen, field)); set(specimen, field, varied); float score = toFloat(callF(tester, specimen)); showStatus("Field varied to: " + varied + ", score: " + score + ", best: " + best.bestScore()); if (best.isNewBest(score)) { S s = structure(specimen); best.put(s, score); print("New best! " + score + " - " + shorten(s, 1000)); } } static volatile S showStatus_status = ""; static JLabel showStatus_label; svoid showStatus(S status) { if (showStatus_label == null) awt { if (showStatus_label == null) { showStatus_label = jlabel(); JFrame frame = showPackedFrame(showStatus_label); setFrameWidth(frame, 300); moveToTopRightCorner(frame); installTimer(showStatus_label, 50, r { S s = showStatus_status; if (neq(s, showStatus_label.getText())) showStatus_label.setText(s); }); } } showStatus_status = unnull(status); } static RGB replaceColor(RGB color) { ret randomColor(); } concept PersistentBest { S bestStructure; double score; transient new Best best; *() { _doneLoading(); } void _doneLoading() { best.put(bestStructure, score); best.onChange = r { cset(PersistentBest.this, bestStructure := best.best, score := best.score); }; } S get() { ret best.get(); } bool has() { ret best.has(); } } p { concepts(); final new TestCase tc; //tc.showBoard(); tc.testFunction(new AllUnknown); Detector1 detector1 = new Detector1(Color.white, Color.black); tc.testFunction(detector1); O tester = func(SquareDetector d) { tc.testFunction(d) }; PersistentBest best = uniq(PersistentBest); //optimizeOneField(tester, detector1, "colLight", func replaceColor, best); Detector2 detector2 = new Detector2(Color.white, Color.black); // Main loop: Make new random specimen + vary best while licensed { for (S field : ll("colLight", "colDark")) { optimizeOneField(tester, detector2, field, func replaceColor, best.best); if (best.has()) optimizeOneField(tester, unstructure(best.get()), field, func varyColor, best.best); } } }