/////////////////////////// // Your API to work with // /////////////////////////// sinterface GameForAI { int round(); // starting from 1 double submit(Submission data); // returns score (0-100) } abstract sclass AI { // stuff you get GameForAI game; RGBImage image; bool visualize = true; RGBImage image() { ret image; } int w() { ret image.w(); } int h() { ret image.h(); } int round() { ret game.round(); } double submit(Submission data) { ret game.submit(data); } A initSubAI(A ai) { setOptAll(ai, +game, +image); ret ai; } // implement this method and call submit() abstract void go(); void done() {} } /////////////// // Main Game // /////////////// static int rounds = 1000; static double targetScore = 99.0; // stop when this score is reached static int fps = 50; sS gameTitle; sS newImageText = "New Image"; sS instruction = "Reproduce this image:"; sS aiTitle = "AI"; sbool showConsoleOnError; static double reproZoom = 2; sbool showTheImage = true, showRepro = true; static int maxImageSize = 128; // width or height sbool mixReproWithImage = true; static int w, h; static new UserGame userGame; static int halfTime; static ImageSurface is, isUser, isRepro; static S imageID; static RGBImage img; static BufferedImage fullSizeImage; static new HashMap words; static L solution; volatile sbool aiMode; static JLabel lblScore, lblTiming, lblInstruction, lblImageName; static new HashMap ais; static S winner; static JCheckBox keepRunning; static L aiButtons; static Game game; svoid pGame { substance(); swing { thread { loadBinarySnippet(#1004373); } // preload applause animation lblInstruction = jcenteredBoldLabel(instruction); lblScore = jcenteredBoldLabel(); nextImage(); addToWindowTop(is, withMargin(lblInstruction)); addToWindow(is, withMargin(lblScore)); addToWindow(is, withMargin(lblImageName = jcenteredlabel())); // add AI bjuttons aiButtons = ll(); for (final Class c : myNonAbstractClassesImplementing(AI)) { final S name = shortClassName(c); final JButton btn = jbutton(name); final Runnable go = r { if (aiMode) ret; setText(btn, name + " Running..."); final Runnable again = this; thread { /*game =*/ testAI(c, voidfunc(Game game) { if (!(game.step >= rounds || (game.step % 10) == 0)) ret; S text = name + " scored " + formatScore(game.score) + " in " + n(game.step, "round"); if (game.error != null) text += " - ERROR: " + game.error; setText_noWait_sync(btn, text); }); if (isChecked(keepRunning)) again.run(); } }; onClick(btn, r { if (aiMode) setChecked(keepRunning, false); else go.run(); }); aiButtons.add(btn); addToWindow(is, withMargin(btn)); } addToWindow(is, lblTiming = jCenteredLabel(; titlePopupMenuItem(is, "Show Winner Code", f showBestCode); titlePopupMenuItem(is, "Restart AIs", r { restartAIs() }); titlePopupMenuItem(is, "Diff", r { setImage(subtractRGBImages(img, renderImage(game.best!))) }); addToWindow(is, withMargin(jRightAlignedLine(keepRunning = jcheckbox("Keep AI Running", true)))); addToWindow(is, withMargin(jbutton("Restart AIs", r { clearMapWithCleanUp(ais); }))); addToWindow(is, withMargin(jbutton(newImageText, r { nextImage(); setImage(main.img); }))); addToWindow(is, withMargin(jbutton("Load image...", r { frameTitle("Load image", selectSnippetID_v1(voidfunc(S imageID) { loadImageSnippet(imageID); })); }))); addToWindow(is, withMargin(jbutton("Scale down", f scaleDown))); addToWindow(is, withMargin(jbutton("Random image", r-thread { loadImageSnippet(randomImageServerID()); }))); packFrame(is); setFrameWidth(is, 500); centerTopFrame(is); hideConsole(); } } svoid nextImage { main.img = makeImage(); if (aiMode) ret; // occasional updates only when AI is running showTheImage(); } svoid showTheImage { w = img.w(); h = img.h(); if (!showTheImage) ret; bool first = is == null; is = showZoomedImage_centered(is, img, 1); if (first) { if (gameTitle == null) gameTitle = programTitle(); setFrameTitle(is, gameTitle); disableImageSurfaceSelector(is); isUser = new ImageSurface(newBufferedImage(w, h, Color.white)); JComponent form = cast callOptMC('makeTheForm, userGame); // make form for user participation if (form != null) { addToWindow(is, withTitle("Your Reproduction:", jscroll_centered(isUser))); addToWindow(is, form); } // animate if idle /*awtEvery(is, 1000, r { if (!aiMode && isInForeground(is) && !mouseInFrame(is)) nextImage(); });*/ // show current image occasionally when AI is running /*awtEvery(is, 1000/fps, r { if (aiMode) showTheImage(); });*/ } } // AI stuff sclass Game implements GameForAI { volatile int step; int rounds = main.rounds; new Best best; RGBImage bestImage; double score; Submission submitted; // what was submitted in this round Throwable error; volatile bool cancelled; public int round() { ret step; } int rounds() { ret rounds; } double percentScore() { ret score; } S bestCode() { ret struct(best!); } public double submit(Submission data) { if (data == null) ret 0; if (submitted != null) fail("No multi-submit please"); submitted = data; RGBImage image = renderImage(data); double score = scoreImage(image); if (best.put(data, score)) { bestImage = image; this.score = best.score; } ret score; } } Game > UserGame { public double submit(Submission data) { submitted = null; double score = super.submit(data); RGBImage image = renderImage(data); isUser.setImage(image); lblScore.setText("Current score: " + formatScore(score) + " / Best: " + formatScore(userGame.score)); ret score; } } static S formatScore(double score) { ret formatDouble(score, 2) + " %"; } svoid initAI(AI ai, GameForAI game) { setOpt(ai, +game); } static Game scoreAI(final AI ai) { ret scoreAI(ai, null); } static Game scoreAI(final AI ai, O onScore) { aiMode = true; final long start = sysNow(); try { final new Game game; initAI(ai, game); halfTime = rounds/2; game.step = 0; main.game = game; while (game.step < rounds && !game.cancelled) { ++game.step; game.submitted = null; double score = game.score; RGBImage image = img; try { setOpt(ai, +image); ai.go(); } catch e { if (game.error == null) { // print first error to console if (showConsoleOnError) showConsole(); printStackTrace(e); } game.error = e; } finally { setOpt(ai, image := null); } if (game.score > score && showRepro) { bool first = isRepro == null; S title = dropSpaces(formatScore(game.score)) + " - " + aiTitle; BufferedImage reproImg = renderWithHints(game.best!); if (mixReproWithImage) reproImg = blendBufferedImages(img.getBufferedImage(), reproImg); isRepro = showZoomedImage_centered(isRepro, title, reproImg, reproZoom); if (first) { //coActivateAllMyFrames(); moveToTopRightCorner(isRepro); enlargeFrameLeftAndBottom(isRepro, 100, 100); } } pcallF(onScore, game); //if (alwaysNewImage) nextImage(); } ai.done(); // TODO: winner saving /*if (game.points-game.halfTimeScore >= rounds-halfTime) thread { titleStatus(is, "Solved!"); showAnimationInTopLeftCorner(#1004373, game.points + " of " + rounds + " points!!", 3.0); winner = structure(ai); save("winner"); }*/ ret game; } finally { aiMode = false; setText(lblTiming, formatDouble(toSeconds(sysNow()-start), 1) + " s"); } } static AI getAI(Class c) { AI ai = ais.get(c); if (ai == null) ais.put(c, ai = nu(c)); ret ai; } // onScore: voidfunc(Game) static Game testAI(Class c, O onScore) { ret scoreAI(getAI(c), onScore); } svoid showBestCode { Submission s = game.best!; showWrappedText("Best code (" + formatScore(game.best.score()) + ")", structure(s)); } svoid showWinnerCode { if (winner == null) load("winner"); if (winner == null) messageBox("No winner yet"); else showWrappedText("Winner Code - " + programTitle(), winner); } static double scoreImage(RGBImage image) { ret 100*(1.0-rgbDistance(image, img)); } svoid restartAIs { clearMapWithCleanUp(ais); // whatever I do, it doesn't get cancelled, haha //if (game != null) game.cancelled = true; } svoid setInstruction(S s) { setText(lblInstruction, instruction = s); } svoid setImage(final RGBImage img) { swing { main.img = img; showTheImage(); restartAIs(); } } svoid scaleDown() { setImage(rgbScale(main.img, 0.5)); } svoid loadImageSnippet(S id) { imageID = id; BufferedImage img = changeTransparencyToWhiteBackground(loadImage2(id)); fullSizeImage = img; img = scaleBufferedImageToMaxWidthOrHeight(maxImageSize, img); setImage(RGBImage(img)); setText(lblImageName, snippetWithTitle(id)); } // We now render in BufferedImage static RGBImage renderImage(Submission s) { ret new RGBImage(renderImage1(s)); }