!7 set flag Reparse. set flag OurSyncCollections. // allow to run on newer JDKs without illegal-access command line flags import javax.swing.filechooser.*; !include #1031138 // Smarty AI Include sbool debugValues = false; // debug sensor output static int defaultSpacing = 10, spacing; static JFrame mainFrame; static LL gridComponents; static JComponent mainGrid; static JCheckBoxMenuItem miShowLocations; static SingleComponentPanel scpMainGrid, scpVisionConfig, scpWheelsConfig, scpCurrentSmarty, scpStimuliAndResponse; static JFrame historyFrame, memoryFrame; static JSpinner worldSizeSpinner; static JTextArea historyTextArea1, historyTextArea2; static JTextArea taSensorValues, taDeviceValues; // originally: BinonDisplay.ObjList.Text static JTextArea memoryTextArea1; // originally: BinonDisplay.ChngResults.Text static JTextArea memoryTextArea2; static Smarty smarty; // AI instance static Q smartyQ = startQ("Smarty Q"); // queue for Smarty operations sS wallSymbol = unicode_blackSquare(), noWallSymbol = unicode_dottedSquare(); static Color lightBlue = colorFromHex("4169e1"); sS locationLetters = charRange('A', 'Z') + "[\\]^_`" + charRange('a', 'z') + charRange(123, 128); sS smartyUnicode = unicode_slightlySmilingFace(); static int smartyFontSize = 40; sS windowsFontID = #1400468; sS emojiFontID = #1400470; sS frameIconID = #1102983; sS monospacedFontID = /*#1400479*/#1400483; static double monospacedFontSize = 12; sbool smartyBrainPersistence = false; sS smartyImageID = #1102987; sS helpTextID = #1031105; sS worldFileExtension = "WLD"; sS bodyFileExtension = "BDY"; sS historyHelp = unindent_mls([[ A percept is the stimulus or simultaneous combination of stimuli observed. An action is the response or simultaneous combination of responses produced. Binon # numbers refer to the binons in memory that represent the percepts, actions, expectations, and perceptual or action sequences. P = Percept, E = Expectation, PP = Perceptual sequence A = Action, AA = Action sequence Read the paper: "The Perception-Action Hierarchy and its Implementation Using Binons (Binary Neurons)" on the www.adaptroninc.com website for more information. ]]); // translate Smarty's windows characters to unicode static SS winToUnicode = litmap( Smarty.Smarty, unicode_slightlySmilingFace(), Smarty.UpArrow, unicode("2191"), Smarty.LeftArrow, unicode("2190"), Smarty.RightArrow, unicode("2192"), Smarty.DownArrow, unicode("2193"), Smarty.Wall, unicode_blackVerticalRectangle(), Smarty.EmptySquare, unicode_whiteVerticalRectangle(), Smarty.chr(Smarty.TurnRght), unicode("21B1"), Smarty.chr(Smarty.TurnLft), unicode("21B0"), Smarty.chr(Smarty.TurnArnd), unicode("21B7"), Smarty.chr(254), unicode_blackSmallSquare(), // "Novel" ); sbool showTabs = true; static int defaultWorldSize = 7, maxWorldSize = 8; static ReliableSingleThread rstUpdateChngResults = rstWithPreDelay(250, r { setText(memoryTextArea2, winToUnicode(state.binonDisplayChngResults)); }); svoid rearrangeLetters { int iLetter = 0; for (int y = 0; y < state.gridRows; y++) for (int x = 0; x < state.gridCols; x++) { JCell cell = getCell(x, y); if (cell.obstacle()) cell.letter = ' '; else cell.letter = locationLetters.charAt(iLetter++); } } sclass VisionMode { sS nextSquare = "next square"; sS distanceToWall = "distance to wall"; sS wallOrNot = "wall or not"; } sclass CameraDirection { sS down = "down"; sS left = "left"; sS right = "right"; sS inFront = "in front"; sS behind = "behind"; static LS all = ll(down, left, right, inFront, behind); } concept SmartyBody { S name = "Smarty0"; Set cameraDirections = litset(CameraDirection.down); S visionMode = VisionMode.nextSquare; // see VisionMode Set wheels = litset("MoveForward", "MoveLeft", "MoveRight", "MoveBackward"); bool changed; // changed w.r.t. file bool used; // used in Smarty execution // for saving S wheelsFlag(S flag) { ret wheels.contains(flag) ? "1" : "0"; } void userCausedChange { print("Body: User caused change"); changed = true; change(); } } concept State { float fontScale = 1.5f; S worldName = "Empty"; int gridRows = defaultWorldSize, gridCols = defaultWorldSize; // actually these are always identical, could merge into one bool showLocations; bool worldChanged; int startX, startY; // Smarty's start position int smartyX, smartyY; S smartyDirection = Smarty.Smarty; // which way Smarty is looking - this or smarty.LeftArrow etc. Rect selection = rect(1, 1, 1, 1); Pt cursorDirection = pt(1, 0); new BitSet obstacles; S history1 = "", history2 = "", memory1 = "", sensorValuesText = "", deviceValuesText = ""; S binonDisplayChngResults = ""; // memory2 new Ref body; // value is just true Map recentWorldFiles = synchronizedMRUCache(5); Map recentBodyFiles = synchronizedMRUCache(5); void setSelection(Rect r) { if (!cset_trueIfChanged(this, selection := r)) ret; if (selection.h == 1 && selection.w > 1) _setField(cursorDirection := pt(1, 0)); else if (selection.w == 1 && selection.h > 1) _setField(cursorDirection := pt(0, 1)); repaintGrid(); } void clearSelectedArea { fillSelection(false); } void invertSelection { JCell cell1 = getCell(selection.x, selection.y); fillSelection(!cell1.obstacle()); } void fillSelection(bool b) { for (Pt p : pointsInRect(selection)) if (!(b && state.smartyX == p.x && state.smartyY == p.y)) // don't put an obstacle over Smarty getCell(p.x, p.y).setObstacle(b); rearrangeLetters(); moveCursor(); } void moveCursor { setCursor(selection.x+cursorDirection.x, selection.y+cursorDirection.y); } void setCursor(int x, int y) { setSelection(rect(mod(x, gridCols), mod(y, gridRows), 1, 1)); } void moveCursor(int dx, int dy) { _setField(cursorDirection := pt(dx, dy)); setCursor(selection.x+cursorDirection.x, selection.y+cursorDirection.y); } void placeSmarty { getCell(selection.x, selection.y).setObstacle(false); cset(state, startX := selection.x, startY := selection.y); moveSmarty(selection.x, selection.y); moveCursor(); } void moveSmarty(int x, int y) { if (!inRange(x, 0, gridCols) || !inRange(y, 0, gridRows)) fail("Smarty position not in range: " + x + "/" + y); if (cset_trueIfChanged(this, smartyX := x, smartyY := y)) { cset(this, worldChanged := true); repaintGrid(); } } void moveSmartyRelative(int x, int y) { moveSmarty(smartyX+x, smartyY+y); } } // end of State static State state; sclass JCell > JComponent { int x, y; char letter; *(int *x, int *y) {} public void paint(Graphics _g) { Graphics2D g = cast _g; int w = getWidth(), h = getHeight(); Color color = Color.white; if (state.selection.contains(x, y)) color = lightBlue; else if (obstacle()) color = Color.black; fillRect(g, 0, 0, w, h, color); if (state.showLocations && !obstacle()) { temp tempSetFont(g, loadFont_cached(windowsFontID)); drawTextWithTopLeftCornerAt(g, str(letter), Pt(2, 0), Color.black); } if (state.smartyX == x && state.smartyY == y) { temp tempSetFontSize(g, smartyFontSize); /*temp tempSetFont(g, loadFont_cached(emojiFontID)); drawCenteredText(g, smartyUnicode, 0, 0, w, h, Color.black);*/ double size = 0.6; int dx = iround((1-size)/2*w); int dy = iround((1-size)/2*h); if (eq(state.smartyDirection, smarty.Smarty)) drawScaledImage(g, loadImage2_cached(smartyImageID), rectFromPoints(dx, dy, w-dx, h-dy)); else { //temp tempSetFont(g, loadFont_cached(windowsFontID)); S icon = lookupOrKeep(winToUnicode, state.smartyDirection); drawCenteredText(g, icon, 0, 0, w, h, Color.black); } } } int index() { ret y*state.gridCols+x; } bool obstacle() { ret main contains(state.obstacles, index()); } void setObstacle(bool b) { if (setBit_trueIfChanged(state.obstacles, index(), b)) { cset(state, worldChanged := true); state.change(); } } { addMouseListener(new MouseAdapter { public void mousePressed(MouseEvent e) { main requestFocus(mainGrid); if (!isLeftButton(e)) ret; state.setSelection(new Rect(x, y, 1, 1)); } }); addMouseMotionListener(new MouseMotionAdapter { public void mouseDragged(MouseEvent e) { //_print("Drag in " + x + "/" + y + ": " + e.getPoint()); Component dest = componentAtScreenLocationInWindow(mainFrame, e); if (dest cast JCell) { //_print("Target: " + dest); state.setSelection(rectFromPointsInclusiveSorted(x, y, dest.x, dest.y)); } } }); } toString { ret x + "/" + y; } } static JCell getCell(int x, int y) { ret gridComponents.get(y).get(x); } static JCell smartyCell() { ret getCell(state.smartyX, state.smartyY); } sbool inGrid(int x, int y) { ret inRange(y, state.gridRows) && inRange(x, state.gridCols); } svoid makeMainGrid { gridComponents = map(iotaZeroList(state.gridRows), y -> map(iotaZeroList(state.gridCols), x -> new JCell(x, y))); mainGrid = setFocusable(setBackground(Color.black, hvgrid(gridComponents, 1))); scpMainGrid.setComponent(mainGrid); rearrangeLetters(); } // always clears the world svoid setWorldSize(int size) { state.obstacles.clear(); state.gridCols = state.gridRows = size; setSpinnerValue(worldSizeSpinner, size); state.selection = rect(1, 1); cset(state, startX := 0, startY := 0); state.moveSmarty(0, 0); cset(state, worldChanged := false); state.change(); makeMainGrid(); resetSmarty(); } svoid repaintGrid() { repaint(mainGrid); } // add more functions here ifndef NoMainMethod p { smartyMain(); } endifndef svoid smartyMain { System.out.println("Main class: " + strWithIdentityHashCode(mc()) + ", class loader: " + getClassLoader(mc())); autoRestart(2.0); // print all vm bus msgs from concepts //vmBus_snoopToPrint((msg, arg) -> firstOfArrayOrSame(arg) instanceof Concepts); setProgramDir(print("Using directory: ", mainDir())); logProgramOutput(); _handleException_showThreadCancellations = true; if (!isDevVersion()) hideConsole(); else veryBigConsole(); db(); uniq(SmartyBody); // make at least one instance state = uniq(State); smarty = uniq(Smarty); initSmarty(); if (!state.body.has()) cset(state, body := conceptWhere(SmartyBody)); // default body //cset(state.body, used := false); // XXX // prep GUI jtattoo_mcWin(); // styling //set swingFontScale_debug; updateFontScale(state.fontScale); // scaling disableSpaceBarForAllButtons(); // no space bar for buttons loadLibrary(windowsFontID); defaultFrameIcon(frameIconID); mainFrame = showFrame("Smarty"); //exitOnClose(mainFrame); onWindowClosing(mainFrame, rThread { cleanUp(mc()); // proper clean-up for standalone mode cleanKillVM(); }); historyTextArea1 = monospaced(uneditableBlackTextArea_noUndo()); historyTextArea2 = monospaced(uneditableBlackTextArea_noUndo()); memoryTextArea1 = /*withTypeWriterFont*/monospaced(uneditableBlack(swing(() -> new JLineHeightTextArea(0.8)))); memoryTextArea2 = monospaced(uneditableBlackTextArea_noUndo(winToUnicode(state.binonDisplayChngResults))); makeMenus(); registerCtrlKey(mainFrame, KeyEvent.VK_N, "New world", r { print("new") }); registerCtrlKey(mainFrame, KeyEvent.VK_R, "Retrieve world", r {}); registerCtrlKey(mainFrame, KeyEvent.VK_S, "Save world", r {}); addMenu(mainFrame, "View", miShowLocations = jCheckBoxMenuItem("Locations (Ctrl+L)", state.showLocations, b -> { cset(state, showLocations := b); repaintGrid(); }), jMenu("UI Zoom", "100%", r { uiZoom(100) }, "112%", r { uiZoom(112) }, "125%", r { uiZoom(125) }, "140%", r { uiZoom(140) }), "---", "Self-Test", rThread selfTest, "Console", r activateConsole, ); registerCtrlKey(mainFrame, KeyEvent.VK_L, "Locations", r { cset(state, showLocations := !state.showLocations); setChecked(miShowLocations, state.showLocations); repaintGrid(); }); JMenuBar menuBar = getMenuBar(mainFrame); JMenuItem helpItem = jMenuItem("Help F1", rThread showHelp); /*print(minSize := getMinimumSize(helpItem)); print(preferredSize := getPreferredSize(helpItem));*/ addMenuItem(menuBar, jPreferredWidthToMaxWidth(helpItem)); addAndRevalidate(menuBar, jHorizontalGlue()); // spacer registerFunctionKey(mainFrame, 1, rThread showHelp); registerKeyCode(mainFrame, KeyEvent.VK_SPACE, r { state.invertSelection() }); registerKeyCode(mainFrame, KeyEvent.VK_UP, r { state.moveCursor(0, -1) }); registerKeyCode(mainFrame, KeyEvent.VK_LEFT, r { state.moveCursor(-1, 0) }); registerKeyCode(mainFrame, KeyEvent.VK_DOWN, r { state.moveCursor(0, 1) }); registerKeyCode(mainFrame, KeyEvent.VK_RIGHT, r { state.moveCursor(1, 0) }); // react to any letter from A to Z for (int key = KeyEvent.VK_A; key <= KeyEvent.VK_Z; key++) registerKeyCode(mainFrame, key, r { state.placeSmarty() }); worldSizeSpinner = jSpinner(state.gridCols, 1, maxWorldSize); onChange(worldSizeSpinner, r { int size = intFromSpinner(worldSizeSpinner); if (state.gridCols != size) { if (state.worldChanged) { int result = swingShowConfirmDialog(mainFrame, "World has changed! - Save it before resizing?", "Smarty", JOptionPane.YES_NO_CANCEL_OPTION); if (result == JOptionPane.YES_OPTION) { saveWorldDialog(r { newWorldWithoutConfirmation(size) }); ret; } else if (result == JOptionPane.CANCEL_OPTION) { setSpinnerValue(worldSizeSpinner, state.gridCols); ret; } } newWorldWithoutConfirmation(size); } }); scpCurrentSmarty = singleComponentPanel(); JComponent middleArea = westAndCenterWithMargin(spacing, jvstackWithSpacing(spacing, withTitle("World size (max=\*maxWorldSize*/)", worldSizeSpinner), jbutton("Clear Selected Area", rThread { state.clearSelectedArea() }), withTitle("Current world", disableTextField(jLiveValueTextField(conceptFieldLiveValue worldName(state)))), showTabs ? null : fontSizePlus(2, setForeground(Color.ORANGE, jCenteredLabel("Design or Select a body for Smarty"))), showTabs ? null : jbutton("Design or Select Smarty's Body", r showSmartyConfig), withTitle("Current Smarty", scpCurrentSmarty), ), jvgridWithSpacing(spacing, withTitle(monospaced(jLabel("Sensors: Values: are:")), taSensorValues = monospaced(uneditableBlackTextArea_noUndo())), withTitle(monospaced(jLabel("Devices: Values: are:")), taDeviceValues = monospaced(uneditableBlackTextArea_noUndo())), ) ); JComponent controlArea = northAndCenterWithMargin(spacing, vstackWithSpacing( fontSizePlus(2, setForeground(Color.blue, jlabel("Design the World - Read the Help F1"))), jMinHeight(swingScale(200), middleArea)), jCenteredSection("Run Smarty", jflow( jbutton("Go / Continue", rThread goCmd), jButton("See History", r showHistory), jbutton("See Memory", r showMemory), jbutton("Reset", r resetSmarty), jbutton("EXIT", rThread killVM), )) ); scpMainGrid = singleComponentPanel(); makeMainGrid(); var mainPanel = westAndCenterWithMargins(spacing, jvstackWithSpacing(spacing, jFixedSize(500, scpMainGrid), scpStimuliAndResponse = singleComponentPanel() ), controlArea); if (showTabs) { scpVisionConfig = singleComponentPanel(); scpWheelsConfig = singleComponentPanel(); updateTabs(); setFrameContents(mainFrame, jtabs( "Smarty", mainPanel, "Vision", scpVisionConfig, "Wheels", scpWheelsConfig, )); } else setFrameContents(mainFrame, mainPanel); centerPackFrame(mainFrame); // set minimum width jMinWidth_pure(mainFrame, max(1000, swingScale(800))); centerFrameWithMinWidth(mainFrame); // set min frame height jMinHeight_pure(mainFrame, getHeight(mainFrame)); // disable height changes entirely (not good, may cut off at the bottom) //frameMaxHeight(mainFrame, getHeight(mainFrame)); //smarty.World.Update_View(); setText(historyTextArea1, winToUnicode(state.history1)); setText(historyTextArea2, winToUnicode(state.history2)); setText(memoryTextArea1, winToUnicode(state.memory1)); setText(taSensorValues, winToUnicode(state.sensorValuesText)); setText(taDeviceValues, winToUnicode(state.deviceValuesText)); enableBodyControls(!state.body->used); if (!smartyBrainPersistence) resetSmarty(); if (!isDevVersion()) showHelp(); else { //goCmd(); //selfTest(); } } // end of main function sbool isDevVersion() { ret isProgramID(#1031104); } svoid updateTabs { scpVisionConfig.setComponent(visionConfigPanel(state.body!)); scpWheelsConfig.setComponent(wheelsConfigPanel(state.body!)); scpCurrentSmarty.setComponent(disableTextField(jLiveValueTextField(conceptFieldLiveValue name(state.body!)))); updateFrameTitles(); } svoid enableBodyControls(bool b) { var panels = ll(scpVisionConfig, scpWheelsConfig); for (var c : concatMap(panel -> allChildrenOfType JComponent(panel), panels)) if (isInstanceOfAny(c, JCheckBox.class, JRadioButton.class, JTextField.class) && !c instanceof BodyNameField) setEnabled(c, b); // Modify body button is enabled iff controls are not enabled for (var c : concatMap(panel -> allChildrenOfType ModifyBodyButton(panel), panels)) setEnabled(c, !b); } svoid showHelp() { S text = loadSnippet(helpTextID); S heading = firstLine(text); trim(dropFirstLine(text)); showCenterFrame(swingScale(650), swingScale(500), heading, makeUneditableWithTextColor(Color.black, wordWrapTextArea(text))); } // run in Swing thread svoid showHistory { Font ttFont = loadFont_cached(monospacedFontID, 12), helpFont = sansSerifFont(13); if (historyFrame == null) historyFrame = getFrame(showCenterFrame(maxPt(pt(800, 600), scalePt(600, 350, swingFontScale())), "History", withMargin(centerAndSouthWithMargin(spacing, centerAndSouthWithMargin( historyTextArea1, westAndCenterWithMargin(spacing, setFont(ttFont, topAlignLabel(jMultiLineLabel( linesLL("Step #", "Percept", "Binon #", "", "Expect", "Binon #", "", "Action", "Binon #", "", "Action", "Binon #", "")))), setFont(ttFont, historyTextArea2)) ), centerAndEastWithMargin( setFont(helpFont, jMultiLineLabel(historyHelp)), jvstackWithSpacing( jButton("See World", r showWorld), jButton("See Memory", r showMemory)) ))))); else frameToFront(historyFrame); updateFrameTitles(); } // run in Swing thread svoid showMemory { Font ttFont = typeWriterFont(12), helpFont = sansSerifFont(13); S Interestng; if (smarty.InterestLevels == 3) Interestng = smarty.IntSymb(smarty.INTERESTING) + "=Interesting, "; else // Only 2 interest levels Interestng = ""; S IntSymbol = " " + smarty.IntSymb(smarty.NOVEL) + " = Novel, " + Interestng + smarty.IntSymb(smarty.FAMILIAR) + " = Familiar"; // originally: BinonDisplay.ObjListTitle.Caption S title = "Bn# OL Ty TL BL TR BR V L R In LQ RQ Pattern " + " l = Left target, r = Right target," + IntSymbol; if (memoryFrame == null) memoryFrame = getFrame(showCenterFrame(scalePt(600, 350, swingFontScale()), "Smarty's Memory", jvsplit(0.5, 100, centerAndEastWithMargins( northAndCenterWithMargin( setFont(ttFont, jLabel(title)), setFont(ttFont, memoryTextArea1)), jvstackWithSpacing( jButton("See World", r showWorld), jButton("See History", r showHistory)) ), memoryTextArea2, ) )); else frameToFront(memoryFrame); updateFrameTitles(); } svoid showWorld { frameToFront(mainFrame); } static JRadioButton visionModeRadioButton(SmartyBody body, ButtonGroup buttonGroup, S visionMode, S text) { var rb = jradiobutton(buttonGroup, text, eq(body.visionMode, visionMode)); onChange(rb, r { if (isChecked(rb)) { cset(body, +visionMode); body.userCausedChange(); } }); ret rb; } sclass ModifyBodyButton extends JButton { *() { super("Modify Smarty's Body"); main addActionListener(this, r modifyBody); } } // enable the controls to edit the body, after confirmation svoid modifyBody { if (state.body->used) { if (!confirmOKCancel("Modifying Smarty's body will reset its state. Do you wish to continue?")) ret; resetSmarty(); cset(state.body, used := false); } enableBodyControls(true); } sclass BodyNameField extends JTextField { *() { setEnabled(false); } } static JComponent bodyNamePanel(SmartyBody body) { SimpleLiveValue lv = conceptFieldLiveValue name(body); lv.onChange(r { body.userCausedChange() }); ret hstackWithSpacing( jMinWidth(swingScale(250), withLabel("Body name:", bindTextComponentToLiveValue(lv, swing(() -> new BodyNameField)))), swing(() -> new ModifyBodyButton)); } static JComponent visionConfigPanel(SmartyBody body) { var buttonGroup = buttonGroup(); ret northAndCenterWithMargins(spacing, bodyNamePanel(body), westAndCenterWithMargin(spacing, jCenteredSection("Camera", withLeftMargin(spacing, jvstackWithSpacing(spacing, itemPlus(jlabel("Select the camera directions"), map(CameraDirection.all, direction -> { var cb = jCheckBox(direction, body.cameraDirections.contains(direction)); onChange(cb, r { addOrRemove(body.cameraDirections, direction, isChecked(cb)); body.userCausedChange(); }); ret cb; }))))), jCenteredSection("Vision mode", jvstack( withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS(replaceSymbols([[ Square locations are identified with a letter. Looking down provides the letter of the current square. Looking in other directions provides the letter in the next square depending on the direction Smarty is facing. If it is a wall then the symbolic stimulus is a $wallSymbol ]])))), visionModeRadioButton(body, buttonGroup, VisionMode.nextSquare, "Looking at the next square (symbolic values = letter in square)"), verticalStrut(20), withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS([[ Looking at the distance to the nearest wall will provide the number of squares from the current position to the wall in the direction the camera is facing. A wall next to the robot is one square away. Looking down will always return 1. ]]))), visionModeRadioButton(body, buttonGroup, VisionMode.distanceToWall, "Distance to wall (magnitude values = number of squares)"), verticalStrut(20), withLeftMargin(spacing*2, jMultiLineLabel(unindentMLS([[ Looking at the next square will either see a wall or an empty square ]]))), visionModeRadioButton(body, buttonGroup, VisionMode.wallOrNot, replaceSymbols("Wall or not (symbolic values = $wallSymbol for a wall and $noWallSymbol for no wall)")), )))); } svoid showVisionConfig(SmartyBody body) { showPackedFrame("Configure Smarty's Vision", visionConfigPanel(body)); } static JCheckBox wheelsConfigCheckBox(SmartyBody body, S symbol, S text) { var cb = jCheckBox(text, body.wheels.contains(symbol)); onChange(cb, r { addOrRemove(body.wheels, symbol, isChecked(cb)); body.userCausedChange(); }); ret cb; } static JComponent wheelsConfigPanel(SmartyBody body) { ret northAndCenterWithMargins(spacing, bodyNamePanel(body), vstackWithSpacing(spacing, westAndCenterWithMargin(spacing, jCenteredSection("Movement", withLeftMargin(spacing, jvstackWithSpacing( jlabel("Select the wheel motions"), wheelsConfigCheckBox(body, "MoveForward", "Forward = f"), wheelsConfigCheckBox(body, "MoveLeft", "Left = l"), wheelsConfigCheckBox(body, "MoveRight", "Right = r"), wheelsConfigCheckBox(body, "MoveBackward", "Backward = b"), ))), jCenteredSection("Help", withLeftMargin( jTopLabel(hhtml(nlToBr(mls_replaceDollarVars(winToUnicode([[ Motion in any direction will move one square. If there is a wall in the way it will not move. A "-" indicates no motion. The direction moved depends on the direction Smarty is facing. Smarty will appear as a $smiley if it cannot turn. It will then always be facing North (up) so moving right will move to the East (right). ]]), smiley := himgForJLabel(#1102987, width := swingScale(15), height := swingScale(15), align := "middle")))))))), westAndCenterWithMargin(spacing, jCenteredSection("Turning", withLeftMargin(spacing, vstackWithSpacing( wheelsConfigCheckBox(body, "TurnRight", "Turn to the right = Rotate clockwise 90 degrees = " + winToUnicode(Smarty.TurnRght)), wheelsConfigCheckBox(body, "TurnLeft", "Turn to the left = Rotate anti-clockwise 90 degrees = " + winToUnicode(Smarty.TurnLft)), wheelsConfigCheckBox(body, "TurnAround", "Turn around = Rotate 180 degrees = " + winToUnicode(Smarty.TurnArnd)), ))), jCenteredSection("Help", withLeftMargin(jMultiLineLabel(winToUnicode(mls_replaceDollarVars([[ 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. ]], left := Smarty.LeftArrow, right := Smarty.RightArrow, up := Smarty.UpArrow, down := Smarty.DownArrow)))))), jCenteredSection("Sensing", withLeftMargin(spacing, wheelsConfigCheckBox(body, "AddAWheelSensor", "Add a wheel sensor to detect if it moved or failed because it was up against a wall")) ) )); } svoid showWheelsConfig(SmartyBody body) { var buttonGroup = buttonGroup(); showPackedFrame("Configure Smarty's Wheels", wheelsConfigPanel(body)); } svoid showSmartyConfig { showPackedFrameMinWidth(400, "Design or Select a body for Smarty", withMargin(centeredButtons( "Vision", r { showVisionConfig(state.body!) }, "Wheels", r { showWheelsConfig(state.body!) }, )) ); } // e.g. $wallSymbol and $noWallSymbol sS replaceSymbols(S s) { ret replaceDollarVars(s, +wallSymbol, +noWallSymbol); } sS exportWorldForSaving() { new LS lines; lines.add(" " + state.gridRows); for (int y = 0; y < state.gridRows; y++) for (int x = 0; x < state.gridCols; x++) { JCell cell = getCell(x, y); lines.add(state.smartyX == x && state.smartyY == y ? "A" : cell.obstacle() ? "#" : " "); } ret lines(lines); } svoid saveWorld(File f) { S text = exportWorldForSaving(); saveTextFile(f, text); infoBox("World saved: " + fileName(f)); cset(state, worldName := fileNameWithoutExtension(f), worldChanged := false); addRecentWorldFile(f); } svoid addRecentWorldFile(File f) swing { removeAndPut(state.recentWorldFiles, f, true); state.change(); makeMenus(); } svoid addRecentBodyFile(File f) swing { removeAndPut(state.recentBodyFiles, f, true); state.change(); makeMenus(); } svoid loadWorld(File f) { pcall-messagebox { LS lines = linesFromFile_list(f); if (eqAfterRtrim(lines(lines), exportWorldForSaving())) ret with infoBox("World is the same as current one"); int i = 0; int gridRows = parseInt(trim(lines.get(i++))); if (gridRows < 1 || gridRows > maxWorldSize) fail("Bad world size: " + gridRows); setWorldSize(gridRows); for y to gridRows: for x to gridRows: { S line = lines.get(i++); JCell cell = getCell(x, y); if (eq(line, "#")) cell.setObstacle(true); else if (eq(line, "A")) state.moveSmarty(x, y); } rearrangeLetters(); repaintGrid(); cset(state, worldName := fileNameWithoutExtension(f)); cset(state, worldChanged := false); infoBox("World loaded: " + fileName(f)); addRecentWorldFile(f); } } svoid saveWorldDialog(Runnable whenDone default null) { swing { JFileChooser fileChooser = new(mainDir()); fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty World files (*.\*worldFileExtension*/)", worldFileExtension)); if (fileChooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) { File f = defaultExtension(worldFileExtension, fileChooser.getSelectedFile()); saveWorld(f); infoBox("World saved as " + f.getName()); } else messageBox("World NOT saved"); callF(whenDone); } } svoid withWorldSave(Runnable r) { if (state.worldChanged) { int result = swingShowConfirmDialog(mainFrame, "World has changed! - Save it?", "Smarty", JOptionPane.YES_NO_CANCEL_OPTION); if (result == JOptionPane.YES_OPTION) { saveWorldDialog(r); ret; } else if (result == JOptionPane.CANCEL_OPTION) ret; else cset(state, worldChanged := false); } r.run(); } svoid loadWorldDialog { withWorldSave(r loadWorldDialogWithoutConfirmation); } svoid loadWorldDialogWithoutConfirmation swing { JFileChooser fileChooser = new(mainDir()); fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty World files (*.\*worldFileExtension*/)", worldFileExtension)); if (fileChooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) loadWorld(fileChooser.getSelectedFile()); } svoid newWorld { withWorldSave(r newWorldWithoutConfirmation); } svoid newWorldWithoutConfirmation(int size default defaultWorldSize) { setWorldSize(size); cset(state, worldName := "Empty", worldChanged := false); updateFrameTitles(); } static File mainDir() { ret mkdirs(userDir("Adaptron/Smarty")); } sS exportBodyForSaving() { S[] Body = new[22]; bodyToArray(state.body!, Body); ret lines(dropFirst(Body)); } svoid saveBody(File f) { S text = exportBodyForSaving(); saveTextFile(f, text); cset(state.body!, changed := false); addRecentBodyFile(f); } svoid bodyToArray(SmartyBody b, S[] Body) { Body[1] = escapeNewLines(b.name); // TODO: remaining values from AI? Body[2] = "1"; //Vision.Value = 1 - checked Body[3] = "0"; //Touch.Value Body[4] = b.wheelsFlag("AddAWheelSensor"); Body[5] = "1"; //Wheels.Value Body[6] = "0"; //Arms.Value Body[7] = b.cameraDirections.contains(CameraDirection.down) ? "1" : "0"; //VisionConfig.VisionDown Body[8] = b.cameraDirections.contains(CameraDirection.left) ? "1" : "0"; //VisionConfig.VisionLeft Body[9] = b.cameraDirections.contains(CameraDirection.right) ? "1" : "0"; //VisionConfig.VisionRight Body[10] = b.cameraDirections.contains(CameraDirection.inFront) ? "1" : "0"; //VisionConfig.VisionInFront Body[11] = b.cameraDirections.contains(CameraDirection.behind) ? "1" : "0"; //VisionConfig.VisionBehind Body[12] = eq(b.visionMode, VisionMode.nextSquare) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(0) Body[13] = eq(b.visionMode, VisionMode.distanceToWall) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(1) Body[14] = b.wheelsFlag("MoveForward"); Body[15] = b.wheelsFlag("MoveLeft"); Body[16] = b.wheelsFlag("MoveRight"); Body[17] = b.wheelsFlag("MoveBackward"); Body[18] = b.wheelsFlag("TurnRight"); Body[19] = b.wheelsFlag("TurnLeft"); Body[20] = b.wheelsFlag("TurnAround"); Body[21] = eq(b.visionMode, VisionMode.wallOrNot) ? "True" : "False"; //VisionConfig.VisionSymbolicOrMagnitude(2) } svoid withBodySave(Runnable r) { if (state.body->changed) { int result = swingShowConfirmDialog(mainFrame, "Body has changed! - Save it?", "Smarty", JOptionPane.YES_NO_CANCEL_OPTION); if (result == JOptionPane.YES_OPTION) { saveBodyDialog(r); ret; } else if (result == JOptionPane.CANCEL_OPTION) ret; else cset(state.body, changed := false); } r.run(); } svoid newBody { withBodySave(r newBodyWithoutConfirmation); } svoid newBodyWithoutConfirmation { cdelete(state.body!); cset(state, body := cnew(SmartyBody)); finishBodySetup(); } svoid loadBody(File f) { pcall-messagebox { LS lines = linesFromFile_list(f); if (eqAfterRtrim(lines(lines), exportBodyForSaving())) ret with infoBox("Body is the same as current one"); S[] Body = asStringArray(itemPlusList("", lines)); newBody(); var b = state.body!; // TODO: remaining values cset(b, name := Body[1]); if (eq(Body[4], "1")) b.wheels.add("AddAWheelSensor"); if (eq(Body[7], "1")) b.cameraDirections.add(CameraDirection.down); if (eq(Body[8], "1")) b.cameraDirections.add(CameraDirection.left); if (eq(Body[9], "1")) b.cameraDirections.add(CameraDirection.right); if (eq(Body[10], "1")) b.cameraDirections.add(CameraDirection.inFront); if (eq(Body[11], "1")) b.cameraDirections.add(CameraDirection.behind); if (eq(Body[12], "True")) b.visionMode = VisionMode.nextSquare; if (eq(Body[13], "True")) b.visionMode = VisionMode.distanceToWall; if (eq(Body[14], "1")) b.wheels.add("MoveForward"); if (eq(Body[15], "1")) b.wheels.add("MoveLeft"); if (eq(Body[16], "1")) b.wheels.add("MoveRight"); if (eq(Body[17], "1")) b.wheels.add("MoveBackward"); if (eq(Body[18], "1")) b.wheels.add("TurnRight"); if (eq(Body[19], "1")) b.wheels.add("TurnLeft"); if (eq(Body[20], "1")) b.wheels.add("TurnAround"); if (eq(Body[21], "True")) b.visionMode = VisionMode.wallOrNot; cset(b, changed := false); b.change(); updateTabs(); infoBox("Body loaded: " + fileName(f)); addRecentBodyFile(f); finishBodySetup(); } } svoid saveBodyDialog(Runnable whenDone default null) { swing { new JFileChooser fileChooser; fileChooser.setSelectedFile(newFile(mainDir(), sanitizeFileName(state.body->name))); fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty Body files (*.\*bodyFileExtension*/)", bodyFileExtension)); if (fileChooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) { File f = defaultExtension(bodyFileExtension, fileChooser.getSelectedFile()); cset(state.body, name := fileNameWithoutExtension(f)); updateTabs(); saveBody(f); infoBox("Body saved as " + f.getName()); } callF(whenDone); } } svoid loadBodyDialog { withBodySave(r loadBodyDialogWithoutConfirmation); } svoid loadBodyDialogWithoutConfirmation swing { JFileChooser fileChooser = new(mainDir()); fileChooser.setFileFilter(new FileNameExtensionFilter("Smarty Body files (*.\*bodyFileExtension*/)", bodyFileExtension)); if (fileChooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) loadBody(fileChooser.getSelectedFile()); } sS infosForWindowTitle() { ret " - World= " + state.worldName + ", Body= " + state.body->name + ", Run done on " + simpleDateFormat_defaultTZ_now("MM-dd-YYYY") + " (mm-dd-yyyy) " + simpleDateFormat_defaultTZ_now("HH:mm:ss"); } svoid updateFrameTitles { frameTitle(mainFrame, "Smarty's World" + infosForWindowTitle()); frameTitle(historyFrame, "Stimulus/Response, Percept/Action History" + infosForWindowTitle()); frameTitle(memoryFrame, "Smarty's Memory" + infosForWindowTitle()); } // Make the dynamic menus svoid makeMenus { addMenu(mainFrame, "Worlds", "New... (Ctrl+N)", r newWorld, "Retrieve... (Ctrl+R)", r loadWorldDialog, "Save... (Ctrl+S)", r saveWorldDialog, "---", mapWithIndexStartingAt1(reversed(keys(state.recentWorldFiles)), (idx, f) -> jMenuItem(idx + " " + fileName(f), r { withWorldSave(r { loadWorld(f) }) })), empty(state.recentWorldFiles) ? null : "---", "Exit", rThread killVM); addMenu(mainFrame, "Bodies", "New... (Ctrl+N)", r newBody, "Retrieve... (Ctrl+R)", r loadBodyDialog, "Save... (Ctrl+S)", r saveBodyDialog, "---", mapWithIndexStartingAt1(reversed(keys(state.recentBodyFiles)), (idx, f) -> jMenuItem(idx + " " + fileName(f), r { withBodySave(r { loadBody(f) }) })), empty(state.recentBodyFiles) ? null : "---", "Exit", rThread killVM); } svoid goCmd { smartyQ.add(r goCmd_impl); } svoid goCmd_impl { pcall-messagebox { evalWithTimeout(10.0, r { print("goCmd"); if (!state.body->used) { finishBodySetup(); cset(state.body, used := true); enableBodyControls(false); } smarty.bodies.BodyFunction2(); }); } } static int Indx(int row, int col) { // C is the across / column location - 0 based // R is the down / row location - 0 based // the function gives the index into NG and CWP linear arrays - 0 based // can not be greater than 199 because 200+ used for wall letters ret state.gridCols * row + col; } // NG(I).Caption is contents of cell x/y // with I = WallNo(x, y, direction) // NG Caption is either "" or smarty.Smarty // or Chr$(64 + InNG - 200) [location letter?] // WP$ seems to hold the playing field // WP$(R, C) can be ABlock$ /* From Brett: WP$ contains either a space, a block or the smarty symbol. The smarty symbol may be an S, >, <, ^, v or + depending on which way smarty is pointing. NG().captions contain the letter for each location. The LookUnder$() routine returns the letter for the camera that looks down at the current square. LookNorth$() etc. and other Look routines return the cell letter that is one cell away. The higher index values into NG() can contain letter for the walls set by the IDWalls() routine. But this feature is not in use and the higher index entries of NG are invisible so a mouse down cannot be done on them. Note also that ScopeLeft$() and other Scope routines that would return wall letters are not in use. */ static int InRow() { ret state.smartyY; } static int InCol() { ret state.smartyX; } svoid setSmartyDirection(S smartyDirection) { if (cset_trueIfChanged(state, +smartyDirection)) repaintGrid(); } // query cell for Smarty's brain sS WP(int y, int x) { if (x == InCol() && y == InRow()) ret state.smartyDirection; else ret getCell(x, y).obstacle() ? smarty.ABlock : smarty.ASpace; } // put more static functions here sclass TheWorld extends Smarty.TheWorld { // find what letter we are standing on public String LookUnder() { ret str(smartyCell().letter); } void moveRelative(int x, int y) { x += state.smartyX; y += state.smartyY; if (!inGrid(x, y) || getCell(x, y).obstacle()) smarty.Motion = smarty.NoMove; else { smarty.Motion = "Y"; state.moveSmarty(x, y); } } public void MoveWest() { moveRelative(-1, 0); } public void MoveSouth() { moveRelative(0, 1); } public void MoveEast() { moveRelative(1, 0); } public void MoveNorth() { moveRelative(0, -1); } public void DisplayStimuliAndResponse(int[][][] inputValues, char response) { new L leftStack; new L rightStack; for (int Sens = 1; Sens <= smarty.NumSenses; Sens++) { int NumSensors = smarty.Senses[Sens][smarty.NumberOfSensors]; if (NumSensors == 0) continue; if (NumSensors != 1) warn("More than one sensor in sense"); S label = smarty.Sense[Sens] + ":"; var inputValue = inputValues[Sens][smarty.Valu][smarty.Fired]; S text; if (smarty.Senses[Sens][smarty.SymbolicOrMagnitude] == smarty.Magnitude) text = str(charPlus(inputValue , '0')) + (debugValues ? " [magn " + inputValue + "]" : ""); else text = lookupOrKeep(winToUnicode, str((char) inputValue)) + (debugValues ? " [char " + inputValue + "]" : ""); // A, B, C etc leftStack.add(withLabel(withTypeWriterFont(jlabel(label)), jlabel(text))); } for (int Devs = 1; Devs <= smarty.NumDevices; Devs++) { S label = smarty.Device[Devs] + ":"; rightStack.add(withLabel(withTypeWriterFont(jlabel(label)), jlabel(winToUnicode(response)))); } scpStimuliAndResponse.set(jhgridWithSpacing( vstack(leftStack), vstack(rightStack))); } public void Update_View() { // called by World.LookInside_Click() to SeeHistory and Bodies.BodyFunction2() // refreshes all the subwindows historyDisplay(); dumpLTM(); } public void setBinonDisplayObjList(S text) { cset(state, memory1 := text); setText(memoryTextArea1, winToUnicode(text)); } public void setBinonDisplayChngResults(S text) { cset(state, binonDisplayChngResults := text); rstUpdateChngResults.trigger(); } public void appendBinonDisplayChngResults(S text) { cset(state, binonDisplayChngResults := state.binonDisplayChngResults+text); rstUpdateChngResults.trigger(); } S lookDirection(int dx, int dy) { int x = InCol()+dx, y = InRow()+dy; // If off top of board or next one is a block if (inGrid(x, y)) // must be on board if (eq(WP(y, x), smarty.ABlock)) ret smarty.Wall; // looking at a wall else // valid square to move into ret str(getCell(x, y).letter); else // looking beyond grid ret smarty.Wall; } public S LookNorth() { ret lookDirection(0, -1); } public S LookSouth() { ret lookDirection(0, 1); } public S LookWest() { ret lookDirection(-1, 0); } public S LookEast() { ret lookDirection( 1, 0); } public void PointUnder() { setSmartyDirection(smarty.Smarty); } public void PointNorth() { setSmartyDirection(smarty.UpArrow); } public void PointSouth() { setSmartyDirection(smarty.DownArrow); } public void PointWest() { setSmartyDirection(smarty.LeftArrow); } public void PointEast() { setSmartyDirection(smarty.RightArrow); } public int RangeNorth() { ret rangeDirection(0, -1); } public int RangeSouth() { ret rangeDirection(0, 1); } public int RangeWest() { ret rangeDirection(-1, 0); } public int RangeEast() { ret rangeDirection( 1, 0); } public int rangeDirection(int dx, int dy) { // Distance to wall int x = InCol(), y = InRow(); int i = 0; do { ++i; x += dx; y += dy; // End if off rightside of board or next one is a block } while (inGrid(x, y) && !getCell(x, y).obstacle()); ret i; } public void showSensorValues(S text) { cset(state, sensorValuesText := text); setText(taSensorValues, winToUnicode(text)); } public void showDeviceValues(S text) { cset(state, deviceValuesText := text); setText(taDeviceValues, winToUnicode(text)); } } // end of TheWorld svoid initSmarty { smarty.World = new TheWorld; smarty.Initialize_Adaptron(); } svoid resetSmarty aka finishBodySetup() { print("Finishing body setup"); ResetSmartyLocation(); smarty.Reset_Adaptron(); // set all memory, S-List, Habit stack cset(state, history1 := "", history2 := "", memory1 := ""); setText(historyTextArea1, ""); setText(historyTextArea2, ""); setText(memoryTextArea1, ""); setText(memoryTextArea2, ""); bodyToArray(state.body!, smarty.BodySetting); //pnl("BodySetting", smarty.BodySetting); /*if (Vision.Value = 1)*/ smarty.SetupVision(); //if (Touch.Value = 1) smarty.SetupTouch(); /*if (Wheels.Value = 1)*/ smarty.SetupWheels(); //if (Arms.Value = 1) smarty.SetupArms(); SetupStimulusResponseDisplay(); //Setup display of stimuli at bottom of World screen updateTabs(); } // not needed svoid SetupStimulusResponseDisplay {} // from Adapt.frm / HISTORYDISPLAY svoid historyDisplay { new LS lines; StringBuilder[] ILines$ = new[10+1]; int GroupSize = 250; // After 250 events the IO.Text area wraps the lines new StringBuilder NumberLine$; new StringBuilder OLine1$; for (int Group = 0; Group <= (smarty.LIN - 1) / GroupSize; Group++) { int EndLIN = min(GroupSize * Group + GroupSize, smarty.LIN); for (int E = GroupSize * Group + 1; E <= EndLIN; E++) { if (E == GroupSize * Group + 1) { // If it is the 1st position / event in the line then NumberLine$ = new StringBuilder("Step # : "); for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) // Add labels to start of lines ILines$[Sn] = new StringBuilder(takeFirst(smarty.Sense[Sn] + ": ", 9)); // The name of the sense OLine1$ = new StringBuilder(takeFirst(smarty.Device[1] + ": ", 9)); // The name of the action device } S E_str = " " + E; // visual-basic style int-to-string! NumberLine$.append(E_str); // the event number int Wdth = l(E_str); // the space taken up by the event number for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) ILines$[Sn].append(takeLast(" " + smarty.INPUTS[E][Sn], Wdth)); OLine1$.append(takeLast(" " + smarty.OUTPUTS[E][1], Wdth)); } lines.add(str(NumberLine$)); for (int Sn = 1; Sn <= smarty.NumSenses; Sn++) lines.add(str(ILines$[Sn])); lines.add(str(OLine1$)); lines.add(""); } S text = rtrim(lines(lines)); cset(state, history1 := text); setText(historyTextArea1, winToUnicode(text)); } // end of historyDisplay svoid dumpLTM { //Called by Update_View String MemValT = null; int[] MemSize = new[2000 + 1]; String Sen = null; String Att = null; String Pe = null; String Ob = null; Object BinTyp = null; boolean DisplayIt = false; //a Spac$, //'-------------------- Long Term Memory (LTM) - Monitoring Info. ------------------------- // 'For Display purposes only by Adapt.DUMPLTM in Adapt.LTMem // 'Long term memory contains a list of the stimuli that have been paid attention to. // 'It stores Perceptual sequences as a pair of sequential memory locations. // // Public LTMEMORY&(1 To 2000, 1 To 6) // '1st index is StoreAt cycle number // '2nd index is what type of information is in the LTM // // '---- LTMEMORY() 2nd index values - type of information in LTMEMORY() // Public LtmPerceptTyp '1 Percept binon type // Public LtmPerceptBin '2 Percept binon // Public LtmESType '3 Type of ES Binon - may be an SS // Public LtmESActBin '4 ES Actbin // Public LtmARType '5 Type of AR Binon - may be an RR // Public LtmARActBin '6 AR ActBin // Public LtmActionTyp '7 Action binon type // Public LtmActionBin '8 Action binon for (var I = 1; I <= smarty.StoreAt; I++) //find the widest binon # for all the StoreAt positions { MemSize[I] = intMax( l(str(I))+1, 3, l(vbToStr(smarty.LTMEMORY[I][smarty.LtmPerceptBin])), l(vbToStr(smarty.LTMEMORY[I][smarty.LtmESActBin])), l(vbToStr(smarty.LTMEMORY[I][smarty.LtmARActBin])), l(vbToStr(smarty.LTMEMORY[I][smarty.LtmActionBin]))); } new StringBuffer text; int GroupSize = 250; var tempVar = (smarty.StoreAt - 1) / GroupSize; for (int Group = 0; Group <= (smarty.StoreAt - 1) / GroupSize; Group++) { int EndLIN = GroupSize * Group + GroupSize; //Only put up the available values if (EndLIN > smarty.StoreAt) EndLIN = smarty.StoreAt; new StringBuilder MemLine; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM display the event number MemLine.append(pad(MemSize[E], str(E))); text.append(MemLine + "\r\n"); //------Percepts(.., Fired) Type MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = smarty.BinonTypeName[smarty.LTMEMORY[E][smarty.LtmPerceptTyp]][smarty.BinAbbreviation]; //Att$ = Str$(STM(1, BinTp, Current)) MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n"); //------Percepts(.., Fired) Binon MemLine = new StringBuilder; //Trigger STIMULUS intensity for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = str(smarty.LTMEMORY[E][smarty.LtmPerceptBin]); //Att$ = Str$(STM(1, BinId, Current)) MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n\r\n"); //------ES ActBin type MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = smarty.AESR(smarty.LTMEMORY[E][smarty.LtmESActBin]); MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n"); //------ LTMEMORY ActBin Object binon MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmESActBin]); MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n\r\n"); //------AR ActBin type MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = smarty.AESR(smarty.LTMEMORY[E][smarty.LtmARActBin]); MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n"); //------ LTMEMORY ActBin Object binon MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmARActBin]); MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n\r\n"); //------Actions(.., Fired) Type MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = smarty.BinonTypeName[smarty.LTMEMORY[E][smarty.LtmActionTyp]][smarty.BinAbbreviation]; MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n"); //------Actions(.., Fired) Binon MemLine = new StringBuilder; for (int E = GroupSize * Group + 1; E <= EndLIN; E++) //For each event in LTM { Att = String.valueOf(smarty.LTMEMORY[E][smarty.LtmActionBin]); MemLine.append(pad(MemSize[E], Att)); } text.append(MemLine + "\r\n\r\n"); } S s = rtrim(str(text)); cset(state, history2 := s); setText(historyTextArea2, winToUnicode(s)); } //End of dumpLTM svoid uiZoom(double percent) { if (cset_trueIfChanged(state, fontScale := toFloat(percent/100))) restart(); } svoid updateFontScale(float scale) { swingFontScale(scale); spacing = iround(defaultSpacing*scale); } svoid selfTest { new SelfTest().run(); } sclass SelfTest { new Scorer scorer; void loadWorldAndBody(S worldText, S bodyText) { File bodyFile = programFile("body.tmp"); File worldFile = programFile("world.tmp"); saveTextFile(worldFile, dropLeadingEmptyLines(worldText)); loadWorld(worldFile); saveTextFile(bodyFile, dropLeadingEmptyLines(bodyText)); loadBody(bodyFile); } run { activateConsole(); print("Self-Test START"); S text = loadSnippet(#1031220); LS parts = splitAtMultipleEqualsLines(text); assertEqualsVerbose(6, l(parts)); loadWorldAndBody(parts.get(0), parts.get(1)); LS outputTexts = subList(parts, 2); once { // step 1 if (!step(outputTexts)) break; text = loadSnippet(#1031228); outputTexts = getMulti(splitAtMultipleEqualsLines(text), 2, 3, 0, 1); // step 2 if (!step(outputTexts)) break; // step 10 text = loadSnippet(#1031229); outputTexts = getMulti(splitAtMultipleEqualsLines(text), 0, 1, 2, 3); repeat 7 { goCmd_impl(); } if (!step(outputTexts)) break; // step 50 text = loadSnippet(#1031230); outputTexts = getMulti(splitAtMultipleEqualsLines(text), 2, 3, 0, 1); repeat 39 { goCmd_impl(); } if (!step(outputTexts)) break; } // second test case text = loadSnippet(#1031231); parts = splitAtMultipleEqualsLines(text); assertEqualsVerbose(6, l(parts)); loadWorldAndBody(parts.get(0), parts.get(1)); once { // step 30 outputTexts = getMulti(subList(parts, 2), 2, 3, 0, 1); repeat 29 { goCmd_impl(); } if (!step(outputTexts)) break; } // third test case text = loadSnippet(#1031238); parts = splitAtMultipleEqualsLines(text); assertEqualsVerbose(6, l(parts)); loadWorldAndBody(parts.get(0), parts.get(1)); once { // step 50 outputTexts = getMulti(subList(parts, 2), 2, 3, 0, 1); repeat 49 { goCmd_impl(); } if (!step(outputTexts)) break; } print("SELF-TEST RESULT: " + scorer); } // returns false if something failed bool step(LS outputTexts) { goCmd_impl(); new LS diffs; printAsciiHeading("HISTORY 1"); print(addAndReturn(diffs, unidiff2(historyTextArea1, outputTexts.get(2)))); printAsciiHeading("HISTORY 2"); print(addAndReturn(diffs, unidiff2(historyTextArea2, outputTexts.get(3)))); printAsciiHeading("MEMORY 1"); print(addAndReturn(diffs, unidiff2(memoryTextArea1, outputTexts.get(0)))); printAsciiHeading("MEMORY 2"); print(addAndReturn(diffs, unidiff2(state.binonDisplayChngResults, outputTexts.get(1)))); bool ok = allStringsEmpty(diffs); scorer.add(ok, nOutputs(nempties(diffs)) + " differ"); ret ok; } } sS unidiff2(JTextComponent ta, S text) { ret unidiff2(getText(ta), text); } sS unidiff2(S actual, S text) { ret unidiff(cleanUpForDiff(text), cleanUpForDiff(actual)); } sS cleanUpForDiff(S text) { ret fixNewLines(rtrim(dropLeadingEmptyLines(text))); } svoid ResetSmartyLocation { if (!getCell(state.startX, state.startY).obstacle()) state.moveSmarty(state.startX, state.startY); } sS winToUnicode(O text) { ret mapCharacters(str(text), c -> lookupOrKeep(winToUnicode, str(c))); } static A monospaced(A a) { ret setFont(monospacedFontID, swingScale(monospacedFontSize), a); }