!7 static int lineWidth = 13; static int lines = 2; sS font = /*#1004568*/#1004970; sbool oldVaryLine = false; !include #1006931 // AI Game & API p { newImageText = "New Letter!"; makeInstruction(); pGame(); swing { setFrameTitle(is, "A. I. Game 5.2"); final JSpinner spinner = jSpinner(lines, 1, 100); addToWindowPack(is, withMargin(jRightAligned(withLabel("Number of lines to use:", spinner)))); onChange(spinner, r { lines = intFromSpinner(spinner); makeInstruction(); restartAIs(); }); } } svoid makeInstruction { setInstruction("Reproduce this image with " + n(lines, "curved line") + ":"); } sclass Curve { Pt a, b, c; // b = control point for curve *() {} *(Pt *a, Pt *b, Pt *c) {} Pt realb() { ret un_closerControlPoint(a, b, c); } } sclass Submission { new L lines; *() {} *(Curve... lines) { this.lines = asList(lines); check(); } *(L *lines) { check(); } void check { assertEquals(main.lines, l(lines)); } } ////////////////// // PUZZLE MAKER // ////////////////// sS lastLetter; static RGBImage makeImage() { S letter; S choice = charRange('A', 'Z') + charRange('0', '9'); do { letter = "" + oneOf(choice); } while (eq(letter, lastLetter)); lastLetter = letter; aiTitle = letter + "/" + lines; ret rgbWhiteBorder(10, rgbAutoCrop(new RGBImage(renderText(font, 100, letter)))); } ////////////////////// // FORM MAKER (NONE // ////////////////////// static JComponent makeTheForm(final GameForAI game) { null; } /////////////// // RENDERERS // /////////////// static RGBImage renderImage(Submission s) { ret new RGBImage(renderImage1(s)); } static BufferedImage renderImage1(Submission s) { BufferedImage bi = newBufferedImage(w, h, Color.white); for (Curve l : s.lines) drawRoundEdgeCurve(bi, l.a, l.realb(), l.c, Color.black, lineWidth); ret bi; } static RGBImage renderWithHints(Submission s) { //BufferedImage bi = renderImage1(s); BufferedImage bi = newBufferedImage(w, h, Color.white); int n = 0; for (Curve l : s.lines) drawRoundEdgeCurve(bi, l.a, l.realb(), l.c, rainbowColor(n++, l(s.lines)), lineWidth); RGBImage img = new RGBImage(bi); for (Curve l : s.lines) { rgbMarkPoints(img, Color.lightGray, 1, l.a, l.c); Pt control = l.b; // closerControlPoint(l.a, l.b, l.c); rgbMarkPoints(img, Color.red, 1, control); // control point in red } ret rgbUncache(img); } ////////////////////////////////////// // Test AIs. Just add your own here // ////////////////////////////////////// AI > AI_Random { new Best best; Curve randomLine() { ret new Curve(randomPoint(), randomPoint(), randomPoint()); } Pt randomPoint() { ret main.randomPoint(image()); } void go { //print("Round: " + round()); if (round() == 1 && best.has()) submit(best.get()); else { Submission guess = guess(); updateBest(guess, submit(guess)); } } bool updateBest(Submission guess, double score) { ret best.put(guess, score); } Submission guess() { ret new Submission(produceN(func { randomLine() }, lines)); } } 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); varyLine(random(s.lines)); ret s; } void varyLine(Curve l) { if (oldVaryLine) switch (random(3)) { case 0: l.a = varyPoint(l.a); case 1: l.b = varyPoint(l.b); case 2: l.c = varyPoint(l.c); } else if (oneIn(3)) switch (random(3)) { case 0: l.a = randomPoint(); case 1: l.b = randomPoint(); case 2: l.c = randomPoint(); } else { l.a = varyPoint2(l.a); l.b = varyPoint2(l.b); l.c = varyPoint2(l.c); } } Pt varyPoint(Pt p) { ret tossACoin() ? randomPoint() : varyPoint(p, 10); } Pt varyPoint2(Pt p) { ret 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 = 2500; int roundsSinceChange; static ImageSurface is; AI_RandomWithVariation newAI() { ret new AI_RandomWithVariation; } void go { if (round() == 1 && leadersBest.has()) 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); if (overtaker.updateBest(guess, score)) { int percent = toIntPercent(score/leader.best.score()); S title = percent + "% Challenger"; bool first = is == null; is = showZoomedImage_centered(is, title, renderWithHints(guess)); if (first) { setFrameWidth(is, 250); moveToTopRightCorner(is); moveFrameDown(is, 300); } } 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; } } } }