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: | 504 / 1571 |
Version history: | 28 change(s) |
Referenced in: | [show references] |