///////////////////////////
// Your API to work with //
///////////////////////////
sinterface GameForAI {
L<Rect> submit(Pt point); // returns correct solution so AI can learn from it
}
abstract sclass AI {
// stuff you get
GameForAI game;
RGBImage image;
int steps;
bool visualize = true;
RGBImage image() { ret image; }
int w() { ret image.w(); }
int h() { ret image.h(); }
L<Rect> submit(Pt p) { ret game.submit(p); }
L<Rect> submit(Rect r) { ret submit(middleOfRect(r)); }
L<Rect> submitNothing() { ret game.submit(null); }
// implement this method and call submit()
abstract void go();
void done() {}
}
///////////////
// Main Game //
///////////////
static int w = 150, h = 150;
static int rounds = 1000;
static bool alwaysNewImage = true; // prevents AIs being stuck on an image
static double imageZoom = 2;
static int fps = 50;
static bool showBlunderWindow;
sS nonClickName = null;
static int points, clicks, halfTime;
static ImageSurface is, isWrong;
static long isWrongLast;
static RGBImage img;
static new HashMap<Rect, Int> words;
static L<Rect> solution;
volatile sbool aiMode;
static JLabel lblScore, lblTiming, lblInstruction;
static new HashMap<Class, AI> ais;
static S winner;
svoid pGame {
substance();
swing {
thread { loadBinarySnippet(#1004373); } // preload applause animation
lblInstruction = jcenteredBoldLabel();
nextImage();
addToWindowTop(is, withMargin(lblInstruction));
if (nempty(nonClickName))
addToWindow(is, withTopMargin(jCenteredLine(jbutton(nonClickName, r {
userClicked(null)
}))));
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(name);
onClick(btn, r {
if (aiMode) ret;
btn.setText(name + " Running...");
thread {
Game game = testAI(c, voidfunc(Game game) {
if (game.step < 50 || (game.step % 10) == 0 || game.step == rounds) {
S text = name + " scored " + game.points + " of " + game.step;
if (game.step > halfTime)
text += " (" + (game.points-game.halfTimeScore) + "/" + (game.step-halfTime) + ")";
if (game.error != null)
text += " - ERROR: " + game.error;
setText_noWait(btn, text);
}
});
}
});
addToWindow(is, withMargin(btn));
}
addToWindow(is, lblTiming = jCenteredLabel(;
titlePopupMenuItem(is, "Show Winner Code", f showWinnerCode);
titlePopupMenuItem(is, "Restart AIs", r { clearMapWithCleanUp(ais); });
titlePopupMenuItem(is, jCheckBoxMenuItem("Show Blunder Window", showBlunderWindow, r { showBlunderWindow = !showBlunderWindow; }));
addToWindow(is, withMargin(jbutton("Restart AIs", r { clearMapWithCleanUp(ais); })));
packFrame(is);
setFrameWidth(is, 400);
centerTopFrame(is);
hideConsole();
}
}
sclass Puzzle {
S instruction, nonClickName;
RGBImage image;
L<Rect> solution;
*() {}
*(S *instruction, BufferedImage image, L<Rect> *solution) {
this.image = new RGBImage(image);
}
*(S *instruction, RGBImage *image, L<Rect> *solution) {}
*(S *instruction, S *nonClickName, RGBImage *image, L<Rect> *solution) {}
}
svoid nextImage {
Puzzle puzzle = makePuzzle();
setText(lblInstruction, or2(puzzle.instruction, "?"));
assertNotNull("Image is null", puzzle.image);
main.img = puzzle.image;
solution = puzzle.solution;
nonClickName = puzzle.nonClickName;
if (aiMode) ret; // occasional updates only when AI is running
showTheImage();
}
svoid showTheImage {
bool first = is == null;
is = showZoomedImage_centered(is, img, imageZoom);
if (first) {
onLeftClick(is, voidfunc(Pt p) { userClicked(p) });
disableImageSurfaceSelector(is);
// 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 {
int points, step, halfTimeScore;
Pt submitted;
Throwable error;
public L<Rect> submit(Pt p) {
if (submitted != null) fail("No multi-submit please");
submitted = p == null ? nonPoint() : p;
bool correct = empty(solution) ? p == null
: p != null && anyRectContains(solution, p);
// print("p=" + p + ", solution=" + solution + ", correct=" + correct);
if (correct) {
++points;
if (!alwaysNewImage) nextImage();
}
ret solution;
}
}
static Game scoreAI(final AI ai, O onScore) {
aiMode = true;
final long start = sysNow();
try {
final new Game game;
setOpt(ai, +game);
halfTime = rounds/2;
while (game.step < rounds) {
if (game.step == halfTime) game.halfTimeScore = game.points;
++game.step;
++ai.steps;
game.submitted = null;
int points = game.points;
RGBImage image = img;
try {
setOpt(ai, +image);
ai.go();
} catch e {
if (game.error == null) { // print first error to console
showConsole();
printStackTrace(e);
}
game.error = e;
} finally {
setOpt(ai, image := null);
}
if (showBlunderWindow && points == game.points && hasElapsed(isWrongLast, 50)) {
isWrongLast = sysNow();
bool first = isWrong == null;
S guess = ""; // game.submitted == null ? "no click" : game.submitted.x + "/" + game.submitted.y;
isWrong = showImage(isWrong, "Last Blunder" + (nempty(guess) ? " (" + guess + ")" : ""), rgbMarkPoint(rgbClone(image), game.submitted, Color.red, 3));
if (first) {
setFrameWidth(isWrong, 230);
moveToTopRightCorner(isWrong);
moveFrameDown(isWrong, 100);
}
}
pcallF(onScore, game);
if (alwaysNewImage) nextImage();
}
print("AI " + shortClassName(ai) + " points after " + rounds + " rounds: " + game.points);
ai.done();
// We consider the game solved when an AI scores 100% in second half
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;
awt {
lblTiming.setText(formatDouble(toSeconds(sysNow()-start), 1) + " s");
nextImage();
}
}
}
static AI getAI(Class<? extends AI> c) {
AI ai = ais.get(c);
if (ai == null) ais.put(c, ai = nu(c));
ret ai;
}
// onScore: voidfunc(Game)
static Game testAI(Class<? extends AI> c, O onScore) {
ret scoreAI(getAI(c), onScore);
}
svoid userClicked(Pt p) {
++clicks;
bool correct = empty(solution) ? p == null
: p != null && anyRectContains(solution, is.pointFromComponentCoordinates(p));
if (correct) {
++points;
nextImage();
} else if (alwaysNewImage) nextImage();
lblScore.setText(print("Your score: " + points + " of " + clicks));
}
svoid showWinnerCode {
if (winner == null) load("winner");
if (winner == null) messageBox("No winner yet");
else showWrappedText("Winner Code - " + programTitle(), winner);
}download show line numbers debug dex old transpilations
Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
| Snippet ID: | #1006891 |
| Snippet name: | AI Game Where User Has To Click [Include] |
| Eternal ID of this version: | #1006891/37 |
| Text MD5: | 58950d720448af75ab2da549150245db |
| Author: | stefan |
| Category: | javax / a.i. |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2017-03-08 17:09:26 |
| Source code size: | 7702 bytes / 249 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 988 / 1891 |
| Version history: | 36 change(s) |
| Referenced in: | [show references] |