!7 /////////////////////////// // Your API to work with // /////////////////////////// abstract sclass GameForAI { abstract RGBImage getImage(); abstract L submit(Pt point); // returns correct solution so AI can learn from it } abstract sclass AI { // stuff you get GameForAI game; RGBImage image() { ret game.getImage(); } int w() { ret image().w(); } int h() { ret image().h(); } L submit(Pt p) { ret game.submit(p); } // implement this method and call submit() abstract void go(); } ////////////////////////////////////// // Test AIs. Just add your own here // ////////////////////////////////////// AI > TestAI { void go { submit(new Pt(random(image().w()), random(image().h()))); } } AI > ErrorAI { void go { throw new NullPointerException; } } /////////////// // Main Game // /////////////// static int w = 400, h = 300; static int border = 10, fontSize = 30; static int rounds = 1000; static S font = #1004887; static int points, clicks; static ImageSurface is; static RGBImage img; static new HashMap words; static L solution; volatile sbool aiMode; static JLabel lblScore; p-substance { nextImage(); addToWindow(is, withMargin(lblScore = jcenteredBoldLabel("Your score: 0 of 0"))); for (final Class c : myNonAbstractClassesImplementing(AI)) { final S name = shortClassName(c); final JButton btn = jbutton("Run " + name); onClick(btn, r { if (aiMode) ret; btn.setText(name + " Running..."); thread { Game game = testAI(c); S text = name + " scored " + game.points + " of " + rounds; if (game.error != null) text += " - ERROR: " + game.error; setText(btn, text); } }); addToWindow(is, withMargin(btn)); } centerTopFrame(packFrame(is)); hideConsole(); } svoid nextImage { RGBImage img = rgbImage(Color.white, w, h); words.clear(); for i to 5: { int num = random(100); S s = str(num); RGB color = new RGB(random(0.5), random(0.5), random(0.5)); renderText_fg.set(color.getColor()); BufferedImage ti = renderText(font, fontSize, s); Rect r; do { r = randomRect(w, h, border, ti.getWidth(), ti.getHeight()); if (r == null) fail("Image too small: \*ti.getWidth()*/*\*ti.getHeight()*/ > \*w*/*\*h*/"); } while (anyRectOverlaps(keys(words), r) && licensed()); rgbCopy(ti, img, r.x, r.y); words.put(r, num); } solution = keysWithBiggestValue(words); main.img = img; if (aiMode) ret; // occasional updates only when AI is running showTheImage(); } svoid showTheImage { bool first = is == null; is = showImage(is, img, "Click On The Highest Number!"); if (first) { onLeftClick(is, voidfunc(Pt p) { ++clicks; if (anyRectContains(solution, p)) { ++points; nextImage(); } lblScore.setText(print("Your score: " + points + " of " + clicks)); }); disableImageSurfaceSelector(is); // animate if idle awtEvery(is, 1000, r { if (!aiMode && isInForeground(is) && !mouseInComponent(is)) nextImage(); }); // show current image occasionally when AI is running awtEvery(is, 20, r { if (aiMode) showTheImage(); }); } } // AI stuff sclass Game extends GameForAI { int points; bool submitted; Throwable error; RGBImage getImage() { ret img; } L submit(Pt p) { if (submitted) fail("No multi-submit please"); submitted = true; if (anyRectContains(solution, p)) { ++points; nextImage(); } ret solution; } } static Game scoreAI(AI ai, long rounds) { aiMode = true; try { new Game game; setOpt(ai, +game); long step = 0; while (step < rounds) { ++step; game.submitted = false; try { ai.go(); } catch e { if (game.error == null) { // print first error to console showConsole(); printStackTrace(e); } game.error = e; } //print("Step " + step + ", move: " + p + ", points: " + game.points); } print("AI " + shortClassName(ai) + " points after " + rounds + " rounds: " + game.points); ret game; } finally { aiMode = false; awt { nextImage(); } } } static Game testAI(Class c) { ret scoreAI(nu(c), rounds); }