Uses 3874K of libraries. Click here for Pure Java version (6909L/49K/174K).
1 | !7 |
2 | |
3 | /////////////////////////// |
4 | // Your API to work with // |
5 | /////////////////////////// |
6 | |
7 | abstract sclass GameForAI {
|
8 | abstract RGBImage getImage(); |
9 | abstract L<Rect> submit(Pt point); // returns correct solution so AI can learn from it |
10 | } |
11 | |
12 | abstract sclass AI {
|
13 | // stuff you get |
14 | |
15 | GameForAI game; |
16 | RGBImage image; |
17 | int steps; |
18 | RGBImage image() { ret image; }
|
19 | int w() { ret image.w(); }
|
20 | int h() { ret image.h(); }
|
21 | L<Rect> submit(Pt p) { ret game.submit(p); }
|
22 | L<Rect> submit(Rect r) { ret submit(middleOfRect(r)); }
|
23 | L<Rect> submitNothing() { ret game.submit(null); }
|
24 | |
25 | // implement this method and call submit() |
26 | abstract void go(); |
27 | |
28 | void done() {}
|
29 | } |
30 | |
31 | ////////////////////////////////////// |
32 | // Test AIs. Just add your own here // |
33 | ////////////////////////////////////// |
34 | |
35 | AI > ClickAnyNumber {
|
36 | void go {
|
37 | submit(random(segment(image; |
38 | } |
39 | } |
40 | |
41 | static ImageSurface isFound; |
42 | |
43 | AI > FindPairs {
|
44 | void go {
|
45 | L<Rect> solution = submitNothing(); |
46 | if (l(solution) == 2) |
47 | isFound = setFrameWidth(showImage(isFound, "Pairs!", mergeImagesHorizontally(rgbClips(image, solution))), 200); |
48 | } |
49 | } |
50 | |
51 | AI > FindNonPairs {
|
52 | void go {
|
53 | L<Rect> solution = submitNothing(); |
54 | if (l(solution) == 1) {
|
55 | L<Rect> myRects = segment(image); |
56 | Rect sol = autoCropOfRGBImage(image, first(solution)); |
57 | myRects = dropRectsIntersectingWith(myRects, sol); |
58 | if (l(myRects) == 1) |
59 | isFound = setFrameWidth(showImage(isFound, "Non-Pairs!", mergeImagesHorizontally(rgbClips(image, concatLists(ll(sol), myRects)))), 250); |
60 | } |
61 | } |
62 | } |
63 | |
64 | AI > JARVIS {
|
65 | new BWImageCategorizer cat; |
66 | bool firstRun = true; |
67 | static ImageSurface is; |
68 | |
69 | BWImage simplifyImage(RGBImage img) {
|
70 | ret new Image2B(img).toBW(); |
71 | } |
72 | |
73 | Rect guess() {
|
74 | L<Rect> myRects = segment(image); |
75 | if (l(myRects) != 2) null; |
76 | int i = cat.locateImage(simplifyImage(image.clip(first(myRects; |
77 | int j = cat.locateImage(simplifyImage(image.clip(second(myRects; |
78 | ret get(myRects, i < j ? 0 : 1); |
79 | } |
80 | |
81 | void go {
|
82 | L<Rect> solution = submit(guess()); |
83 | Analysis analysis = analyzePair(image, solution); |
84 | if (analysis == null) ret; |
85 | int n = cat.numCategories(); |
86 | int i = cat.addImage(simplifyImage(first(analysis.images))); |
87 | int j = cat.addImage(simplifyImage(second(analysis.images))); |
88 | bool update = cat.numCategories() > n; |
89 | if (analysis.hetero && i > j) {
|
90 | swap(cat.images, i, j); |
91 | update = true; |
92 | } |
93 | if (cat.numCategories() > 10) {
|
94 | cat.allowedDistance += 0.01f; |
95 | print("Got 11 categories after " + steps + " rounds. Upping allowed distance to: " + cat.allowedDistance);
|
96 | cat.clear(); |
97 | steps = 0; |
98 | } else if (update) {
|
99 | bool first = is == null; |
100 | is = showImage_centered(is, "JARVIS Has Learned These Numbers", mergeImagesHorizontally(cat.rgbImages())); |
101 | if (first) {
|
102 | setFrameWidth(is, 400); |
103 | moveToTopRightCorner(getFrame(is)); |
104 | } |
105 | } |
106 | if (firstRun && steps < 50) sleep(blend(1000, 0, steps/50.0)); |
107 | } |
108 | |
109 | void done() {
|
110 | print("Categories: " + cat.numCategories() + " (should probably be 10)");
|
111 | steps = 0; firstRun = false; |
112 | } |
113 | |
114 | void cleanMeUp() {
|
115 | print("Jarvis cleaning up");
|
116 | if (is != null) is.setImage((BufferedImage) null); |
117 | } |
118 | } |
119 | |
120 | sclass Analysis {
|
121 | bool hetero; |
122 | L<RGBImage> images; |
123 | |
124 | *() {}
|
125 | *(bool *hetero, L<RGBImage> *images) {}
|
126 | } |
127 | |
128 | static Analysis analyzePair(RGBImage image, L<Rect> solution) {
|
129 | if (l(solution) == 2) |
130 | ret new Analysis(false, rgbClips(image, rgbAutoCropRects(image, solution))); |
131 | if (l(solution) == 1) {
|
132 | L<Rect> myRects = segment(image); |
133 | Rect sol = autoCropOfRGBImage(image, first(solution)); |
134 | myRects = dropRectsIntersectingWith(myRects, sol); |
135 | if (l(myRects) == 1) |
136 | ret new Analysis(true, rgbClips(image, concatLists(ll(sol), myRects))); |
137 | } |
138 | null; // no insights today |
139 | } |
140 | |
141 | static L<Rect> segment(RGBImage img) {
|
142 | ret autoSegment(new BWImage(img), 3); // 2 is too small |
143 | } |
144 | |
145 | /////////////// |
146 | // Main Game // |
147 | /////////////// |
148 | |
149 | static int w = 150, h = 150; |
150 | static int border = 10, fontSize = 30, numberMargin = 3; |
151 | static int rounds = 1000, numbers = 2; |
152 | static S font = #1004887; |
153 | static bool alwaysNewImage = true; // prevents AIs being stuck on an image |
154 | static int fps = 50; |
155 | |
156 | static int points, clicks; |
157 | static ImageSurface is, isWrong; |
158 | static long isWrongLast; |
159 | static RGBImage img; |
160 | static new HashMap<Rect, Int> words; |
161 | static L<Rect> solution; |
162 | volatile sbool aiMode; |
163 | static JLabel lblScore, lblTiming; |
164 | static new HashMap<Class, AI> ais; |
165 | |
166 | p-substance {
|
167 | thread { loadBinarySnippet(#1004373); } // preload applause animation
|
168 | nextImage(); |
169 | addToWindow(is, withMargin(lblScore = jcenteredBoldLabel("Your score: 0 of 0")));
|
170 | for (final Class c : myNonAbstractClassesImplementing(AI)) {
|
171 | final S name = shortClassName(c); |
172 | final JButton btn = jbutton(name); |
173 | onClick(btn, r {
|
174 | if (aiMode) ret; |
175 | btn.setText(name + " Running..."); |
176 | thread {
|
177 | Game game = testAI(c, voidfunc(Game game) {
|
178 | if (game.step < 50 || (game.step % 10) == 0 || game.step == rounds) {
|
179 | S text = name + " scored " + game.points + " of " + game.step; |
180 | if (game.error != null) |
181 | text += " - ERROR: " + game.error; |
182 | setText_noWait(btn, text); |
183 | } |
184 | }); |
185 | } |
186 | }); |
187 | addToWindow(is, withMargin(btn)); |
188 | } |
189 | addToWindow(is, lblTiming = jCenteredLabel(; |
190 | titlePopupMenuItem(is, "Restart AIs", r { clearMapWithCleanUp(ais); });
|
191 | addToWindow(is, withMargin(jbutton("Restart AIs", r { clearMapWithCleanUp(ais); })));
|
192 | |
193 | packFrame(is); |
194 | setFrameWidth(is, 400); |
195 | centerTopFrame(is); |
196 | hideConsole(); |
197 | } |
198 | |
199 | svoid nextImage {
|
200 | RGBImage img = rgbImage(Color.white, w, h); |
201 | words.clear(); |
202 | new L<Rect> taken; |
203 | for i to numbers: {
|
204 | int num = random(10); |
205 | S s = str(num); |
206 | RGB color = new RGB(random(0.5), random(0.5), random(0.5)); |
207 | renderText_fg.set(color.getColor()); |
208 | BufferedImage ti = renderText(font, fontSize, s); |
209 | Rect r; |
210 | int safety = 0; |
211 | do {
|
212 | r = randomRect(w, h, border, ti.getWidth(), ti.getHeight()); |
213 | if (r == null || ++safety >= 1000) fail("Image too small: \*ti.getWidth()*/*\*ti.getHeight()*/ > \*w*/*\*h*/");
|
214 | } while (anyRectOverlaps(taken, r)); |
215 | rgbCopy(ti, img, r.x, r.y); |
216 | words.put(r, num); |
217 | taken.add(growRect(r, numberMargin)); |
218 | } |
219 | solution = keysWithBiggestValue(words); |
220 | |
221 | main.img = img; |
222 | if (aiMode) ret; // occasional updates only when AI is running |
223 | showTheImage(); |
224 | } |
225 | |
226 | svoid showTheImage {
|
227 | bool first = is == null; |
228 | is = showZoomedImage_centered(is, img, "Click On The Highest Number!", 1.5); |
229 | if (first) {
|
230 | onLeftClick(is, voidfunc(Pt p) {
|
231 | ++clicks; |
232 | if (anyRectContains(solution, is.pointFromComponentCoordinates(p))) {
|
233 | ++points; |
234 | nextImage(); |
235 | } else if (alwaysNewImage) nextImage(); |
236 | lblScore.setText(print("Your score: " + points + " of " + clicks));
|
237 | }); |
238 | disableImageSurfaceSelector(is); |
239 | |
240 | // animate if idle |
241 | awtEvery(is, 1000, r {
|
242 | if (!aiMode && isInForeground(is) && !mouseInComponent(is)) |
243 | nextImage(); |
244 | }); |
245 | |
246 | // show current image occasionally when AI is running |
247 | awtEvery(is, 1000/fps, r {
|
248 | if (aiMode) showTheImage(); |
249 | }); |
250 | } |
251 | } |
252 | |
253 | // AI stuff |
254 | |
255 | sclass Game extends GameForAI {
|
256 | int points, step; |
257 | Pt submitted; |
258 | Throwable error; |
259 | |
260 | RGBImage getImage() { ret img; }
|
261 | |
262 | L<Rect> submit(Pt p) {
|
263 | if (submitted != null) fail("No multi-submit please");
|
264 | submitted = p == null ? new Pt(-9, -9) : p; |
265 | if (p != null && anyRectContains(solution, p)) {
|
266 | ++points; |
267 | if (!alwaysNewImage) nextImage(); |
268 | } |
269 | ret solution; |
270 | } |
271 | } |
272 | |
273 | static Game scoreAI(AI ai, O onScore) {
|
274 | aiMode = true; |
275 | final long start = sysNow(); |
276 | try {
|
277 | final new Game game; |
278 | setOpt(ai, +game); |
279 | while (game.step < rounds) {
|
280 | ++game.step; |
281 | ++ai.steps; |
282 | game.submitted = null; |
283 | int points = game.points; |
284 | RGBImage image = img; |
285 | try {
|
286 | setOpt(ai, +image); |
287 | ai.go(); |
288 | } catch e {
|
289 | if (game.error == null) { // print first error to console
|
290 | showConsole(); |
291 | printStackTrace(e); |
292 | } |
293 | game.error = e; |
294 | } finally {
|
295 | setOpt(ai, image := null); |
296 | } |
297 | if (points == game.points && hasElapsed(isWrongLast, 50)) {
|
298 | isWrongLast = sysNow(); |
299 | bool first = isWrong == null; |
300 | isWrong = showImage(isWrong, "Last Blunder", rgbMarkPoint(image, game.submitted, Color.red, 3)); |
301 | if (first) {
|
302 | setFrameWidth(isWrong, 230); |
303 | moveToTopRightCorner(isWrong); |
304 | moveFrameDown(isWrong, 100); |
305 | } |
306 | } |
307 | pcallF(onScore, game); |
308 | if (alwaysNewImage) nextImage(); |
309 | } |
310 | print("AI " + shortClassName(ai) + " points after " + rounds + " rounds: " + game.points);
|
311 | ai.done(); |
312 | if (game.points >= rounds) thread { showAnimationInTopLeftCorner(#1004373, game.points + " of " + rounds + " points!!", 3.0); }
|
313 | ret game; |
314 | } finally {
|
315 | aiMode = false; |
316 | awt {
|
317 | lblTiming.setText(formatDouble(toSeconds(sysNow()-start), 1) + " s"); |
318 | nextImage(); |
319 | } |
320 | } |
321 | } |
322 | |
323 | static AI getAI(Class<? extends AI> c) {
|
324 | AI ai = ais.get(c); |
325 | if (ai == null) ais.put(c, ai = nu(c)); |
326 | ret ai; |
327 | } |
328 | |
329 | // onScore: voidfunc(Game) |
330 | static Game testAI(Class<? extends AI> c, O onScore) {
|
331 | ret scoreAI(getAI(c), onScore); |
332 | } |
Began life as a copy of #1006752
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: | #1006753 |
| Snippet name: | Second A. I. Game Simplified & Solved |
| Eternal ID of this version: | #1006753/130 |
| Text MD5: | 2e737c0b59655989c054e0c2444c7af2 |
| Transpilation MD5: | 8120804f7ea57b2990fbcfd34691461d |
| Author: | stefan |
| Category: | javax / gui |
| Type: | JavaX source code |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2017-02-03 23:58:17 |
| Source code size: | 9723 bytes / 332 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 956 / 1467 |
| Version history: | 129 change(s) |
| Referenced in: | [show references] |