Download Jar. Uses 1177K of libraries. Click here for Pure Java version (36804L/240K).
1 | !7 |
2 | |
3 | set flag Reparse. |
4 | |
5 | set flag OurSyncCollections. // allow to run on newer JDKs without illegal-access command line flags |
6 | |
7 | import javax.swing.filechooser.*; |
8 | |
9 | !include #1031138 // Smarty AI Include |
10 | |
11 | sbool debugValues = false; // debug sensor output |
12 | static int defaultSpacing = 10, spacing; |
13 | static JFrame mainFrame; |
14 | static LL<JCell> gridComponents; |
15 | static JComponent mainGrid; |
16 | static JCheckBoxMenuItem miShowLocations; |
17 | static SingleComponentPanel scpMainGrid, scpVisionConfig, scpWheelsConfig, scpCurrentSmarty, |
18 | scpStimuliAndResponse; |
19 | static JFrame historyFrame, memoryFrame; |
20 | static JSpinner worldSizeSpinner; |
21 | static JTextArea historyTextArea1, historyTextArea2; |
22 | static JTextArea taSensorValues, taDeviceValues; |
23 | |
24 | // originally: BinonDisplay.ObjList.Text |
25 | static JTextArea memoryTextArea1; |
26 | |
27 | // originally: BinonDisplay.ChngResults.Text |
28 | static JTextArea memoryTextArea2; |
29 | |
30 | static Smarty smarty; // AI instance |
31 | |
32 | static Q smartyQ = startQ("Smarty Q"); // queue for Smarty operations
|
33 | |
34 | sS wallSymbol = unicode_blackSquare(), noWallSymbol = unicode_dottedSquare(); |
35 | |
36 | static Color lightBlue = colorFromHex("4169e1");
|
37 | |
38 | sS locationLetters = charRange('A', 'Z') + "[\\]^_`" + charRange('a', 'z') + charRange(123, 128);
|
39 | sS smartyUnicode = unicode_slightlySmilingFace(); |
40 | static int smartyFontSize = 40; |
41 | |
42 | sS windowsFontID = #1400468; |
43 | sS emojiFontID = #1400470; |
44 | sS frameIconID = #1102983; |
45 | sS monospacedFontID = /*#1400479*/#1400483; |
46 | static double monospacedFontSize = 12; |
47 | |
48 | sbool smartyBrainPersistence = false; |
49 | |
50 | sS smartyImageID = #1102987; |
51 | sS helpTextID = #1031105; |
52 | |
53 | sS worldFileExtension = "WLD"; |
54 | sS bodyFileExtension = "BDY"; |
55 | |
56 | sS historyHelp = unindent_mls([[ |
57 | A percept is the stimulus or simultaneous combination of stimuli observed. |
58 | An action is the response or simultaneous combination of responses produced. |
59 | Binon # numbers refer to the binons in memory that represent the percepts, actions, expectations, and perceptual or action sequences. |
60 | P = Percept, E = Expectation, PP = Perceptual sequence A = Action, AA = Action sequence |
61 | Read the paper: "The Perception-Action Hierarchy and its Implementation Using Binons (Binary Neurons)" on the www.adaptroninc.com website for more information. |
62 | ]]); |
63 | |
64 | // translate Smarty's windows characters to unicode |
65 | static SS winToUnicode = litmap( |
66 | Smarty.Smarty, unicode_slightlySmilingFace(), |
67 | Smarty.UpArrow, unicode("2191"),
|
68 | Smarty.LeftArrow, unicode("2190"),
|
69 | Smarty.RightArrow, unicode("2192"),
|
70 | Smarty.DownArrow, unicode("2193"),
|
71 | Smarty.Wall, unicode_blackVerticalRectangle(), |
72 | Smarty.EmptySquare, unicode_whiteVerticalRectangle(), |
73 | Smarty.chr(Smarty.TurnRght), unicode("21B1"),
|
74 | Smarty.chr(Smarty.TurnLft), unicode("21B0"),
|
75 | Smarty.chr(Smarty.TurnArnd), unicode("21B7"),
|
76 | Smarty.chr(254), unicode_blackSmallSquare(), // "Novel" |
77 | ); |
78 | |
79 | sbool showTabs = true; |
80 | |
81 | static int defaultWorldSize = 7, maxWorldSize = 8; |
82 | |
83 | static ReliableSingleThread rstUpdateChngResults = rstWithPreDelay(250, r {
|
84 | setText(memoryTextArea2, winToUnicode(state.binonDisplayChngResults)); |
85 | }); |
86 | |
87 | svoid rearrangeLetters {
|
88 | int iLetter = 0; |
89 | for (int y = 0; y < state.gridRows; y++) |
90 | for (int x = 0; x < state.gridCols; x++) {
|
91 | JCell cell = getCell(x, y); |
92 | if (cell.obstacle()) |
93 | cell.letter = ' '; |
94 | else |
95 | cell.letter = locationLetters.charAt(iLetter++); |
96 | } |
97 | } |
98 | |
99 | sclass VisionMode {
|
100 | sS nextSquare = "next square"; |
101 | sS distanceToWall = "distance to wall"; |
102 | sS wallOrNot = "wall or not"; |
103 | } |
104 | |
105 | sclass CameraDirection {
|
106 | sS down = "down"; |
107 | sS left = "left"; |
108 | sS right = "right"; |
109 | sS inFront = "in front"; |
110 | sS behind = "behind"; |
111 | |
112 | static LS all = ll(down, left, right, inFront, behind); |
113 | } |
114 | |
115 | concept SmartyBody {
|
116 | S name = "Smarty0"; |
117 | Set<S> cameraDirections = litset(CameraDirection.down); |
118 | S visionMode = VisionMode.nextSquare; // see VisionMode |
119 | Set<S> wheels = litset("MoveForward", "MoveLeft", "MoveRight", "MoveBackward");
|
120 | bool changed; // changed w.r.t. file |
121 | bool used; // used in Smarty execution |
122 | |
123 | // for saving |
124 | S wheelsFlag(S flag) { ret wheels.contains(flag) ? "1" : "0"; }
|
125 | |
126 | void userCausedChange {
|
127 | print("Body: User caused change");
|
128 | changed = true; |
129 | change(); |
130 | } |
131 | } |
132 | |
133 | concept State {
|
134 | float fontScale = 1.5f; |
135 | S worldName = "Empty"; |
136 | int gridRows = defaultWorldSize, gridCols = defaultWorldSize; // actually these are always identical, could merge into one |
137 | bool showLocations; |
138 | bool worldChanged; |
139 | int startX, startY; // Smarty's start position |
140 | int smartyX, smartyY; |
141 | S smartyDirection = Smarty.Smarty; // which way Smarty is looking - this or smarty.LeftArrow etc. |
142 | Rect selection = rect(1, 1, 1, 1); |
143 | Pt cursorDirection = pt(1, 0); |
144 | new BitSet obstacles; |
145 | |
146 | S history1 = "", history2 = "", memory1 = "", sensorValuesText = "", deviceValuesText = ""; |
147 | S binonDisplayChngResults = ""; // memory2 |
148 | |
149 | new Ref<SmartyBody> body; |
150 | |
151 | // value is just true |
152 | Map<File, Bool> recentWorldFiles = synchronizedMRUCache(5); |
153 | Map<File, Bool> recentBodyFiles = synchronizedMRUCache(5); |
154 | |
155 | void setSelection(Rect r) {
|
156 | if (!cset_trueIfChanged(this, selection := r)) ret; |
157 | if (selection.h == 1 && selection.w > 1) _setField(cursorDirection := pt(1, 0)); |
158 | else if (selection.w == 1 && selection.h > 1) _setField(cursorDirection := pt(0, 1)); |
159 | repaintGrid(); |
160 | } |
161 | |
162 | void clearSelectedArea {
|
163 | fillSelection(false); |
164 | } |
165 | |
166 | void invertSelection {
|
167 | JCell cell1 = getCell(selection.x, selection.y); |
168 | fillSelection(!cell1.obstacle()); |
169 | } |
170 | |
171 | void fillSelection(bool b) {
|
172 | for (Pt p : pointsInRect(selection)) |
173 | if (!(b && state.smartyX == p.x && state.smartyY == p.y)) // don't put an obstacle over Smarty |
174 | getCell(p.x, p.y).setObstacle(b); |
175 | rearrangeLetters(); |
176 | moveCursor(); |
177 | } |
178 | |
179 | void moveCursor {
|
180 | setCursor(selection.x+cursorDirection.x, selection.y+cursorDirection.y); |
181 | } |
182 | |
183 | void setCursor(int x, int y) {
|
184 | setSelection(rect(mod(x, gridCols), mod(y, gridRows), 1, 1)); |
185 | } |
186 | |
187 | void moveCursor(int dx, int dy) {
|
188 | _setField(cursorDirection := pt(dx, dy)); |
189 | setCursor(selection.x+cursorDirection.x, selection.y+cursorDirection.y); |
190 | } |
191 | |
192 | void placeSmarty {
|
193 | getCell(selection.x, selection.y).setObstacle(false); |
194 | cset(state, startX := selection.x, startY := selection.y); |
195 | moveSmarty(selection.x, selection.y); |
196 | moveCursor(); |
197 | } |
198 | |
199 | void moveSmarty(int x, int y) {
|
200 | if (!inRange(x, 0, gridCols) || !inRange(y, 0, gridRows)) |
201 | fail("Smarty position not in range: " + x + "/" + y);
|
202 | |
203 | if (cset_trueIfChanged(this, smartyX := x, smartyY := y)) {
|
204 | cset(this, worldChanged := true); |
205 | repaintGrid(); |
206 | } |
207 | } |
208 | |
209 | void moveSmartyRelative(int x, int y) {
|
210 | moveSmarty(smartyX+x, smartyY+y); |
211 | } |
212 | } // end of State |
213 | |
214 | static State state; |
215 | |
216 | sclass JCell > JComponent {
|
217 | int x, y; |
218 | char letter; |
219 | |
220 | *(int *x, int *y) {}
|
221 | |
222 | public void paint(Graphics _g) {
|
223 | Graphics2D g = cast _g; |
224 | int w = getWidth(), h = getHeight(); |
225 | Color color = Color.white; |
226 | if (state.selection.contains(x, y)) color = lightBlue; |
227 | else if (obstacle()) color = Color.black; |
228 | |
229 | fillRect(g, 0, 0, w, h, color); |
230 | |
231 | if (state.showLocations && !obstacle()) {
|
232 | temp tempSetFont(g, loadFont_cached(windowsFontID)); |
233 | drawTextWithTopLeftCornerAt(g, str(letter), Pt(2, 0), Color.black); |
234 | } |
235 | |
236 | if (state.smartyX == x && state.smartyY == y) {
|
237 | temp tempSetFontSize(g, smartyFontSize); |
238 | /*temp tempSetFont(g, loadFont_cached(emojiFontID)); |
239 | drawCenteredText(g, smartyUnicode, 0, 0, w, h, Color.black);*/ |
240 | double size = 0.6; |
241 | int dx = iround((1-size)/2*w); |
242 | int dy = iround((1-size)/2*h); |
243 | if (eq(state.smartyDirection, smarty.Smarty)) |
244 | drawScaledImage(g, loadImage2_cached(smartyImageID), rectFromPoints(dx, dy, w-dx, h-dy)); |
245 | else {
|
246 | //temp tempSetFont(g, loadFont_cached(windowsFontID)); |
247 | S icon = lookupOrKeep(winToUnicode, state.smartyDirection); |
248 | drawCenteredText(g, icon, 0, 0, w, h, Color.black); |
249 | } |
250 | } |
251 | } |
252 | |
253 | int index() { ret y*state.gridCols+x; }
|
254 | bool obstacle() { ret main contains(state.obstacles, index()); }
|
255 | void setObstacle(bool b) {
|
256 | if (setBit_trueIfChanged(state.obstacles, index(), b)) {
|
257 | cset(state, worldChanged := true); |
258 | state.change(); |
259 | } |
260 | } |
261 | |
262 | {
|
263 | addMouseListener(new MouseAdapter {
|
264 | public void mousePressed(MouseEvent e) {
|
265 | main requestFocus(mainGrid); |
266 | if (!isLeftButton(e)) ret; |
267 | state.setSelection(new Rect(x, y, 1, 1)); |
268 | } |
269 | }); |
270 | |
271 | addMouseMotionListener(new MouseMotionAdapter {
|
272 | public void mouseDragged(MouseEvent e) {
|
273 | //_print("Drag in " + x + "/" + y + ": " + e.getPoint());
|
274 | Component dest = componentAtScreenLocationInWindow(mainFrame, e); |
275 | if (dest cast JCell) {
|
276 | //_print("Target: " + dest);
|
277 | state.setSelection(rectFromPointsInclusiveSorted(x, y, dest.x, dest.y)); |
278 | } |
279 | } |
280 | }); |
281 | } |
282 | |
283 | toString { ret x + "/" + y; }
|
284 | } |
285 | |
286 | static JCell getCell(int x, int y) {
|
287 | ret gridComponents.get(y).get(x); |
288 | } |
289 | |
290 | static JCell smartyCell() {
|
291 | ret getCell(state.smartyX, state.smartyY); |
292 | } |
293 | |
294 | sbool inGrid(int x, int y) {
|
295 | ret inRange(y, state.gridRows) && inRange(x, state.gridCols); |
296 | } |
297 | |
298 | svoid makeMainGrid {
|
299 | gridComponents = map(iotaZeroList(state.gridRows), y |
300 | -> map(iotaZeroList(state.gridCols), x |
301 | -> new JCell(x, y))); |
302 | mainGrid = setFocusable(setBackground(Color.black, hvgrid(gridComponents, 1))); |
303 | scpMainGrid.setComponent(mainGrid); |
304 | rearrangeLetters(); |
305 | } |
306 | |
307 | // always clears the world |
308 | svoid setWorldSize(int size) {
|
309 | state.obstacles.clear(); |
310 | state.gridCols = state.gridRows = size; |
311 | setSpinnerValue(worldSizeSpinner, size); |
312 | state.selection = rect(1, 1); |
313 | cset(state, startX := 0, startY := 0); |
314 | state.moveSmarty(0, 0); |
315 | cset(state, worldChanged := false); |
316 | state.change(); |
317 | makeMainGrid(); |
318 | resetSmarty(); |
319 | } |
320 | |
321 | svoid repaintGrid() {
|
322 | repaint(mainGrid); |
323 | } |
324 | |
325 | // add more functions here |
326 | |
327 | ifndef NoMainMethod |
328 | p { smartyMain(); }
|
329 | endifndef |
330 | |
331 | svoid smartyMain {
|
332 | System.out.println("Main class: " + strWithIdentityHashCode(mc()) + ", class loader: " + getClassLoader(mc()));
|
333 | |
334 | autoRestart(2.0); |
335 | |
336 | // print all vm bus msgs from concepts |
337 | //vmBus_snoopToPrint((msg, arg) -> firstOfArrayOrSame(arg) instanceof Concepts); |
338 | |
339 | setProgramDir(print("Using directory: ", mainDir()));
|
340 | logProgramOutput(); |
341 | _handleException_showThreadCancellations = true; |
342 | |
343 | if (!isDevVersion()) hideConsole(); |
344 | else veryBigConsole(); |
345 | |
346 | db(); |
347 | uniq(SmartyBody); // make at least one instance |
348 | state = uniq(State); |
349 | smarty = uniq(Smarty); |
350 | initSmarty(); |
351 | if (!state.body.has()) cset(state, body := conceptWhere(SmartyBody)); // default body |
352 | //cset(state.body, used := false); // XXX |
353 | |
354 | // prep GUI |
355 | |
356 | jtattoo_mcWin(); // styling |
357 | //set swingFontScale_debug; |
358 | updateFontScale(state.fontScale); // scaling |
359 | disableSpaceBarForAllButtons(); // no space bar for buttons |
360 | |
361 | loadLibrary(windowsFontID); |
362 | defaultFrameIcon(frameIconID); |
363 | mainFrame = showFrame("Smarty");
|
364 | //exitOnClose(mainFrame); |
365 | onWindowClosing(mainFrame, rThread {
|
366 | cleanUp(mc()); // proper clean-up for standalone mode |
367 | cleanKillVM(); |
368 | }); |
369 | |
370 | historyTextArea1 = monospaced(uneditableBlackTextArea_noUndo()); |
371 | historyTextArea2 = monospaced(uneditableBlackTextArea_noUndo()); |
372 | memoryTextArea1 = /*withTypeWriterFont*/monospaced(uneditableBlack(swing(() -> new JLineHeightTextArea(0.8)))); |
373 | memoryTextArea2 = monospaced(uneditableBlackTextArea_noUndo(winToUnicode(state.binonDisplayChngResults))); |
374 | |
375 | makeMenus(); |
376 | |
377 | registerCtrlKey(mainFrame, KeyEvent.VK_N, "New world", r { print("new") });
|
378 | registerCtrlKey(mainFrame, KeyEvent.VK_R, "Retrieve world", r {});
|
379 | registerCtrlKey(mainFrame, KeyEvent.VK_S, "Save world", r {});
|
380 | |
381 | addMenu(mainFrame, "View", |
382 | miShowLocations = jCheckBoxMenuItem("Locations (Ctrl+L)", state.showLocations, b -> {
|
383 | cset(state, showLocations := b); |
384 | repaintGrid(); |
385 | }), |
386 | jMenu("UI Zoom",
|
387 | "100%", r { uiZoom(100) },
|
388 | "112%", r { uiZoom(112) },
|
389 | "125%", r { uiZoom(125) },
|
390 | "140%", r { uiZoom(140) }),
|
391 | |
392 | "---", |
393 | "Self-Test", rThread selfTest, |
394 | "Console", r activateConsole, |
395 | ); |
396 | |
397 | registerCtrlKey(mainFrame, KeyEvent.VK_L, "Locations", r {
|
398 | cset(state, showLocations := !state.showLocations); |
399 | setChecked(miShowLocations, state.showLocations); |
400 | repaintGrid(); |
401 | }); |
402 | |
403 | JMenuBar menuBar = getMenuBar(mainFrame); |
404 | JMenuItem helpItem = jMenuItem("Help F1", rThread showHelp);
|
405 | /*print(minSize := getMinimumSize(helpItem)); |
406 | print(preferredSize := getPreferredSize(helpItem));*/ |
407 | addMenuItem(menuBar, jPreferredWidthToMaxWidth(helpItem)); |
408 | addAndRevalidate(menuBar, jHorizontalGlue()); // spacer |
409 | |
410 | registerFunctionKey(mainFrame, 1, rThread showHelp); |
411 | |
412 | registerKeyCode(mainFrame, KeyEvent.VK_SPACE, r { state.invertSelection() });
|
413 | registerKeyCode(mainFrame, KeyEvent.VK_UP, r { state.moveCursor(0, -1) });
|
414 | registerKeyCode(mainFrame, KeyEvent.VK_LEFT, r { state.moveCursor(-1, 0) });
|
415 | registerKeyCode(mainFrame, KeyEvent.VK_DOWN, r { state.moveCursor(0, 1) });
|
416 | registerKeyCode(mainFrame, KeyEvent.VK_RIGHT, r { state.moveCursor(1, 0) });
|
417 | |
418 | // react to any letter from A to Z |
419 | for (int key = KeyEvent.VK_A; key <= KeyEvent.VK_Z; key++) |
420 | registerKeyCode(mainFrame, key, r { state.placeSmarty() });
|
421 | |
422 | worldSizeSpinner = jSpinner(state.gridCols, 1, maxWorldSize); |
423 | onChange(worldSizeSpinner, r {
|
424 | int size = intFromSpinner(worldSizeSpinner); |
425 | if (state.gridCols != size) {
|
426 | if (state.worldChanged) {
|
427 | int result = swingShowConfirmDialog(mainFrame, |
428 | "World has changed! - Save it before resizing?", "Smarty", |
429 | JOptionPane.YES_NO_CANCEL_OPTION); |
430 | if (result == JOptionPane.YES_OPTION) {
|
431 | saveWorldDialog(r { newWorldWithoutConfirmation(size) });
|
432 | ret; |
433 | } else if (result == JOptionPane.CANCEL_OPTION) {
|
434 | setSpinnerValue(worldSizeSpinner, state.gridCols); |
435 | ret; |
436 | } |
437 | } |
438 | |
439 | newWorldWithoutConfirmation(size); |
440 | } |
441 | }); |
442 | |
443 | scpCurrentSmarty = singleComponentPanel(); |
444 | |
445 | JComponent middleArea = westAndCenterWithMargin(spacing, |
446 | jvstackWithSpacing(spacing, |
447 | withTitle("World size (max=\*maxWorldSize*/)", worldSizeSpinner),
|
448 | jbutton("Clear Selected Area", rThread { state.clearSelectedArea() }),
|
449 | withTitle("Current world", disableTextField(jLiveValueTextField(conceptFieldLiveValue worldName(state)))),
|
450 | showTabs ? null : fontSizePlus(2, setForeground(Color.ORANGE, jCenteredLabel("Design or Select a body for Smarty"))),
|
451 | showTabs ? null : jbutton("Design or Select Smarty's Body", r showSmartyConfig),
|
452 | withTitle("Current Smarty", scpCurrentSmarty),
|
453 | ), |
454 | jvgridWithSpacing(spacing, |
455 | withTitle(monospaced(jLabel("Sensors: Values: are:")), taSensorValues = monospaced(uneditableBlackTextArea_noUndo())),
|
456 | withTitle(monospaced(jLabel("Devices: Values: are:")), taDeviceValues = monospaced(uneditableBlackTextArea_noUndo())),
|
457 | ) |
458 | ); |
459 | |
460 | JComponent controlArea = northAndCenterWithMargin(spacing, |
461 | vstackWithSpacing( |
462 | fontSizePlus(2, setForeground(Color.blue, jlabel("Design the World - Read the Help F1"))),
|
463 | jMinHeight(swingScale(200), middleArea)), |
464 | jCenteredSection("Run Smarty",
|
465 | jflow( |
466 | jbutton("Go / Continue", rThread goCmd),
|
467 | jButton("See History", r showHistory),
|
468 | jbutton("See Memory", r showMemory),
|
469 | jbutton("Reset", r resetSmarty),
|
470 | jbutton("EXIT", rThread killVM),
|
471 | )) |
472 | ); |
473 | |
474 | scpMainGrid = singleComponentPanel(); |
475 | makeMainGrid(); |
476 | |
477 | var mainPanel = westAndCenterWithMargins(spacing, |
478 | jvstackWithSpacing(spacing, |
479 | jFixedSize(500, scpMainGrid), |
480 | scpStimuliAndResponse = singleComponentPanel() |
481 | ), |
482 | controlArea); |
483 | |
484 | if (showTabs) {
|
485 | scpVisionConfig = singleComponentPanel(); |
486 | scpWheelsConfig = singleComponentPanel(); |
487 | updateTabs(); |
488 | setFrameContents(mainFrame, jtabs( |
489 | "Smarty", mainPanel, |
490 | "Vision", scpVisionConfig, |
491 | "Wheels", scpWheelsConfig, |
492 | )); |
493 | } else |
494 | setFrameContents(mainFrame, mainPanel); |
495 | |
496 | centerPackFrame(mainFrame); |
497 | |
498 | // set minimum width |
499 | jMinWidth_pure(mainFrame, max(1000, swingScale(800))); |
500 | centerFrameWithMinWidth(mainFrame); |
501 | |
502 | // set min frame height |
503 | jMinHeight_pure(mainFrame, getHeight(mainFrame)); |
504 | |
505 | // disable height changes entirely (not good, may cut off at the bottom) |
506 | //frameMaxHeight(mainFrame, getHeight(mainFrame)); |
507 | |
508 | //smarty.World.Update_View(); |
509 | setText(historyTextArea1, winToUnicode(state.history1)); |
510 | setText(historyTextArea2, winToUnicode(state.history2)); |
511 | setText(memoryTextArea1, winToUnicode(state.memory1)); |
512 | setText(taSensorValues, winToUnicode(state.sensorValuesText)); |
513 | setText(taDeviceValues, winToUnicode(state.deviceValuesText)); |
514 | |
515 | enableBodyControls(!state.body->used); |
516 | |
517 | if (!smartyBrainPersistence) |
518 | resetSmarty(); |
519 | |
520 | if (!isDevVersion()) showHelp(); |
521 | else {
|
522 | //goCmd(); |
523 | //selfTest(); |
524 | } |
525 | } // end of main function |
526 | |
527 | sbool isDevVersion() {
|
528 | ret isProgramID(#1031104); |
529 | } |
530 | |
531 | svoid updateTabs {
|
532 | scpVisionConfig.setComponent(visionConfigPanel(state.body!)); |
533 | scpWheelsConfig.setComponent(wheelsConfigPanel(state.body!)); |
534 | scpCurrentSmarty.setComponent(disableTextField(jLiveValueTextField(conceptFieldLiveValue name(state.body!)))); |
535 | updateFrameTitles(); |
536 | } |
537 | |
538 | svoid enableBodyControls(bool b) {
|
539 | var panels = ll(scpVisionConfig, scpWheelsConfig); |
540 | for (var c : concatMap(panel -> allChildrenOfType JComponent(panel), panels)) |
541 | if (isInstanceOfAny(c, JCheckBox.class, JRadioButton.class, JTextField.class) |
542 | && !c instanceof BodyNameField) |
543 | setEnabled(c, b); |
544 | |
545 | // Modify body button is enabled iff controls are not enabled |
546 | for (var c : concatMap(panel -> allChildrenOfType ModifyBodyButton(panel), panels)) |
547 | setEnabled(c, !b); |
548 | } |
549 | |
550 | svoid showHelp() {
|
551 | S text = loadSnippet(helpTextID); |
552 | S heading = firstLine(text); |
553 | trim(dropFirstLine(text)); |
554 | showCenterFrame(swingScale(650), swingScale(500), heading, makeUneditableWithTextColor(Color.black, wordWrapTextArea(text))); |
555 | } |
556 | |
557 | // run in Swing thread |
558 | svoid showHistory {
|
559 | Font ttFont = loadFont_cached(monospacedFontID, 12), helpFont = sansSerifFont(13); |
560 | if (historyFrame == null) |
561 | historyFrame = getFrame(showCenterFrame(maxPt(pt(800, 600), scalePt(600, 350, swingFontScale())), |
562 | "History", |
563 | withMargin(centerAndSouthWithMargin(spacing, |
564 | centerAndSouthWithMargin( |
565 | historyTextArea1, |
566 | westAndCenterWithMargin(spacing, setFont(ttFont, topAlignLabel(jMultiLineLabel( |
567 | linesLL("Step #", "Percept", "Binon #", "", "Expect", "Binon #",
|
568 | "", "Action", "Binon #", "", "Action", "Binon #", "")))), |
569 | setFont(ttFont, historyTextArea2)) |
570 | ), |
571 | centerAndEastWithMargin( |
572 | setFont(helpFont, jMultiLineLabel(historyHelp)), |
573 | jvstackWithSpacing( |
574 | jButton("See World", r showWorld),
|
575 | jButton("See Memory", r showMemory))
|
576 | ))))); |
577 | else |
578 | frameToFront(historyFrame); |
579 | updateFrameTitles(); |
580 | } |
581 | |
582 | // run in Swing thread |
583 | svoid showMemory {
|
584 | Font ttFont = typeWriterFont(12), helpFont = sansSerifFont(13); |
585 | |
586 | S Interestng; |
587 | if (smarty.InterestLevels == 3) |
588 | Interestng = smarty.IntSymb(smarty.INTERESTING) + "=Interesting, "; |
589 | else // Only 2 interest levels |
590 | Interestng = ""; |
591 | |
592 | S IntSymbol = " " + smarty.IntSymb(smarty.NOVEL) + " = Novel, " + Interestng + smarty.IntSymb(smarty.FAMILIAR) + " = Familiar"; |
593 | |
594 | // originally: BinonDisplay.ObjListTitle.Caption |
595 | S title = "Bn# OL Ty TL BL TR BR V L R In LQ RQ Pattern " |
596 | + " l = Left target, r = Right target," + IntSymbol; |
597 | |
598 | if (memoryFrame == null) |
599 | memoryFrame = getFrame(showCenterFrame(scalePt(600, 350, swingFontScale()), |
600 | "Smarty's Memory", |
601 | jvsplit(0.5, 100, |
602 | centerAndEastWithMargins( |
603 | northAndCenterWithMargin( |
604 | setFont(ttFont, jLabel(title)), |
605 | setFont(ttFont, memoryTextArea1)), |
606 | jvstackWithSpacing( |
607 | jButton("See World", r showWorld),
|
608 | jButton("See History", r showHistory))
|
609 | ), |
610 | memoryTextArea2, |
611 | ) |
612 | )); |
613 | else |
614 | frameToFront(memoryFrame); |
615 | updateFrameTitles(); |
616 | } |
617 | |
618 | svoid showWorld {
|
619 | frameToFront(mainFrame); |
620 | } |
621 | |
622 | static JRadioButton visionModeRadioButton(SmartyBody body, ButtonGroup buttonGroup, S visionMode, S text) {
|
623 | var rb = jradiobutton(buttonGroup, text, eq(body.visionMode, visionMode)); |
624 | onChange(rb, r { if (isChecked(rb)) { cset(body, +visionMode); body.userCausedChange(); } });
|
625 | ret rb; |
626 | } |
627 | |
628 | sclass ModifyBodyButton extends JButton {
|
629 | *() {
|
630 | super("Modify Smarty's Body");
|
631 | main addActionListener(this, r modifyBody); |
632 | } |
633 | } |
634 | |
635 | // enable the controls to edit the body, after confirmation |
636 | svoid modifyBody {
|
637 | if (state.body->used) {
|
638 | if (!confirmOKCancel("Modifying Smarty's body will reset its state. Do you wish to continue?"))
|
639 | ret; |
640 | resetSmarty(); |
641 | cset(state.body, used := false); |
642 | } |
643 | enableBodyControls(true); |
644 | } |
645 | |
646 | sclass BodyNameField extends JTextField {
|
647 | *() {
|
648 | setEnabled(false); |
649 | } |
650 | } |
651 | |
652 | static JComponent bodyNamePanel(SmartyBody body) {
|
653 | SimpleLiveValue<S> lv = conceptFieldLiveValue name(body); |
654 | lv.onChange(r { body.userCausedChange() });
|
655 | ret hstackWithSpacing( |
656 | jMinWidth(swingScale(250), withLabel("Body name:",
|
657 | bindTextComponentToLiveValue(lv, swing(() -> new BodyNameField)))), |
658 | swing(() -> new ModifyBodyButton)); |
659 | } |
660 | |
661 | static JComponent visionConfigPanel(SmartyBody body) {
|
662 | var buttonGroup = buttonGroup(); |
663 | ret northAndCenterWithMargins(spacing, |
664 | bodyNamePanel(body), |
665 | westAndCenterWithMargin(spacing, |
666 | jCenteredSection("Camera",
|
667 | withLeftMargin(spacing, jvstackWithSpacing(spacing, |
668 | itemPlus(jlabel("Select the camera directions"),
|
669 | map(CameraDirection.all, direction -> {
|
670 | var cb = jCheckBox(direction, body.cameraDirections.contains(direction)); |
671 | onChange(cb, r { addOrRemove(body.cameraDirections, direction, isChecked(cb)); body.userCausedChange(); });
|
672 | ret cb; |
673 | }))))), |
674 | |
675 | jCenteredSection("Vision mode",
|
676 | jvstack( |
677 | withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS(replaceSymbols([[ |
678 | Square locations are identified with a letter. |
679 | Looking down provides the letter of the current square. |
680 | Looking in other directions provides the letter in the next square |
681 | depending on the direction Smarty is facing. |
682 | If it is a wall then the symbolic stimulus is a $wallSymbol |
683 | ]])))), |
684 | visionModeRadioButton(body, buttonGroup, VisionMode.nextSquare, |
685 | "Looking at the next square (symbolic values = letter in square)"), |
686 | verticalStrut(20), |
687 | |
688 | withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS([[ |
689 | Looking at the distance to the nearest wall will provide the |
690 | number of squares from the current position to the wall in |
691 | the direction the camera is facing. A wall next to the robot |
692 | is one square away. Looking down will always return 1. |
693 | ]]))), |
694 | visionModeRadioButton(body, buttonGroup, VisionMode.distanceToWall, |
695 | "Distance to wall (magnitude values = number of squares)"), |
696 | verticalStrut(20), |
697 | |
698 | withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS([[ |
699 | Looking at the next square will either see a wall or an empty square |
700 | ]]))), |
701 | visionModeRadioButton(body, buttonGroup, VisionMode.wallOrNot, |
702 | replaceSymbols("Wall or not (symbolic values = $wallSymbol for a wall and $noWallSymbol for no wall)")),
|
703 | )))); |
704 | } |
705 | |
706 | svoid showVisionConfig(SmartyBody body) {
|
707 | showPackedFrame("Configure Smarty's Vision",
|
708 | visionConfigPanel(body)); |
709 | } |
710 | |
711 | static JCheckBox wheelsConfigCheckBox(SmartyBody body, S symbol, S text) {
|
712 | var cb = jCheckBox(text, body.wheels.contains(symbol)); |
713 | onChange(cb, r { addOrRemove(body.wheels, symbol, isChecked(cb)); body.userCausedChange(); });
|
714 | ret cb; |
715 | } |
716 | |
717 | static JComponent wheelsConfigPanel(SmartyBody body) {
|
718 | ret northAndCenterWithMargins(spacing, |
719 | bodyNamePanel(body), |
720 | vstackWithSpacing(spacing, |
721 | westAndCenterWithMargin(spacing, |
722 | jCenteredSection("Movement",
|
723 | withLeftMargin(spacing, jvstackWithSpacing( |
724 | jlabel("Select the wheel motions"),
|
725 | wheelsConfigCheckBox(body, "MoveForward", "Forward = f"), |
726 | wheelsConfigCheckBox(body, "MoveLeft", "Left = l"), |
727 | wheelsConfigCheckBox(body, "MoveRight", "Right = r"), |
728 | wheelsConfigCheckBox(body, "MoveBackward", "Backward = b"), |
729 | ))), |
730 | |
731 | jCenteredSection("Help", withLeftMargin(
|
732 | jTopLabel(hhtml(nlToBr(mls_replaceDollarVars(winToUnicode([[ |
733 | Motion in any direction will move one square. |
734 | If there is a wall in the way it will not move. A "-" indicates no motion. |
735 | The direction moved depends on the direction Smarty is facing. |
736 | Smarty will appear as a $smiley if it cannot turn. It will then always be |
737 | facing North (up) so moving right will move to the East (right). |
738 | ]]), smiley := himgForJLabel(#1102987, width := swingScale(15), height := swingScale(15), align := "middle")))))))), |
739 | |
740 | westAndCenterWithMargin(spacing, |
741 | jCenteredSection("Turning",
|
742 | withLeftMargin(spacing, vstackWithSpacing( |
743 | wheelsConfigCheckBox(body, "TurnRight", "Turn to the right = Rotate clockwise 90 degrees = " + winToUnicode(Smarty.TurnRght)), |
744 | wheelsConfigCheckBox(body, "TurnLeft", "Turn to the left = Rotate anti-clockwise 90 degrees = " + winToUnicode(Smarty.TurnLft)), |
745 | wheelsConfigCheckBox(body, "TurnAround", "Turn around = Rotate 180 degrees = " + winToUnicode(Smarty.TurnArnd)), |
746 | ))), |
747 | |
748 | jCenteredSection("Help", withLeftMargin(jMultiLineLabel(winToUnicode(mls_replaceDollarVars([[
|
749 | Turning will stay on the same square. If Smarty is able to turn then it will appear as $left, $right, $up or $down to indicate the direction it is facing. |
750 | ]], |
751 | left := Smarty.LeftArrow, |
752 | right := Smarty.RightArrow, |
753 | up := Smarty.UpArrow, |
754 | down := Smarty.DownArrow)))))), |
755 | |
756 | jCenteredSection("Sensing",
|
757 | withLeftMargin(spacing, wheelsConfigCheckBox(body, "AddAWheelSensor", "Add a wheel sensor to detect if it moved or failed because it was up against a wall")) |
758 | ) |
759 | )); |
760 | } |
761 | |
762 | svoid showWheelsConfig(SmartyBody body) {
|
763 | var buttonGroup = buttonGroup(); |
764 | showPackedFrame("Configure Smarty's Wheels",
|
765 | wheelsConfigPanel(body)); |
766 | } |
767 | |
768 | svoid showSmartyConfig {
|
769 | showPackedFrameMinWidth(400, "Design or Select a body for Smarty", |
770 | withMargin(centeredButtons( |
771 | "Vision", r { showVisionConfig(state.body!) },
|
772 | "Wheels", r { showWheelsConfig(state.body!) },
|
773 | )) |
774 | ); |
775 | } |
776 | |
777 | // e.g. $wallSymbol and $noWallSymbol |
778 | sS replaceSymbols(S s) {
|
779 | ret replaceDollarVars(s, +wallSymbol, +noWallSymbol); |
780 | } |
781 | |
782 | sS exportWorldForSaving() {
|
783 | new LS lines; |
784 | lines.add(" " + state.gridRows);
|
785 | |
786 | for (int y = 0; y < state.gridRows; y++) |
787 | for (int x = 0; x < state.gridCols; x++) {
|
788 | JCell cell = getCell(x, y); |
789 | lines.add(state.smartyX == x && state.smartyY == y ? "A" : cell.obstacle() ? "#" : " "); |
790 | } |
791 | |
792 | ret lines(lines); |
793 | } |
794 | |
795 | svoid saveWorld(File f) {
|
796 | S text = exportWorldForSaving(); |
797 | saveTextFile(f, text); |
798 | infoBox("World saved: " + fileName(f));
|
799 | cset(state, worldName := fileNameWithoutExtension(f), worldChanged := false); |
800 | addRecentWorldFile(f); |
801 | } |
802 | |
803 | svoid addRecentWorldFile(File f) swing {
|
804 | removeAndPut(state.recentWorldFiles, f, true); |
805 | state.change(); |
806 | makeMenus(); |
807 | } |
808 | |
809 | svoid addRecentBodyFile(File f) swing {
|
810 | removeAndPut(state.recentBodyFiles, f, true); |
811 | state.change(); |
812 | makeMenus(); |
813 | } |
814 | |
815 | svoid loadWorld(File f) {
|
816 | pcall-messagebox {
|
817 | LS lines = linesFromFile_list(f); |
818 | |
819 | if (eqAfterRtrim(lines(lines), exportWorldForSaving())) |
820 | ret with infoBox("World is the same as current one");
|
821 | |
822 | int i = 0; |
823 | int gridRows = parseInt(trim(lines.get(i++))); |
824 | if (gridRows < 1 || gridRows > maxWorldSize) fail("Bad world size: " + gridRows);
|
825 | setWorldSize(gridRows); |
826 | for y to gridRows: |
827 | for x to gridRows: {
|
828 | S line = lines.get(i++); |
829 | JCell cell = getCell(x, y); |
830 | if (eq(line, "#")) |
831 | cell.setObstacle(true); |
832 | else if (eq(line, "A")) |
833 | state.moveSmarty(x, y); |
834 | } |
835 | rearrangeLetters(); |
836 | repaintGrid(); |
837 | cset(state, worldName := fileNameWithoutExtension(f)); |
838 | cset(state, worldChanged := false); |
839 | infoBox("World loaded: " + fileName(f));
|
840 | addRecentWorldFile(f); |
841 | } |
842 | } |
843 | |
844 | svoid saveWorldDialog(Runnable whenDone default null) {
|
845 | swing {
|
846 | JFileChooser fileChooser = new(mainDir()); |
847 | fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty World files (*.\*worldFileExtension*/)", worldFileExtension));
|
848 | |
849 | if (fileChooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
|
850 | File f = defaultExtension(worldFileExtension, fileChooser.getSelectedFile()); |
851 | saveWorld(f); |
852 | infoBox("World saved as " + f.getName());
|
853 | } else |
854 | messageBox("World NOT saved");
|
855 | |
856 | callF(whenDone); |
857 | } |
858 | } |
859 | |
860 | svoid withWorldSave(Runnable r) {
|
861 | if (state.worldChanged) {
|
862 | int result = swingShowConfirmDialog(mainFrame, |
863 | "World has changed! - Save it?", "Smarty", |
864 | JOptionPane.YES_NO_CANCEL_OPTION); |
865 | if (result == JOptionPane.YES_OPTION) {
|
866 | saveWorldDialog(r); |
867 | ret; |
868 | } else if (result == JOptionPane.CANCEL_OPTION) |
869 | ret; |
870 | else |
871 | cset(state, worldChanged := false); |
872 | } |
873 | |
874 | r.run(); |
875 | } |
876 | |
877 | svoid loadWorldDialog {
|
878 | withWorldSave(r loadWorldDialogWithoutConfirmation); |
879 | } |
880 | |
881 | svoid loadWorldDialogWithoutConfirmation swing {
|
882 | JFileChooser fileChooser = new(mainDir()); |
883 | fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty World files (*.\*worldFileExtension*/)", worldFileExtension));
|
884 | |
885 | if (fileChooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) |
886 | loadWorld(fileChooser.getSelectedFile()); |
887 | } |
888 | |
889 | svoid newWorld {
|
890 | withWorldSave(r newWorldWithoutConfirmation); |
891 | } |
892 | |
893 | svoid newWorldWithoutConfirmation(int size default defaultWorldSize) {
|
894 | setWorldSize(size); |
895 | cset(state, worldName := "Empty", worldChanged := false); |
896 | updateFrameTitles(); |
897 | } |
898 | |
899 | static File mainDir() {
|
900 | ret mkdirs(userDir("Adaptron/Smarty"));
|
901 | } |
902 | |
903 | sS exportBodyForSaving() {
|
904 | S[] Body = new[22]; |
905 | bodyToArray(state.body!, Body); |
906 | ret lines(dropFirst(Body)); |
907 | } |
908 | |
909 | svoid saveBody(File f) {
|
910 | S text = exportBodyForSaving(); |
911 | saveTextFile(f, text); |
912 | |
913 | cset(state.body!, changed := false); |
914 | addRecentBodyFile(f); |
915 | } |
916 | |
917 | svoid bodyToArray(SmartyBody b, S[] Body) {
|
918 | Body[1] = escapeNewLines(b.name); |
919 | // TODO: remaining values from AI? |
920 | Body[2] = "1"; //Vision.Value = 1 - checked |
921 | Body[3] = "0"; //Touch.Value |
922 | Body[4] = b.wheelsFlag("AddAWheelSensor");
|
923 | Body[5] = "1"; //Wheels.Value |
924 | Body[6] = "0"; //Arms.Value |
925 | Body[7] = b.cameraDirections.contains(CameraDirection.down) ? "1" : "0"; //VisionConfig.VisionDown |
926 | Body[8] = b.cameraDirections.contains(CameraDirection.left) ? "1" : "0"; //VisionConfig.VisionLeft |
927 | Body[9] = b.cameraDirections.contains(CameraDirection.right) ? "1" : "0"; //VisionConfig.VisionRight |
928 | Body[10] = b.cameraDirections.contains(CameraDirection.inFront) ? "1" : "0"; //VisionConfig.VisionInFront |
929 | Body[11] = b.cameraDirections.contains(CameraDirection.behind) ? "1" : "0"; //VisionConfig.VisionBehind |
930 | Body[12] = eq(b.visionMode, VisionMode.nextSquare) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(0) |
931 | Body[13] = eq(b.visionMode, VisionMode.distanceToWall) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(1) |
932 | Body[14] = b.wheelsFlag("MoveForward");
|
933 | Body[15] = b.wheelsFlag("MoveLeft");
|
934 | Body[16] = b.wheelsFlag("MoveRight");
|
935 | Body[17] = b.wheelsFlag("MoveBackward");
|
936 | Body[18] = b.wheelsFlag("TurnRight");
|
937 | Body[19] = b.wheelsFlag("TurnLeft");
|
938 | Body[20] = b.wheelsFlag("TurnAround");
|
939 | Body[21] = eq(b.visionMode, VisionMode.wallOrNot) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(2) |
940 | } |
941 | |
942 | svoid withBodySave(Runnable r) {
|
943 | if (state.body->changed) {
|
944 | int result = swingShowConfirmDialog(mainFrame, |
945 | "Body has changed! - Save it?", "Smarty", |
946 | JOptionPane.YES_NO_CANCEL_OPTION); |
947 | if (result == JOptionPane.YES_OPTION) {
|
948 | saveBodyDialog(r); |
949 | ret; |
950 | } else if (result == JOptionPane.CANCEL_OPTION) |
951 | ret; |
952 | else |
953 | cset(state.body, changed := false); |
954 | } |
955 | |
956 | r.run(); |
957 | } |
958 | |
959 | svoid newBody {
|
960 | withBodySave(r newBodyWithoutConfirmation); |
961 | } |
962 | |
963 | svoid newBodyWithoutConfirmation {
|
964 | cdelete(state.body!); |
965 | cset(state, body := cnew(SmartyBody)); |
966 | finishBodySetup(); |
967 | } |
968 | |
969 | svoid loadBody(File f) {
|
970 | pcall-messagebox {
|
971 | LS lines = linesFromFile_list(f); |
972 | |
973 | if (eqAfterRtrim(lines(lines), exportBodyForSaving())) |
974 | ret with infoBox("Body is the same as current one");
|
975 | |
976 | S[] Body = asStringArray(itemPlusList("", lines));
|
977 | newBody(); |
978 | var b = state.body!; |
979 | // TODO: remaining values |
980 | cset(b, name := Body[1]); |
981 | if (eq(Body[4], "1")) b.wheels.add("AddAWheelSensor");
|
982 | if (eq(Body[7], "1")) b.cameraDirections.add(CameraDirection.down); |
983 | if (eq(Body[8], "1")) b.cameraDirections.add(CameraDirection.left); |
984 | if (eq(Body[9], "1")) b.cameraDirections.add(CameraDirection.right); |
985 | if (eq(Body[10], "1")) b.cameraDirections.add(CameraDirection.inFront); |
986 | if (eq(Body[11], "1")) b.cameraDirections.add(CameraDirection.behind); |
987 | if (eq(Body[12], "True")) b.visionMode = VisionMode.nextSquare; |
988 | if (eq(Body[13], "True")) b.visionMode = VisionMode.distanceToWall; |
989 | if (eq(Body[14], "1")) b.wheels.add("MoveForward");
|
990 | if (eq(Body[15], "1")) b.wheels.add("MoveLeft");
|
991 | if (eq(Body[16], "1")) b.wheels.add("MoveRight");
|
992 | if (eq(Body[17], "1")) b.wheels.add("MoveBackward");
|
993 | if (eq(Body[18], "1")) b.wheels.add("TurnRight");
|
994 | if (eq(Body[19], "1")) b.wheels.add("TurnLeft");
|
995 | if (eq(Body[20], "1")) b.wheels.add("TurnAround");
|
996 | if (eq(Body[21], "True")) b.visionMode = VisionMode.wallOrNot; |
997 | cset(b, changed := false); |
998 | b.change(); |
999 | updateTabs(); |
1000 | infoBox("Body loaded: " + fileName(f));
|
1001 | addRecentBodyFile(f); |
1002 | |
1003 | finishBodySetup(); |
1004 | } |
1005 | } |
1006 | |
1007 | svoid saveBodyDialog(Runnable whenDone default null) {
|
1008 | swing {
|
1009 | new JFileChooser fileChooser; |
1010 | fileChooser.setSelectedFile(newFile(mainDir(), sanitizeFileName(state.body->name))); |
1011 | fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty Body files (*.\*bodyFileExtension*/)", bodyFileExtension));
|
1012 | |
1013 | if (fileChooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
|
1014 | File f = defaultExtension(bodyFileExtension, fileChooser.getSelectedFile()); |
1015 | cset(state.body, name := fileNameWithoutExtension(f)); |
1016 | updateTabs(); |
1017 | saveBody(f); |
1018 | infoBox("Body saved as " + f.getName());
|
1019 | } |
1020 | |
1021 | callF(whenDone); |
1022 | } |
1023 | } |
1024 | |
1025 | svoid loadBodyDialog {
|
1026 | withBodySave(r loadBodyDialogWithoutConfirmation); |
1027 | } |
1028 | |
1029 | svoid loadBodyDialogWithoutConfirmation swing {
|
1030 | JFileChooser fileChooser = new(mainDir()); |
1031 | fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty Body files (*.\*bodyFileExtension*/)", bodyFileExtension));
|
1032 | |
1033 | if (fileChooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) |
1034 | loadBody(fileChooser.getSelectedFile()); |
1035 | } |
1036 | |
1037 | sS infosForWindowTitle() {
|
1038 | ret " - World= " + state.worldName + ", Body= " + state.body->name |
1039 | + ", Run done on " + simpleDateFormat_defaultTZ_now("MM-dd-YYYY") + " (mm-dd-yyyy) "
|
1040 | + simpleDateFormat_defaultTZ_now("HH:mm:ss");
|
1041 | } |
1042 | |
1043 | svoid updateFrameTitles {
|
1044 | frameTitle(mainFrame, "Smarty's World" + infosForWindowTitle()); |
1045 | frameTitle(historyFrame, "Stimulus/Response, Percept/Action History" + infosForWindowTitle()); |
1046 | frameTitle(memoryFrame, "Smarty's Memory" + infosForWindowTitle()); |
1047 | } |
1048 | |
1049 | // Make the dynamic menus |
1050 | svoid makeMenus {
|
1051 | addMenu(mainFrame, "Worlds", |
1052 | "New... (Ctrl+N)", r newWorld, |
1053 | "Retrieve... (Ctrl+R)", r loadWorldDialog, |
1054 | "Save... (Ctrl+S)", r saveWorldDialog, |
1055 | "---", |
1056 | mapWithIndexStartingAt1(reversed(keys(state.recentWorldFiles)), (idx, f) |
1057 | -> jMenuItem(idx + " " + fileName(f), r { withWorldSave(r { loadWorld(f) }) })),
|
1058 | empty(state.recentWorldFiles) ? null : "---", |
1059 | "Exit", rThread killVM); |
1060 | |
1061 | addMenu(mainFrame, "Bodies", |
1062 | "New... (Ctrl+N)", r newBody, |
1063 | "Retrieve... (Ctrl+R)", r loadBodyDialog, |
1064 | "Save... (Ctrl+S)", r saveBodyDialog, |
1065 | "---", |
1066 | mapWithIndexStartingAt1(reversed(keys(state.recentBodyFiles)), (idx, f) |
1067 | -> jMenuItem(idx + " " + fileName(f), r { withBodySave(r { loadBody(f) }) })),
|
1068 | empty(state.recentBodyFiles) ? null : "---", |
1069 | "Exit", rThread killVM); |
1070 | } |
1071 | |
1072 | svoid goCmd { smartyQ.add(r goCmd_impl); }
|
1073 | |
1074 | svoid goCmd_impl {
|
1075 | pcall-messagebox {
|
1076 | evalWithTimeout(10.0, r {
|
1077 | print("goCmd");
|
1078 | |
1079 | if (!state.body->used) {
|
1080 | finishBodySetup(); |
1081 | cset(state.body, used := true); |
1082 | enableBodyControls(false); |
1083 | } |
1084 | |
1085 | smarty.bodies.BodyFunction2(); |
1086 | }); |
1087 | } |
1088 | } |
1089 | |
1090 | static int Indx(int row, int col) {
|
1091 | // C is the across / column location - 0 based |
1092 | // R is the down / row location - 0 based |
1093 | // the function gives the index into NG and CWP linear arrays - 0 based |
1094 | // can not be greater than 199 because 200+ used for wall letters |
1095 | |
1096 | ret state.gridCols * row + col; |
1097 | } |
1098 | |
1099 | // NG(I).Caption is contents of cell x/y |
1100 | // with I = WallNo(x, y, direction) |
1101 | |
1102 | // NG Caption is either "" or smarty.Smarty |
1103 | // or Chr$(64 + InNG - 200) [location letter?] |
1104 | |
1105 | // WP$ seems to hold the playing field |
1106 | // WP$(R, C) can be ABlock$ |
1107 | |
1108 | /* From Brett: |
1109 | |
1110 | WP$ contains either a space, a block or the smarty symbol. |
1111 | |
1112 | The smarty symbol may be an S, >, <, ^, v or + depending on which way smarty is pointing. |
1113 | |
1114 | NG().captions contain the letter for each location. The LookUnder$() routine returns the letter |
1115 | for the camera that looks down at the current square. LookNorth$() etc. and other Look routines |
1116 | return the cell letter that is one cell away. |
1117 | |
1118 | The higher index values into NG() can contain letter for the walls set by the IDWalls() routine. |
1119 | But this feature is not in use and the higher index entries of NG are invisible so a mouse down |
1120 | cannot be done on them. |
1121 | |
1122 | Note also that ScopeLeft$() and other Scope routines that would return wall letters are not in use. |
1123 | */ |
1124 | |
1125 | static int InRow() { ret state.smartyY; }
|
1126 | static int InCol() { ret state.smartyX; }
|
1127 | |
1128 | svoid setSmartyDirection(S smartyDirection) {
|
1129 | if (cset_trueIfChanged(state, +smartyDirection)) |
1130 | repaintGrid(); |
1131 | } |
1132 | |
1133 | // query cell for Smarty's brain |
1134 | sS WP(int y, int x) {
|
1135 | if (x == InCol() && y == InRow()) |
1136 | ret state.smartyDirection; |
1137 | else |
1138 | ret getCell(x, y).obstacle() ? smarty.ABlock : smarty.ASpace; |
1139 | } |
1140 | |
1141 | // put more static functions here |
1142 | |
1143 | sclass TheWorld extends Smarty.TheWorld {
|
1144 | |
1145 | // find what letter we are standing on |
1146 | public String LookUnder() {
|
1147 | ret str(smartyCell().letter); |
1148 | } |
1149 | |
1150 | void moveRelative(int x, int y) {
|
1151 | x += state.smartyX; y += state.smartyY; |
1152 | |
1153 | if (!inGrid(x, y) || getCell(x, y).obstacle()) |
1154 | smarty.Motion = smarty.NoMove; |
1155 | else {
|
1156 | smarty.Motion = "Y"; |
1157 | state.moveSmarty(x, y); |
1158 | } |
1159 | } |
1160 | |
1161 | public void MoveWest() {
|
1162 | moveRelative(-1, 0); |
1163 | } |
1164 | |
1165 | public void MoveSouth() {
|
1166 | moveRelative(0, 1); |
1167 | } |
1168 | |
1169 | public void MoveEast() {
|
1170 | moveRelative(1, 0); |
1171 | } |
1172 | |
1173 | public void MoveNorth() {
|
1174 | moveRelative(0, -1); |
1175 | } |
1176 | |
1177 | public void DisplayStimuliAndResponse(int[][][] inputValues, char response) {
|
1178 | new L<JComponent> leftStack; |
1179 | new L<JComponent> rightStack; |
1180 | |
1181 | for (int Sens = 1; Sens <= smarty.NumSenses; Sens++) {
|
1182 | int NumSensors = smarty.Senses[Sens][smarty.NumberOfSensors]; |
1183 | if (NumSensors == 0) continue; |
1184 | if (NumSensors != 1) warn("More than one sensor in sense");
|
1185 | |
1186 | S label = smarty.Sense[Sens] + ":"; |
1187 | |
1188 | var inputValue = inputValues[Sens][smarty.Valu][smarty.Fired]; |
1189 | S text; |
1190 | if (smarty.Senses[Sens][smarty.SymbolicOrMagnitude] == smarty.Magnitude) |
1191 | text = str(charPlus(inputValue , '0')) |
1192 | + (debugValues ? " [magn " + inputValue + "]" : ""); |
1193 | else |
1194 | text = lookupOrKeep(winToUnicode, str((char) inputValue)) |
1195 | + (debugValues ? " [char " + inputValue + "]" : ""); // A, B, C etc |
1196 | |
1197 | leftStack.add(withLabel(withTypeWriterFont(jlabel(label)), jlabel(text))); |
1198 | } |
1199 | |
1200 | for (int Devs = 1; Devs <= smarty.NumDevices; Devs++) {
|
1201 | S label = smarty.Device[Devs] + ":"; |
1202 | |
1203 | rightStack.add(withLabel(withTypeWriterFont(jlabel(label)), jlabel(winToUnicode(response)))); |
1204 | } |
1205 | |
1206 | scpStimuliAndResponse.set(jhgridWithSpacing( |
1207 | vstack(leftStack), |
1208 | vstack(rightStack))); |
1209 | } |
1210 | |
1211 | public void Update_View() { // called by World.LookInside_Click() to SeeHistory and Bodies.BodyFunction2()
|
1212 | // refreshes all the subwindows |
1213 | historyDisplay(); |
1214 | dumpLTM(); |
1215 | } |
1216 | |
1217 | public void setBinonDisplayObjList(S text) {
|
1218 | cset(state, memory1 := text); |
1219 | setText(memoryTextArea1, winToUnicode(text)); |
1220 | } |
1221 | |
1222 | public void setBinonDisplayChngResults(S text) {
|
1223 | cset(state, binonDisplayChngResults := text); |
1224 | rstUpdateChngResults.trigger(); |
1225 | } |
1226 | |
1227 | public void appendBinonDisplayChngResults(S text) {
|
1228 | cset(state, binonDisplayChngResults := state.binonDisplayChngResults+text); |
1229 | rstUpdateChngResults.trigger(); |
1230 | } |
1231 | |
1232 | S lookDirection(int dx, int dy) {
|
1233 | int x = InCol()+dx, y = InRow()+dy; |
1234 | // If off top of board or next one is a block |
1235 | if (inGrid(x, y)) // must be on board |
1236 | if (eq(WP(y, x), smarty.ABlock)) |
1237 | ret smarty.Wall; // looking at a wall |
1238 | else // valid square to move into |
1239 | ret str(getCell(x, y).letter); |
1240 | else // looking beyond grid |
1241 | ret smarty.Wall; |
1242 | } |
1243 | |
1244 | public S LookNorth() { ret lookDirection(0, -1); }
|
1245 | public S LookSouth() { ret lookDirection(0, 1); }
|
1246 | public S LookWest() { ret lookDirection(-1, 0); }
|
1247 | public S LookEast() { ret lookDirection( 1, 0); }
|
1248 | |
1249 | public void PointUnder() {
|
1250 | setSmartyDirection(smarty.Smarty); |
1251 | } |
1252 | |
1253 | public void PointNorth() {
|
1254 | setSmartyDirection(smarty.UpArrow); |
1255 | } |
1256 | |
1257 | public void PointSouth() {
|
1258 | setSmartyDirection(smarty.DownArrow); |
1259 | } |
1260 | |
1261 | public void PointWest() {
|
1262 | setSmartyDirection(smarty.LeftArrow); |
1263 | } |
1264 | |
1265 | public void PointEast() {
|
1266 | setSmartyDirection(smarty.RightArrow); |
1267 | } |
1268 | |
1269 | public int RangeNorth() { ret rangeDirection(0, -1); }
|
1270 | public int RangeSouth() { ret rangeDirection(0, 1); }
|
1271 | public int RangeWest() { ret rangeDirection(-1, 0); }
|
1272 | public int RangeEast() { ret rangeDirection( 1, 0); }
|
1273 | |
1274 | public int rangeDirection(int dx, int dy) { // Distance to wall
|
1275 | int x = InCol(), y = InRow(); |
1276 | int i = 0; |
1277 | do {
|
1278 | ++i; |
1279 | x += dx; |
1280 | y += dy; |
1281 | // End if off rightside of board or next one is a block |
1282 | } while (inGrid(x, y) && !getCell(x, y).obstacle()); |
1283 | ret i; |
1284 | } |
1285 | |
1286 | public void showSensorValues(S text) {
|
1287 | cset(state, sensorValuesText := text); |
1288 | setText(taSensorValues, winToUnicode(text)); |
1289 | } |
1290 | |
1291 | public void showDeviceValues(S text) {
|
1292 | cset(state, deviceValuesText := text); |
1293 | setText(taDeviceValues, winToUnicode(text)); |
1294 | } |
1295 | } // end of TheWorld |
1296 | |
1297 | svoid initSmarty {
|
1298 | smarty.World = new TheWorld; |
1299 | smarty.Initialize_Adaptron(); |
1300 | } |
1301 | |
1302 | svoid resetSmarty aka finishBodySetup() {
|
1303 | print("Finishing body setup");
|
1304 | |
1305 | ResetSmartyLocation(); |
1306 | smarty.Reset_Adaptron(); // set all memory, S-List, Habit stack |
1307 | |
1308 | cset(state, history1 := "", history2 := "", memory1 := ""); |
1309 | setText(historyTextArea1, ""); |
1310 | setText(historyTextArea2, ""); |
1311 | setText(memoryTextArea1, ""); |
1312 | setText(memoryTextArea2, ""); |
1313 | |
1314 | bodyToArray(state.body!, smarty.BodySetting); |
1315 | //pnl("BodySetting", smarty.BodySetting);
|
1316 | |
1317 | /*if (Vision.Value = 1)*/ smarty.SetupVision(); |
1318 | //if (Touch.Value = 1) smarty.SetupTouch(); |
1319 | |
1320 | /*if (Wheels.Value = 1)*/ smarty.SetupWheels(); |
1321 | //if (Arms.Value = 1) smarty.SetupArms(); |
1322 | |
1323 | SetupStimulusResponseDisplay(); //Setup display of stimuli at bottom of World screen |
1324 | |
1325 | updateTabs(); |
1326 | } |
1327 | |
1328 | // not needed |
1329 | svoid SetupStimulusResponseDisplay {}
|
1330 | |
1331 | // from Adapt.frm / HISTORYDISPLAY |
1332 | svoid historyDisplay {
|
1333 | new LS lines; |
1334 | StringBuilder[] ILines$ = new[10+1]; |
1335 | int GroupSize = 250; // After 250 events the IO.Text area wraps the lines |
1336 | new StringBuilder NumberLine$; |
1337 | new StringBuilder OLine1$; |
1338 | |
1339 | for (int Group = 0; Group <= (smarty.LIN - 1) / GroupSize; Group++) {
|
1340 | int EndLIN = min(GroupSize * Group + GroupSize, smarty.LIN); |
1341 | |
1342 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) {
|
1343 | if (E == GroupSize * Group + 1) { // If it is the 1st position / event in the line then
|
1344 | NumberLine$ = new StringBuilder("Step # : ");
|
1345 | for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) // Add labels to start of lines |
1346 | ILines$[Sn] = new StringBuilder(takeFirst(smarty.Sense[Sn] + ": ", 9)); // The name of the sense |
1347 | OLine1$ = new StringBuilder(takeFirst(smarty.Device[1] + ": ", 9)); // The name of the action device |
1348 | } |
1349 | |
1350 | S E_str = " " + E; // visual-basic style int-to-string! |
1351 | NumberLine$.append(E_str); // the event number |
1352 | int Wdth = l(E_str); // the space taken up by the event number |
1353 | |
1354 | for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) |
1355 | ILines$[Sn].append(takeLast(" " + smarty.INPUTS[E][Sn], Wdth));
|
1356 | |
1357 | OLine1$.append(takeLast(" " + smarty.OUTPUTS[E][1], Wdth));
|
1358 | } |
1359 | |
1360 | lines.add(str(NumberLine$)); |
1361 | for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) |
1362 | lines.add(str(ILines$[Sn])); |
1363 | lines.add(str(OLine1$)); |
1364 | lines.add("");
|
1365 | } |
1366 | |
1367 | S text = rtrim(lines(lines)); |
1368 | cset(state, history1 := text); |
1369 | setText(historyTextArea1, winToUnicode(text)); |
1370 | } // end of historyDisplay |
1371 | |
1372 | svoid dumpLTM { //Called by Update_View
|
1373 | String MemValT = null; |
1374 | int[] MemSize = new[2000 + 1]; |
1375 | String Sen = null; |
1376 | String Att = null; |
1377 | String Pe = null; |
1378 | String Ob = null; |
1379 | Object BinTyp = null; |
1380 | |
1381 | boolean DisplayIt = false; //a Spac$, |
1382 | |
1383 | //'-------------------- Long Term Memory (LTM) - Monitoring Info. ------------------------- |
1384 | // 'For Display purposes only by Adapt.DUMPLTM in Adapt.LTMem |
1385 | // 'Long term memory contains a list of the stimuli that have been paid attention to. |
1386 | // 'It stores Perceptual sequences as a pair of sequential memory locations. |
1387 | // |
1388 | // Public LTMEMORY&(1 To 2000, 1 To 6) |
1389 | // '1st index is StoreAt cycle number |
1390 | // '2nd index is what type of information is in the LTM |
1391 | // |
1392 | // '---- LTMEMORY() 2nd index values - type of information in LTMEMORY() |
1393 | // Public LtmPerceptTyp '1 Percept binon type |
1394 | // Public LtmPerceptBin '2 Percept binon |
1395 | // Public LtmESType '3 Type of ES Binon - may be an SS |
1396 | // Public LtmESActBin '4 ES Actbin |
1397 | // Public LtmARType '5 Type of AR Binon - may be an RR |
1398 | // Public LtmARActBin '6 AR ActBin |
1399 | // Public LtmActionTyp '7 Action binon type |
1400 | // Public LtmActionBin '8 Action binon |
1401 | |
1402 | for (var I = 1; I <= smarty.StoreAt; I++) //find the widest binon # for all the StoreAt positions |
1403 | {
|
1404 | MemSize[I] = intMax( |
1405 | l(str(I))+1, |
1406 | 3, |
1407 | l(vbToStr(smarty.LTMEMORY[I][smarty.LtmPerceptBin])), |
1408 | l(vbToStr(smarty.LTMEMORY[I][smarty.LtmESActBin])), |
1409 | l(vbToStr(smarty.LTMEMORY[I][smarty.LtmARActBin])), |
1410 | l(vbToStr(smarty.LTMEMORY[I][smarty.LtmActionBin]))); |
1411 | } |
1412 | |
1413 | new StringBuffer text; |
1414 | |
1415 | int GroupSize = 250; |
1416 | |
1417 | var tempVar = (smarty.StoreAt - 1) / GroupSize; |
1418 | |
1419 | for (int Group = 0; Group <= (smarty.StoreAt - 1) / GroupSize; Group++) {
|
1420 | int EndLIN = GroupSize * Group + GroupSize; //Only put up the available values |
1421 | |
1422 | if (EndLIN > smarty.StoreAt) EndLIN = smarty.StoreAt; |
1423 | |
1424 | new StringBuilder MemLine; |
1425 | |
1426 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM display the event number |
1427 | MemLine.append(pad(MemSize[E], str(E))); |
1428 | |
1429 | text.append(MemLine + "\r\n"); |
1430 | |
1431 | //------Percepts(.., Fired) Type |
1432 | |
1433 | MemLine = new StringBuilder; |
1434 | |
1435 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1436 | {
|
1437 | Att = smarty.BinonTypeName[smarty.LTMEMORY[E][smarty.LtmPerceptTyp]][smarty.BinAbbreviation]; //Att$ = Str$(STM(1, BinTp, Current)) |
1438 | MemLine.append(pad(MemSize[E], Att)); |
1439 | } |
1440 | |
1441 | text.append(MemLine + "\r\n"); |
1442 | |
1443 | //------Percepts(.., Fired) Binon |
1444 | |
1445 | MemLine = new StringBuilder; //Trigger STIMULUS intensity |
1446 | |
1447 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1448 | {
|
1449 | Att = str(smarty.LTMEMORY[E][smarty.LtmPerceptBin]); //Att$ = Str$(STM(1, BinId, Current)) |
1450 | MemLine.append(pad(MemSize[E], Att)); |
1451 | } |
1452 | |
1453 | text.append(MemLine + "\r\n\r\n"); |
1454 | |
1455 | //------ES ActBin type |
1456 | |
1457 | MemLine = new StringBuilder; |
1458 | |
1459 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1460 | {
|
1461 | Att = smarty.AESR(smarty.LTMEMORY[E][smarty.LtmESActBin]); |
1462 | MemLine.append(pad(MemSize[E], Att)); |
1463 | } |
1464 | |
1465 | text.append(MemLine + "\r\n"); |
1466 | |
1467 | |
1468 | //------ LTMEMORY ActBin Object binon |
1469 | |
1470 | MemLine = new StringBuilder; |
1471 | |
1472 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1473 | {
|
1474 | Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmESActBin]); |
1475 | MemLine.append(pad(MemSize[E], Att)); |
1476 | } |
1477 | |
1478 | text.append(MemLine + "\r\n\r\n"); |
1479 | |
1480 | //------AR ActBin type |
1481 | |
1482 | MemLine = new StringBuilder; |
1483 | |
1484 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1485 | {
|
1486 | Att = smarty.AESR(smarty.LTMEMORY[E][smarty.LtmARActBin]); |
1487 | MemLine.append(pad(MemSize[E], Att)); |
1488 | } |
1489 | |
1490 | text.append(MemLine + "\r\n"); |
1491 | |
1492 | |
1493 | |
1494 | //------ LTMEMORY ActBin Object binon |
1495 | |
1496 | MemLine = new StringBuilder; |
1497 | |
1498 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1499 | {
|
1500 | Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmARActBin]); |
1501 | MemLine.append(pad(MemSize[E], Att)); |
1502 | } |
1503 | |
1504 | text.append(MemLine + "\r\n\r\n"); |
1505 | |
1506 | //------Actions(.., Fired) Type |
1507 | |
1508 | MemLine = new StringBuilder; |
1509 | |
1510 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1511 | {
|
1512 | |
1513 | Att = smarty.BinonTypeName[smarty.LTMEMORY[E][smarty.LtmActionTyp]][smarty.BinAbbreviation]; |
1514 | MemLine.append(pad(MemSize[E], Att)); |
1515 | } |
1516 | |
1517 | text.append(MemLine + "\r\n"); |
1518 | |
1519 | //------Actions(.., Fired) Binon |
1520 | |
1521 | MemLine = new StringBuilder; |
1522 | |
1523 | for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM |
1524 | {
|
1525 | Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmActionBin]); |
1526 | MemLine.append(pad(MemSize[E], Att)); |
1527 | } |
1528 | |
1529 | text.append(MemLine + "\r\n\r\n"); |
1530 | } |
1531 | |
1532 | S s = rtrim(str(text)); |
1533 | cset(state, history2 := s); |
1534 | setText(historyTextArea2, winToUnicode(s)); |
1535 | } //End of dumpLTM |
1536 | |
1537 | svoid uiZoom(double percent) {
|
1538 | if (cset_trueIfChanged(state, fontScale := toFloat(percent/100))) |
1539 | restart(); |
1540 | } |
1541 | |
1542 | svoid updateFontScale(float scale) {
|
1543 | swingFontScale(scale); |
1544 | spacing = iround(defaultSpacing*scale); |
1545 | } |
1546 | |
1547 | svoid selfTest { new SelfTest().run(); }
|
1548 | |
1549 | sclass SelfTest {
|
1550 | new Scorer scorer; |
1551 | |
1552 | void loadWorldAndBody(S worldText, S bodyText) {
|
1553 | File bodyFile = programFile("body.tmp");
|
1554 | File worldFile = programFile("world.tmp");
|
1555 | |
1556 | saveTextFile(worldFile, dropLeadingEmptyLines(worldText)); |
1557 | loadWorld(worldFile); |
1558 | |
1559 | saveTextFile(bodyFile, dropLeadingEmptyLines(bodyText)); |
1560 | loadBody(bodyFile); |
1561 | } |
1562 | |
1563 | run {
|
1564 | activateConsole(); |
1565 | |
1566 | print("Self-Test START");
|
1567 | |
1568 | S text = loadSnippet(#1031220); |
1569 | LS parts = splitAtMultipleEqualsLines(text); |
1570 | |
1571 | assertEqualsVerbose(6, l(parts)); |
1572 | loadWorldAndBody(parts.get(0), parts.get(1)); |
1573 | LS outputTexts = subList(parts, 2); |
1574 | |
1575 | once {
|
1576 | // step 1 |
1577 | if (!step(outputTexts)) break; |
1578 | |
1579 | text = loadSnippet(#1031228); |
1580 | outputTexts = getMulti(splitAtMultipleEqualsLines(text), 2, 3, 0, 1); |
1581 | |
1582 | // step 2 |
1583 | if (!step(outputTexts)) break; |
1584 | |
1585 | // step 10 |
1586 | text = loadSnippet(#1031229); |
1587 | outputTexts = getMulti(splitAtMultipleEqualsLines(text), 0, 1, 2, 3); |
1588 | |
1589 | repeat 7 { goCmd_impl(); }
|
1590 | if (!step(outputTexts)) break; |
1591 | |
1592 | // step 50 |
1593 | text = loadSnippet(#1031230); |
1594 | outputTexts = getMulti(splitAtMultipleEqualsLines(text), 2, 3, 0, 1); |
1595 | |
1596 | repeat 39 { goCmd_impl(); }
|
1597 | if (!step(outputTexts)) break; |
1598 | } |
1599 | |
1600 | // second test case |
1601 | |
1602 | text = loadSnippet(#1031231); |
1603 | parts = splitAtMultipleEqualsLines(text); |
1604 | |
1605 | assertEqualsVerbose(6, l(parts)); |
1606 | loadWorldAndBody(parts.get(0), parts.get(1)); |
1607 | |
1608 | once {
|
1609 | // step 30 |
1610 | outputTexts = getMulti(subList(parts, 2), 2, 3, 0, 1); |
1611 | |
1612 | repeat 29 { goCmd_impl(); }
|
1613 | if (!step(outputTexts)) break; |
1614 | } |
1615 | |
1616 | // third test case |
1617 | |
1618 | text = loadSnippet(#1031238); |
1619 | parts = splitAtMultipleEqualsLines(text); |
1620 | |
1621 | assertEqualsVerbose(6, l(parts)); |
1622 | loadWorldAndBody(parts.get(0), parts.get(1)); |
1623 | |
1624 | once {
|
1625 | // step 50 |
1626 | outputTexts = getMulti(subList(parts, 2), 2, 3, 0, 1); |
1627 | |
1628 | repeat 49 { goCmd_impl(); }
|
1629 | if (!step(outputTexts)) break; |
1630 | } |
1631 | |
1632 | print("SELF-TEST RESULT: " + scorer);
|
1633 | } |
1634 | |
1635 | // returns false if something failed |
1636 | bool step(LS outputTexts) {
|
1637 | goCmd_impl(); |
1638 | |
1639 | new LS diffs; |
1640 | |
1641 | printAsciiHeading("HISTORY 1");
|
1642 | print(addAndReturn(diffs, unidiff2(historyTextArea1, outputTexts.get(2)))); |
1643 | |
1644 | printAsciiHeading("HISTORY 2");
|
1645 | print(addAndReturn(diffs, unidiff2(historyTextArea2, outputTexts.get(3)))); |
1646 | |
1647 | printAsciiHeading("MEMORY 1");
|
1648 | print(addAndReturn(diffs, unidiff2(memoryTextArea1, outputTexts.get(0)))); |
1649 | |
1650 | printAsciiHeading("MEMORY 2");
|
1651 | print(addAndReturn(diffs, unidiff2(state.binonDisplayChngResults, outputTexts.get(1)))); |
1652 | |
1653 | bool ok = allStringsEmpty(diffs); |
1654 | scorer.add(ok, nOutputs(nempties(diffs)) + " differ"); |
1655 | ret ok; |
1656 | } |
1657 | } |
1658 | |
1659 | sS unidiff2(JTextComponent ta, S text) {
|
1660 | ret unidiff2(getText(ta), text); |
1661 | } |
1662 | |
1663 | sS unidiff2(S actual, S text) {
|
1664 | ret unidiff(cleanUpForDiff(text), cleanUpForDiff(actual)); |
1665 | } |
1666 | |
1667 | sS cleanUpForDiff(S text) {
|
1668 | ret fixNewLines(rtrim(dropLeadingEmptyLines(text))); |
1669 | } |
1670 | |
1671 | svoid ResetSmartyLocation {
|
1672 | if (!getCell(state.startX, state.startY).obstacle()) |
1673 | state.moveSmarty(state.startX, state.startY); |
1674 | } |
1675 | |
1676 | sS winToUnicode(O text) {
|
1677 | ret mapCharacters(str(text), c -> lookupOrKeep(winToUnicode, str(c))); |
1678 | } |
1679 | |
1680 | static <A extends JComponent> A monospaced(A a) {
|
1681 | ret setFont(monospacedFontID, swingScale(monospacedFontSize), a); |
1682 | } |
Began life as a copy of #1031104
download show line numbers debug dex old transpilations
Travelled to 5 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt, ymdyxumozjwr
No comments. add comment
| Snippet ID: | #1031123 |
| Snippet name: | Smarty [stable preview] |
| Eternal ID of this version: | #1031123/29 |
| Text MD5: | 9021c2e87e2209c7658da189fd4bf473 |
| Transpilation MD5: | 4aabad26cb231133ac6de6fdcfdc0d22 |
| Author: | stefan |
| Category: | |
| Type: | JavaX source code (desktop) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2021-06-06 23:50:57 |
| Source code size: | 56388 bytes / 1682 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 728 / 2064 |
| Version history: | 28 change(s) |
| Referenced in: | [show references] |