!7 static int boxes = 3; !include #1006931 // AI Game & API p-autorestart { newImageText = "New Letter!"; makeInstruction(); pGame(); swing { setFrameTitle(is, "A. I. Game 5"); final JSpinner spinner = jSpinner(boxes, 1, 100); addToWindowPack_keepWidth(is, withMargin(jRightAligned(withLabel("Number of boxes to use:", spinner)))); onChange(spinner, r { boxes = intFromSpinner(spinner); makeInstruction(); restartAIs(); }); clickButton(last(aiButtons)); // Start the winner AI! } } svoid makeInstruction { setInstruction("Reproduce this image with " + n2(boxes, "box", "boxes") + ":"); } sclass Box { Pt a, b; RGB color; *() {} *(Pt *a, Pt *b, RGB *color) {} } sclass Submission { RGB background; new L boxes; *() {} *(RGB *background, Box... boxes) { this.boxes = asList(boxes); check(); } *(RGB *background, L *boxes) { check(); } void check { assertEquals(main.boxes, l(boxes)); } } ////////////////// // PUZZLE MAKER // ////////////////// sS lastLetter; static RGBImage makeImage() { //ret loadRGBImage(/*#1006930*/#1006944); S letter; do { letter = "" + randomCharBetween('A', 'Z'); } while (eq(letter, lastLetter)); lastLetter = letter; renderText_withLeading = false; renderText_bg.set(toColor(randomColor())); renderText_fg.set(toColor(randomColor())); ret new RGBImage(renderText(#1004568, 100, letter)); } /////////////// // RENDERERS // /////////////// static RGBImage renderImage(Submission s) { ret new RGBImage(renderImage1(s)); } static BufferedImage renderImage1(Submission s) { BufferedImage bi = newBufferedImage(w, h, toColor(s.background)); Graphics2D g = imageGraphics(bi); for (Box e : s.boxes) { int x1 = min(e.a.x, e.b.x), y1 = min(e.a.y, e.b.y); int x2 = max(e.a.x, e.b.x), y2 = max(e.a.y, e.b.y); fillRect(g, x1, y1, x2-x1+1, y2-y1+1, toColor(e.color)); } g.dispose(); ret bi; } static BufferedImage renderWithHints(Submission s) { BufferedImage bi = renderImage1(s); for (Box e : s.boxes) { int x1 = min(e.a.x, e.b.x), y1 = min(e.a.y, e.b.y); int x2 = max(e.a.x, e.b.x), y2 = max(e.a.y, e.b.y); drawRect(bi, x1, y1, x2-x1+1, y2-y1+1, colorWithAlpha(0.5, Color.black)); } ret bi; } ////////////////////////////////////// // Test AIs. Just add your own here // ////////////////////////////////////// AI > AI_Random { new Best best; Box randomBox() { ret new Box(randomPoint(), randomPoint(), randomColor()); } Pt randomPoint() { ret main.randomPoint(image()); } void go { //print("Round: " + round()); if (round() == 1 && best.has()) // TODO: automate this submit(best.get()); else { Submission guess = guess(); updateBest(guess, submit(guess)); } } void updateBest(Submission guess, double score) { best.put(guess, score); } Submission guess() { ret new Submission(randomColor(), produceN(func { randomBox() }, boxes)); } } AI_Random > AI_RandomWithVariation { int n; Submission guess() { if (odd(n++) && best.has()) ret vary(best.get()); else ret super.guess(); } Submission vary(Submission s) { s = cloneThroughStructure(s); if (oneIn(10)) s.background = varyColor(s.background); else if (tossCoin()) replaceRandomElement(s.boxes, randomBox()); else varyBox(random(s.boxes)); ret s; } void varyBox(Box l) { int i = random(3); if (i == 0) l.a = varyPoint(l.a); else if (i == 1) l.b = varyPoint(l.b); else l.color = varyColor(l.color); } Pt varyPoint(Pt p) { ret tossACoin() ? randomPoint() : varyPoint(p, 10); } Pt varyPoint(Pt p, int range) { range = max(range, 1); ret new Pt( random(p.x-range, p.x+range+1), random(p.y-range, p.y+range+1)); } } AI > AI_Racer { AI_RandomWithVariation leader, overtaker; new Best leadersBest; int discardEvery = 5000; int roundsSinceChange; AI_RandomWithVariation newAI() { ret new AI_RandomWithVariation; } void go { if (round() == 1 && leadersBest.has()) // TODO: automate this submit(leadersBest.get()); else if (tossACoin()) { if (leader == null) leader = newAI(); initSubAI(leader); Submission guess = leader.guess(); double score = submit(guess); leader.updateBest(guess, score); leadersBest.put(guess, score); } else { if (overtaker == null) overtaker = newAI(); initSubAI(overtaker); Submission guess = overtaker.guess(); double score = submit(guess); overtaker.updateBest(guess, score); if (score > leadersBest.score()) { // displace leader! print("Overtake at " + formatScore(overtaker.best.score()) + " vs " + formatScore(leadersBest.score())); leader = overtaker; overtaker = null; roundsSinceChange = 0; } else if (roundsSinceChange++ >= discardEvery) { // make new overtaker print("Discarding overtaker at " + formatScore(overtaker.best.score()) + " vs " + formatScore(leadersBest.score())); overtaker = null; roundsSinceChange = 0; } } } }