Author Topic: Flash Math v2.not-quite-0  (Read 3700 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Flash Math v2.not-quite-0
« on: August 10, 2019, 05:52:17 pm »
A revision of the math trainer which I wrote for children oh-so-many eons ago:

Code: QB64: [Select]
  1.  
  2. DEFLNG A-Z
  3. CONST Skyblue~& = &HFF87CEEB
  4. CONST Gold~& = &HFFFFD700
  5. CONST Black~& = &HFF000000
  6. CONST LightGray~& = &HFFD3D3D3
  7.  
  8.  
  9. SCREEN _NEWIMAGE(640, 480, 32)
  10.  
  11. DIM SHARED F75, F50, F25, F15
  12. F75 = _LOADFONT("courbd.ttf", 75)
  13. F50 = _LOADFONT("courbd.ttf", 50)
  14. F25 = _LOADFONT("courbd.ttf", 25)
  15. F15 = _LOADFONT("courbd.ttf", 20)
  16.  
  17. REDIM SHARED OName(0) AS STRING 'Operation Name
  18. REDIM SHARED PL(0) AS INTEGER 'Priority Level
  19. DIM SHARED QuickReturn AS INTEGER
  20. Set_OrderOfOperations 'This will also make certain our directories are valid, and if not make them.
  21.  
  22.  
  23.  
  24. TYPE OptionType
  25.     x AS INTEGER
  26.     y AS INTEGER
  27.     wide AS INTEGER
  28.     high AS INTEGER
  29.     choices AS INTEGER 'from 0 to choices, so subtract 1 from total number of choices
  30.     captions AS STRING ' "12345678901234567890" --10 spaces per choice, so the left would represent two choices
  31.     clicks AS INTEGER 'binary value of click state for our choices; up to 16 max
  32.     Font AS INTEGER
  33.  
  34. DIM SHARED Options(1 TO 3) AS OptionType
  35.  
  36. Options(1).x = 70: Options(1).y = 100: Options(1).high = 50: Options(1).wide = 100 '1 is mode
  37. Options(1).choices = 4: Options(1).captions = "+         -        *          /         RND       "
  38. Options(1).Font = F25: Options(1).clicks = 16 'rnd selected as default
  39.  
  40. Options(2).x = 70: Options(2).y = 200: Options(2).high = 50: Options(2).wide = 100 '2 is time
  41. Options(2).choices = 4: Options(2).captions = "15        30       60         120       300       "
  42. Options(2).Font = F25: Options(2).clicks = 4 '60 second default game
  43.  
  44. Options(3).x = 70: Options(3).y = 300: Options(3).high = 50: Options(3).wide = 100 '3 is difficulty
  45. Options(3).choices = 4:: Options(3).captions = "TRIVIAL   EASY     AVERAGE    HARD      INSANE    "
  46. Options(3).Font = F15: Options(3).clicks = 4 'average default setting
  47.  
  48. DIM SHARED opt$
  49. DIM SHARED FinishTime AS _FLOAT
  50. DIM SHARED LowNum AS INTEGER, Highnum AS INTEGER
  51.  
  52. DIM SHARED Problem(10000) AS STRING
  53. DIM SHARED Answer(10000) AS STRING
  54. DIM SHARED Guess(10000) AS STRING
  55.  
  56.  
  57.  
  58.  
  59.     SetupOptions
  60.     PlayGame
  61.  
  62.     _LIMIT 60
  63.  
  64. SUB PlayGame
  65.     oldmouse = -1: oldmouse2 = -1
  66.     s = SaveState
  67.     _FONT F75
  68.     ProblemsSolved = 0
  69.     DO
  70.         RedoDivisionByZero:
  71.         num1 = RND * Highnum + LowNum
  72.         num2 = RND * Highnum + LowNum
  73.         o$ = MID$(opt$, INT(RND * LEN(opt$) + 1), 1)
  74.         IF o$ = "/" THEN num1 = num1 * num2: IF num2 = 0 GOTO RedoDivisionByZero
  75.         IF o$ = "-" AND num1 < num2 THEN SWAP num1, num2
  76.         math$ = _TRIM$(STR$(num1)) + o$ + _TRIM$(STR$(num2))
  77.         answer$ = Evaluate_Expression$(math$)
  78.         guess$ = STRING$(LEN(answer$), "?"): g = 1
  79.         DO
  80.             TimeLeft = FinishTime - TIMER
  81.             IF TimeLeft <= 0 THEN EXIT DO
  82.             _LIMIT 30
  83.             CLS , 0
  84.             COLOR &HFFFA0000, 0: _PRINTSTRING (0, 0), STR$(TimeLeft)
  85.             FOR i = 0 TO 4
  86.                 BoxTitle 45 + i * 110, 240, 110, 100, 3, &HFF0FFF00, Gold, _TRIM$(STR$(i))
  87.                 BoxTitle 45 + i * 110, 340, 110, 100, 3, &HFF0FFF00, Gold, _TRIM$(STR$(i + 5))
  88.             NEXT
  89.  
  90.             WHILE _MOUSEINPUT: WEND
  91.             IF _MOUSEBUTTON(1) AND NOT oldmouse THEN 'it's a click
  92.                 Xclick = INT((_MOUSEX - 45) / 110)
  93.                 Yclick = INT((_MOUSEY - 240) / 100)
  94.                 Choice = Xclick + 5 * Yclick
  95.                 IF Choice >= 0 AND Choice <= 9 THEN
  96.                     MID$(guess$, g, 1) = _TRIM$(STR$(Choice))
  97.                     g = g + 1
  98.                 END IF
  99.             END IF
  100.             oldmouse = _MOUSEBUTTON(1): oldmouse2 = _MOUSEBUTTON(2)
  101.             display$ = math$ + "=" + guess$
  102.             COLOR &HFFFF0000, 0: BoxTitle 45, 100, 550, 100, 3, Skyblue, Gold, display$
  103.             _DISPLAY
  104.         LOOP UNTIL g > LEN(answer$)
  105.         ProblemsSolved = ProblemsSolved + 1
  106.         Problem(ProblemsSolved) = math$
  107.         Answer(ProblemsSolved) = answer$
  108.         Guess(ProblemsSolved) = guess$
  109.         IF guess$ = answer$ THEN
  110.             FinishTime = FinishTime + 1 '1 second extra time for each correct answer
  111.         ELSE
  112.             FinishTime = FinishTime - 1 'and a 1 second penalty for a wrong answer
  113.         END IF
  114.         TimeLeft = FinishTime - TIMER
  115.         IF TimeLeft <= 0 THEN EXIT DO
  116.     LOOP
  117.  
  118.     CLS
  119.     _FONT F25
  120.     PRINT "PROBLEM";
  121.     LOCATE , 200: PRINT "ANSWER";
  122.     LOCATE , 400: PRINT "GUESS"
  123.     i = 1
  124.     DO UNTIL i > ProblemsSolved
  125.         COLOR -1
  126.         PRINT i; Problem(i);
  127.         LOCATE , 200: PRINT Answer(i);
  128.         IF Guess(i) = Answer(i) THEN COLOR &HFF00FF00 ELSE COLOR &HFFFF0000
  129.         LOCATE , 400: PRINT Guess(i)
  130.         i = i + 1
  131.         IF i MOD 15 = 1 THEN
  132.             Mousepause
  133.             CLS
  134.             PRINT "PROBLEM";
  135.             LOCATE , 200: PRINT "ANSWER";
  136.             LOCATE , 400: PRINT "GUESS"
  137.         END IF
  138.     LOOP
  139.     IF i > ProblemsSolved THEN Mousepause ELSE SYSTEM
  140.     RestoreState s
  141.  
  142. SUB Mousepause
  143.     PRINT "Click <Left Button> for more results"
  144.     click = 0
  145.     DO
  146.         WHILE _MOUSEINPUT: WEND
  147.         IF _MOUSEBUTTON(1) THEN
  148.             DO
  149.                 _LIMIT 30
  150.                 j = _MOUSEINPUT
  151.             LOOP UNTIL _MOUSEBUTTON(1) = 0
  152.             click = -1
  153.         END IF
  154.         _LIMIT 30
  155.     LOOP UNTIL click
  156.  
  157.  
  158. SUB SetupOptions
  159.     s = SaveState
  160.     DO
  161.         _LIMIT 30
  162.         CLS
  163.         FOR i = 1 TO 3 '3 option sets to display
  164.             _FONT Options(i).Font
  165.             x1 = Options(i).x: y1 = Options(i).y
  166.             w = Options(i).wide: H = Options(i).high
  167.             clicks = Options(i).clicks
  168.             FOR j = 0 TO Options(i).choices
  169.                 t$ = _TRIM$(MID$(Options(i).captions, j * 10, 10))
  170.                 IF clicks AND 2 ^ j THEN
  171.                     COLOR Black, 0: BoxTitle x1 + j * w, y1, w, H, 3, Skyblue, Gold, t$
  172.                 ELSE
  173.                     COLOR LightGray, 0: BoxTitle x1 + j * w, y1, w, H, 3, Black, Gold, t$
  174.                 END IF
  175.             NEXT
  176.         NEXT
  177.         _FONT F50
  178.         COLOR Skyblue, 0
  179.         CenterText 0, 0, 640, 100, "Math Flash!"
  180.         COLOR Black, 0
  181.         BoxTitle 170, 390, 300, 60, 3, &HFF0FFF00, Gold, "PLAY"
  182.  
  183.         _DISPLAY
  184.         WHILE _MOUSEINPUT: WEND
  185.  
  186.         IF _MOUSEBUTTON(1) AND NOT oldmouse THEN 'if button was up, but is now down, then it's a click
  187.             ClickX = INT((_MOUSEX - 70) / 100): ClickY = _CEIL((_MOUSEY - 100) / 50)
  188.             IF ClickX >= 0 AND ClickX <= 4 THEN 'Click on menu item 0 to 4
  189.                 SELECT CASE ClickY '1 = top , 3 = middle, 5 = bottom
  190.                     CASE 1
  191.                         IF 2 ^ ClickX = 16 THEN
  192.                             IF Options(1).clicks AND 16 THEN Options(1).clicks = 0 ELSE Options(1).clicks = 16
  193.                         ELSE
  194.                             Options(1).clicks = Options(1).clicks XOR 2 ^ ClickX
  195.                             IF Options(1).clicks <> 16 THEN Options(1).clicks = Options(1).clicks AND NOT 16
  196.                         END IF
  197.                     CASE 3, 5
  198.                         Options(ClickY \ 2 + 1).clicks = 2 ^ ClickX
  199.                 END SELECT
  200.             END IF
  201.             IF _MOUSEX > 170 AND _MOUSEX < 470 AND _MOUSEY > 390 AND _MOUSEY < 450 THEN EXIT DO
  202.         END IF
  203.         oldmouse = _MOUSEBUTTON(1)
  204.     LOOP
  205.     opt$ = ""
  206.     IF Options(1).clicks = 16 THEN Options(1).clicks = INT(RND * 15) + 1
  207.     IF Options(1).clicks AND 1 THEN opt$ = opt$ + "+"
  208.     IF Options(1).clicks AND 2 THEN opt$ = opt$ + "-"
  209.     IF Options(1).clicks AND 4 THEN opt$ = opt$ + "/"
  210.     IF Options(1).clicks AND 8 THEN opt$ = opt$ + "*"
  211.     SELECT CASE Options(2).clicks
  212.         CASE 1: FinishTime = TIMER + 15
  213.         CASE 2: FinishTime = TIMER + 30
  214.         CASE 4: FinishTime = TIMER + 60
  215.         CASE 8: FinishTime = TIMER + 120
  216.         CASE 16: FinishTime = TIMER + 300
  217.     END SELECT
  218.     SELECT CASE Options(3).clicks
  219.         CASE 1: LowNum = 1: Highnum = 5
  220.         CASE 2: LowNum = 0: Highnum = 10
  221.         CASE 4: LowNum = 0: Highnum = 12
  222.         CASE 8: LowNum = 0: Highnum = 99
  223.         CASE 16: LowNum = 10: Highnum = 89
  224.     END SELECT
  225.     RestoreState s
  226.  
  227.  
  228. SUB BoxTitle (x1, y1, x2, y2, thick, fg AS _UNSIGNED LONG, bg AS _UNSIGNED LONG, title$)
  229.     Box x1, y1, x2, y2, thick, fg, bg
  230.     CenterText x1, y1 + thick, x1 + x2, y1 + y2 + thick, title$
  231.  
  232.  
  233. SUB Box (x, y, wide, high, thick, Kolor AS _UNSIGNED LONG, Trim AS _UNSIGNED LONG)
  234.     LINE (x, y)-STEP(wide, high), Trim, BF
  235.     LINE (x + thick, y + thick)-STEP(wide - 2 * thick, high - 2 * thick), Kolor, BF
  236.  
  237.  
  238. SUB CenterText (x1, y1, x2, y2, text$)
  239.     text$ = _TRIM$(text$)
  240.     xmax = x2 - x1: ymax = y2 - y1
  241.     textlength = _PRINTWIDTH(text$)
  242.     xpos = (xmax - textlength) / 2
  243.     ypos = (ymax - _FONTHEIGHT) / 2
  244.     _PRINTSTRING (x1 + xpos, y1 + ypos), text$
  245.  
  246. FUNCTION SaveState
  247.     TYPE SaveStateType
  248.         InUse AS INTEGER
  249.         DC AS INTEGER
  250.         BG AS INTEGER
  251.         F AS INTEGER
  252.         D AS INTEGER
  253.         S AS INTEGER
  254.         Disp AS INTEGER
  255.         CurX AS INTEGER
  256.         CurY AS INTEGER
  257.     END TYPE
  258.     DIM SS AS SaveStateType, Temp AS SaveStateType
  259.     SHARED NSS AS LONG 'Number of Saved States
  260.     SHARED SaveMem AS _MEM
  261.     IF NOT _MEMEXISTS(SaveMem) THEN
  262.         SaveMem = _MEMNEW(LEN(SS) * 255) 'Save up to 255 save states; More than 255 and we toss an error
  263.         $CHECKING:OFF
  264.         _MEMFILL SaveMem, SaveMem.OFFSET, SaveMem.SIZE, 0 AS _UNSIGNED _BYTE
  265.         $CHECKING:ON
  266.     END IF
  267.  
  268.     'Data to Save
  269.     SS.InUse = -1
  270.     SS.F = _FONT
  271.     SS.DC = _DEFAULTCOLOR
  272.     SS.BG = _BACKGROUNDCOLOR
  273.     SS.D = _DEST
  274.     SS.S = _SOURCE
  275.     SS.Disp = _AUTODISPLAY
  276.     SS.CurX = POS(0)
  277.     SS.CurY = CSRLIN
  278.     FOR i = 1 TO NSS
  279.         O = (i - 1) * LEN(SS)
  280.         _MEMGET SaveMem, SaveMem.OFFSET + O, Temp
  281.         IF Temp.InUse = 0 THEN
  282.             _MEMPUT SaveMem, SaveMem.OFFSET + O, SS
  283.             SaveState = i
  284.             EXIT FUNCTION
  285.         END IF
  286.     NEXT
  287.     _MEMPUT SaveMem, SaveMem.OFFSET + NSS * LEN(SS), SS
  288.     NSS = NSS + 1
  289.     SaveState = NSS
  290.  
  291. SUB RestoreState (WhichOne AS LONG)
  292.     DIM SS AS SaveStateType
  293.     SHARED NSS AS LONG 'Number of Saved States
  294.     SHARED SaveMem AS _MEM
  295.     _MEMGET SaveMem, SaveMem.OFFSET + (WhichOne - 1) * LEN(SS), SS
  296.     IF SS.InUse THEN
  297.         SS.InUse = 0 'Let the routine know that we're no longer in use for this handle
  298.         $CHECKING:OFF
  299.         _MEMPUT SaveMem, SaveMem.OFFSET + (WhichOne - 1) * LEN(SS), SS
  300.         $CHECKING:ON
  301.         _FONT SS.F
  302.         COLOR SS.DC, SS.BG
  303.         _DEST SS.D
  304.         _SOURCE SS.S
  305.         IF SS.Disp THEN _AUTODISPLAY ELSE _DISPLAY
  306.         LOCATE SS.CurY, SS.CurX
  307.     END IF
  308.  
  309. FUNCTION Evaluate_Expression$ (e$)
  310.     t$ = e$ 'So we preserve our original data, we parse a temp copy of it
  311.  
  312.     b = INSTR(UCASE$(e$), "EQL") 'take out assignment before the preparser sees it
  313.     IF b THEN t$ = MID$(e$, b + 3): var$ = UCASE$(LTRIM$(RTRIM$(MID$(e$, 1, b - 1))))
  314.  
  315.     QuickReturn = 0
  316.     PreParse t$
  317.  
  318.     IF QuickReturn THEN Evaluate_Expression$ = t$: EXIT FUNCTION
  319.  
  320.     IF LEFT$(t$, 5) = "ERROR" THEN Evaluate_Expression$ = t$: EXIT FUNCTION
  321.  
  322.     'Deal with brackets first
  323.     exp$ = "(" + t$ + ")" 'Starting and finishing brackets for our parse routine.
  324.  
  325.     DO
  326.         Eval_E = INSTR(exp$, ")")
  327.         IF Eval_E > 0 THEN
  328.             c = 0
  329.             DO UNTIL Eval_E - c <= 0
  330.                 c = c + 1
  331.                 IF Eval_E THEN
  332.                     IF MID$(exp$, Eval_E - c, 1) = "(" THEN EXIT DO
  333.                 END IF
  334.             LOOP
  335.             s = Eval_E - c + 1
  336.             IF s < 1 THEN PRINT "ERROR -- BAD () Count": END
  337.             eval$ = " " + MID$(exp$, s, Eval_E - s) + " " 'pad with a space before and after so the parser can pick up the values properly.
  338.             ParseExpression eval$
  339.  
  340.             eval$ = LTRIM$(RTRIM$(eval$))
  341.             IF LEFT$(eval$, 5) = "ERROR" THEN Evaluate_Expression$ = eval$: EXIT SUB
  342.             exp$ = DWD(LEFT$(exp$, s - 2) + eval$ + MID$(exp$, Eval_E + 1))
  343.             IF MID$(exp$, 1, 1) = "N" THEN MID$(exp$, 1) = "-"
  344.  
  345.             temppp$ = DWD(LEFT$(exp$, s - 2) + " ## " + eval$ + " ## " + MID$(exp$, E + 1))
  346.         END IF
  347.     LOOP UNTIL Eval_E = 0
  348.     c = 0
  349.     DO
  350.         c = c + 1
  351.         SELECT CASE MID$(exp$, c, 1)
  352.             CASE "0" TO "9", ".", "-" 'At this point, we should only have number values left.
  353.             CASE ELSE: Evaluate_Expression$ = "ERROR - Unknown Diagnosis: (" + exp$ + ") ": EXIT SUB
  354.         END SELECT
  355.     LOOP UNTIL c >= LEN(exp$)
  356.  
  357.     Evaluate_Expression$ = exp$
  358.  
  359.  
  360.  
  361. SUB ParseExpression (exp$)
  362.     DIM num(10) AS STRING
  363.     'We should now have an expression with no () to deal with
  364.     IF MID$(exp$, 2, 1) = "-" THEN exp$ = "0+" + MID$(exp$, 2)
  365.     FOR J = 1 TO 250
  366.         lowest = 0
  367.         DO UNTIL lowest = LEN(exp$)
  368.             lowest = LEN(exp$): OpOn = 0
  369.             FOR P = 1 TO UBOUND(OName)
  370.                 'Look for first valid operator
  371.                 IF J = PL(P) THEN 'Priority levels match
  372.                     IF LEFT$(exp$, 1) = "-" THEN op = INSTR(2, exp$, OName(P)) ELSE op = INSTR(exp$, OName(P))
  373.                     IF op > 0 AND op < lowest THEN lowest = op: OpOn = P
  374.                 END IF
  375.             NEXT
  376.             IF OpOn = 0 THEN EXIT DO 'We haven't gotten to the proper PL for this OP to be processed yet.
  377.             IF LEFT$(exp$, 1) = "-" THEN op = INSTR(2, exp$, OName(OpOn)) ELSE op = INSTR(exp$, OName(OpOn))
  378.             numset = 0
  379.  
  380.             '*** SPECIAL OPERATION RULESETS
  381.             IF OName(OpOn) = "-" THEN 'check for BOOLEAN operators before the -
  382.                 SELECT CASE MID$(exp$, op - 3, 3)
  383.                     CASE "NOT", "XOR", "AND", "EQV", "IMP"
  384.                         EXIT DO 'Not an operator, it's a negative
  385.                 END SELECT
  386.                 IF MID$(exp$, op - 3, 2) = "OR" THEN EXIT DO 'Not an operator, it's a negative
  387.             END IF
  388.  
  389.             IF op THEN
  390.                 c = LEN(OName(OpOn)) - 1
  391.                 DO
  392.                     SELECT CASE MID$(exp$, op + c + 1, 1)
  393.                         CASE "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N": numset = -1 'Valid digit
  394.                         CASE "-" 'We need to check if it's a minus or a negative
  395.                             IF OName(OpOn) = "_PI" OR numset THEN EXIT DO
  396.                         CASE ELSE 'Not a valid digit, we found our separator
  397.                             EXIT DO
  398.                     END SELECT
  399.                     c = c + 1
  400.                 LOOP UNTIL op + c >= LEN(exp$)
  401.                 E = op + c
  402.  
  403.                 c = 0
  404.                 DO
  405.                     c = c + 1
  406.                     SELECT CASE MID$(exp$, op - c, 1)
  407.                         CASE "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N" 'Valid digit
  408.                         CASE "-" 'We need to check if it's a minus or a negative
  409.                             c1 = c
  410.                             bad = 0
  411.                             DO
  412.                                 c1 = c1 + 1
  413.                                 SELECT CASE MID$(exp$, op - c1, 1)
  414.                                     CASE "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."
  415.                                         bad = -1
  416.                                         EXIT DO 'It's a minus sign
  417.                                     CASE ELSE
  418.                                         'It's a negative sign and needs to count as part of our numbers
  419.                                 END SELECT
  420.                             LOOP UNTIL op - c1 <= 0
  421.                             IF bad THEN EXIT DO 'We found our seperator
  422.                         CASE ELSE 'Not a valid digit, we found our separator
  423.                             EXIT DO
  424.                     END SELECT
  425.                 LOOP UNTIL op - c <= 0
  426.                 s = op - c
  427.                 num(1) = MID$(exp$, s + 1, op - s - 1) 'Get our first number
  428.                 num(2) = MID$(exp$, op + LEN(OName(OpOn)), E - op - LEN(OName(OpOn)) + 1) 'Get our second number
  429.                 IF MID$(num(1), 1, 1) = "N" THEN MID$(num(1), 1) = "-"
  430.                 IF MID$(num(2), 1, 1) = "N" THEN MID$(num(2), 1) = "-"
  431.                 num(3) = EvaluateNumbers(OpOn, num())
  432.                 IF MID$(num(3), 1, 1) = "-" THEN MID$(num(3), 1) = "N"
  433.                 'PRINT "*************"
  434.                 'PRINT num(1), OName(OpOn), num(2), num(3), exp$
  435.                 IF LEFT$(num(3), 5) = "ERROR" THEN exp$ = num(3): EXIT SUB
  436.                 exp$ = LTRIM$(N2S(DWD(LEFT$(exp$, s) + RTRIM$(LTRIM$(num(3))) + MID$(exp$, E + 1))))
  437.                 'PRINT exp$
  438.             END IF
  439.             op = 0
  440.         LOOP
  441.     NEXT
  442.  
  443.  
  444.  
  445.  
  446. SUB Set_OrderOfOperations
  447.     'PL sets our priortity level. 1 is highest to 65535 for the lowest.
  448.     'I used a range here so I could add in new priority levels as needed.
  449.     'OName ended up becoming the name of our commands, as I modified things.... Go figure!  LOL!
  450.  
  451.     'Constants get evaluated first, with a Priority Level of 1
  452.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_PI"
  453.     REDIM _PRESERVE PL(i): PL(i) = 1
  454.     'I'm not certain where exactly percentages should go.  They kind of seem like a special case to me.  COS10% should be COS.1 I'd think...
  455.     'I'm putting it here for now, and if anyone knows someplace better for it in our order of operations, let me know.
  456.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "%"
  457.     REDIM _PRESERVE PL(i): PL(i) = 5
  458.     'Then Functions with PL 10
  459.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ACOS"
  460.     REDIM _PRESERVE PL(i): PL(i) = 10
  461.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ASIN"
  462.     REDIM _PRESERVE PL(i): PL(i) = 10
  463.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ARCSEC"
  464.     REDIM _PRESERVE PL(i): PL(i) = 10
  465.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ARCCSC"
  466.     REDIM _PRESERVE PL(i): PL(i) = 10
  467.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ARCCOT"
  468.     REDIM _PRESERVE PL(i): PL(i) = 10
  469.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_SECH"
  470.     REDIM _PRESERVE PL(i): PL(i) = 10
  471.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_CSCH"
  472.     REDIM _PRESERVE PL(i): PL(i) = 10
  473.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_COTH"
  474.     REDIM _PRESERVE PL(i): PL(i) = 10
  475.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "COS"
  476.     REDIM _PRESERVE PL(i): PL(i) = 10
  477.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "SIN"
  478.     REDIM _PRESERVE PL(i): PL(i) = 10
  479.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "TAN"
  480.     REDIM _PRESERVE PL(i): PL(i) = 10
  481.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "LOG"
  482.     REDIM _PRESERVE PL(i): PL(i) = 10
  483.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "EXP"
  484.     REDIM _PRESERVE PL(i): PL(i) = 10
  485.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "ATN"
  486.     REDIM _PRESERVE PL(i): PL(i) = 10
  487.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_D2R"
  488.     REDIM _PRESERVE PL(i): PL(i) = 10
  489.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_D2G"
  490.     REDIM _PRESERVE PL(i): PL(i) = 10
  491.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_R2D"
  492.     REDIM _PRESERVE PL(i): PL(i) = 10
  493.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_R2G"
  494.     REDIM _PRESERVE PL(i): PL(i) = 10
  495.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_G2D"
  496.     REDIM _PRESERVE PL(i): PL(i) = 10
  497.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_G2R"
  498.     REDIM _PRESERVE PL(i): PL(i) = 10
  499.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "ABS"
  500.     REDIM _PRESERVE PL(i): PL(i) = 10
  501.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "SGN"
  502.     REDIM _PRESERVE PL(i): PL(i) = 10
  503.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "INT"
  504.     REDIM _PRESERVE PL(i): PL(i) = 10
  505.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_ROUND"
  506.     REDIM _PRESERVE PL(i): PL(i) = 10
  507.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "FIX"
  508.     REDIM _PRESERVE PL(i): PL(i) = 10
  509.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_SEC"
  510.     REDIM _PRESERVE PL(i): PL(i) = 10
  511.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_CSC"
  512.     REDIM _PRESERVE PL(i): PL(i) = 10
  513.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "_COT"
  514.     REDIM _PRESERVE PL(i): PL(i) = 10
  515.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "ASC"
  516.     REDIM _PRESERVE PL(i): PL(i) = 10
  517.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "CHR$"
  518.     REDIM _PRESERVE PL(i): PL(i) = 10
  519.  
  520.     'Exponents with PL 20
  521.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "^"
  522.     REDIM _PRESERVE PL(i): PL(i) = 20
  523.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "SQR"
  524.     REDIM _PRESERVE PL(i): PL(i) = 20
  525.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "ROOT"
  526.     REDIM _PRESERVE PL(i): PL(i) = 20
  527.     'Multiplication and Division PL 30
  528.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "*"
  529.     REDIM _PRESERVE PL(i): PL(i) = 30
  530.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "/"
  531.     REDIM _PRESERVE PL(i): PL(i) = 30
  532.     'Integer Division PL 40
  533.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "\"
  534.     REDIM _PRESERVE PL(i): PL(i) = 40
  535.     'MOD PL 50
  536.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "MOD"
  537.     REDIM _PRESERVE PL(i): PL(i) = 50
  538.     'Addition and Subtraction PL 60
  539.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "+"
  540.     REDIM _PRESERVE PL(i): PL(i) = 60
  541.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "-"
  542.     REDIM _PRESERVE PL(i): PL(i) = 60
  543.  
  544.     'Relational Operators =, >, <, <>, <=, >=   PL 70
  545.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "<>"
  546.     REDIM _PRESERVE PL(i): PL(i) = 70
  547.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "><" 'These next three are just reversed symbols as an attempt to help process a common typo
  548.     REDIM _PRESERVE PL(i): PL(i) = 70
  549.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "<="
  550.     REDIM _PRESERVE PL(i): PL(i) = 70
  551.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = ">="
  552.     REDIM _PRESERVE PL(i): PL(i) = 70
  553.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "=<" 'I personally can never keep these things straight.  Is it < = or = <...
  554.     REDIM _PRESERVE PL(i): PL(i) = 70
  555.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "=>" 'Who knows, check both!
  556.     REDIM _PRESERVE PL(i): PL(i) = 70
  557.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = ">"
  558.     REDIM _PRESERVE PL(i): PL(i) = 70
  559.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "<"
  560.     REDIM _PRESERVE PL(i): PL(i) = 70
  561.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "="
  562.     REDIM _PRESERVE PL(i): PL(i) = 70
  563.     'Logical Operations PL 80+
  564.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "NOT"
  565.     REDIM _PRESERVE PL(i): PL(i) = 80
  566.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "AND"
  567.     REDIM _PRESERVE PL(i): PL(i) = 90
  568.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "OR"
  569.     REDIM _PRESERVE PL(i): PL(i) = 100
  570.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "XOR"
  571.     REDIM _PRESERVE PL(i): PL(i) = 110
  572.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "EQV"
  573.     REDIM _PRESERVE PL(i): PL(i) = 120
  574.     i = i + 1: REDIM _PRESERVE OName(i): OName(i) = "IMP"
  575.     REDIM _PRESERVE PL(i): PL(i) = 130
  576.  
  577.  
  578. FUNCTION EvaluateNumbers$ (p, num() AS STRING)
  579.     DIM n1 AS _FLOAT, n2 AS _FLOAT, n3 AS _FLOAT
  580.     SELECT CASE OName(p) 'Depending on our operator..
  581.         CASE "_PI": n1 = 3.14159265358979323846264338327950288## 'Future compatable in case something ever stores extra digits for PI
  582.         CASE "%": n1 = (VAL(num(1))) / 100 'Note percent is a special case and works with the number BEFORE the % command and not after
  583.         CASE "_ACOS": n1 = _ACOS(VAL(num(2)))
  584.         CASE "_ASIN": n1 = _ASIN(VAL(num(2)))
  585.         CASE "_ARCSEC": n1 = _ARCSEC(VAL(num(2)))
  586.         CASE "_ARCCSC": n1 = _ARCCSC(VAL(num(2)))
  587.         CASE "_ARCCOT": n1 = _ARCCOT(VAL(num(2)))
  588.         CASE "_SECH": n1 = _SECH(VAL(num(2)))
  589.         CASE "_CSCH": n1 = _CSCH(VAL(num(2)))
  590.         CASE "_COTH": n1 = _COTH(VAL(num(2)))
  591.         CASE "COS": n1 = COS(VAL(num(2)))
  592.         CASE "SIN": n1 = SIN(VAL(num(2)))
  593.         CASE "TAN": n1 = TAN(VAL(num(2)))
  594.         CASE "LOG": n1 = LOG(VAL(num(2)))
  595.         CASE "EXP": n1 = EXP(VAL(num(2)))
  596.         CASE "ATN": n1 = ATN(VAL(num(2)))
  597.         CASE "_D2R": n1 = 0.0174532925 * (VAL(num(2)))
  598.         CASE "_D2G": n1 = 1.1111111111 * (VAL(num(2)))
  599.         CASE "_R2D": n1 = 57.2957795 * (VAL(num(2)))
  600.         CASE "_R2G": n1 = 0.015707963 * (VAL(num(2)))
  601.         CASE "_G2D": n1 = 0.9 * (VAL(num(2)))
  602.         CASE "_G2R": n1 = 63.661977237 * (VAL(num(2)))
  603.         CASE "ABS": n1 = ABS(VAL(num(2)))
  604.         CASE "SGN": n1 = SGN(VAL(num(2)))
  605.         CASE "INT": n1 = INT(VAL(num(2)))
  606.         CASE "_ROUND": n1 = _ROUND(VAL(num(2)))
  607.         CASE "FIX": n1 = FIX(VAL(num(2)))
  608.         CASE "_SEC": n1 = _SEC(VAL(num(2)))
  609.         CASE "_CSC": n1 = _CSC(VAL(num(2)))
  610.         CASE "_COT": n1 = _COT(VAL(num(2)))
  611.         CASE "^": n1 = VAL(num(1)) ^ VAL(num(2))
  612.         CASE "SQR": n1 = SQR(VAL(num(2)))
  613.         CASE "ROOT"
  614.             n1 = VAL(num(1)): n2 = VAL(num(2))
  615.             IF n2 = 1 THEN EvaluateNumbers$ = RTRIM$(LTRIM$(STR$(n1))): EXIT FUNCTION
  616.             IF n1 < 0 AND n2 >= 1 THEN sign = -1: n1 = -n1 ELSE sign = 1
  617.             n3 = 1## / n2
  618.             IF n3 <> INT(n3) AND n2 < 1 THEN sign = SGN(n1): n1 = ABS(n1)
  619.             n1 = sign * (n1 ^ n3)
  620.         CASE "*": n1 = VAL(num(1)) * VAL(num(2))
  621.         CASE "/": n1 = VAL(num(1)) / VAL(num(2))
  622.         CASE "\"
  623.             IF VAL(num(2)) <> 0 THEN
  624.                 n1 = VAL(num(1)) \ VAL(num(2))
  625.             ELSE
  626.                 EvaluateNumbers$ = "ERROR - Bad operation (We shouldn't see this)"
  627.                 EXIT FUNCTION
  628.             END IF
  629.         CASE "MOD": n1 = VAL(num(1)) MOD VAL(num(2))
  630.         CASE "+": n1 = VAL(num(1)) + VAL(num(2))
  631.         CASE "-": n1 = VAL(num(1)) - VAL(num(2))
  632.         CASE "=": n1 = VAL(num(1)) = VAL(num(2))
  633.         CASE ">": n1 = VAL(num(1)) > VAL(num(2))
  634.         CASE "<": n1 = VAL(num(1)) < VAL(num(2))
  635.         CASE "<>", "><": n1 = VAL(num(1)) <> VAL(num(2))
  636.         CASE "<=", "=<": n1 = VAL(num(1)) <= VAL(num(2))
  637.         CASE ">=", "=>": n1 = VAL(num(1)) >= VAL(num(2))
  638.         CASE "NOT": n1 = NOT VAL(num(2))
  639.         CASE "AND": n1 = VAL(num(1)) AND VAL(num(2))
  640.         CASE "OR": n1 = VAL(num(1)) OR VAL(num(2))
  641.         CASE "XOR": n1 = VAL(num(1)) XOR VAL(num(2))
  642.         CASE "EQV": n1 = VAL(num(1)) EQV VAL(num(2))
  643.         CASE "IMP": n1 = VAL(num(1)) IMP VAL(num(2))
  644.         CASE ELSE
  645.             EvaluateNumbers$ = "ERROR - Bad operation (We shouldn't see this)" 'Let's say we're bad...
  646.     END SELECT
  647.     EvaluateNumbers$ = RTRIM$(LTRIM$(STR$(n1)))
  648.  
  649. FUNCTION DWD$ (exp$) 'Deal With Duplicates
  650.     'To deal with duplicate operators in our code.
  651.     'Such as --  becomes a +
  652.     '++ becomes a +
  653.     '+- becomes a -
  654.     '-+ becomes a -
  655.     t$ = exp$
  656.     DO
  657.         bad = 0
  658.         DO
  659.             l = INSTR(t$, "++")
  660.             IF l THEN t$ = LEFT$(t$, l - 1) + "+" + MID$(t$, l + 2): bad = -1
  661.         LOOP UNTIL l = 0
  662.         DO
  663.             l = INSTR(t$, "+-")
  664.             IF l THEN t$ = LEFT$(t$, l - 1) + "-" + MID$(t$, l + 2): bad = -1
  665.         LOOP UNTIL l = 0
  666.         DO
  667.             l = INSTR(t$, "-+")
  668.             IF l THEN t$ = LEFT$(t$, l - 1) + "-" + MID$(t$, l + 2): bad = -1
  669.         LOOP UNTIL l = 0
  670.         DO
  671.             l = INSTR(t$, "--")
  672.             IF l THEN t$ = LEFT$(t$, l - 1) + "+" + MID$(t$, l + 2): bad = -1
  673.         LOOP UNTIL l = 0
  674.     LOOP UNTIL NOT bad
  675.     DWD$ = t$
  676.     VerifyString t$
  677.  
  678. SUB PreParse (e$)
  679.     DIM f AS _FLOAT
  680.  
  681.     t$ = e$
  682.  
  683.     'First strip all spaces
  684.     t$ = ""
  685.     FOR i = 1 TO LEN(e$)
  686.         IF MID$(e$, i, 1) <> " " THEN t$ = t$ + MID$(e$, i, 1)
  687.     NEXT
  688.  
  689.     t$ = UCASE$(t$)
  690.     IF t$ = "" THEN e$ = "ERROR -- NULL string; nothing to evaluate": EXIT SUB
  691.  
  692.     'ERROR CHECK by counting our brackets
  693.     l = 0
  694.     DO
  695.         l = INSTR(l + 1, t$, "("): IF l THEN c = c + 1
  696.     LOOP UNTIL l = 0
  697.     l = 0
  698.     DO
  699.         l = INSTR(l + 1, t$, ")"): IF l THEN c1 = c1 + 1
  700.     LOOP UNTIL l = 0
  701.     IF c <> c1 THEN e$ = "ERROR -- Bad Parenthesis:" + STR$(c) + "( vs" + STR$(c1) + ")": EXIT SUB
  702.  
  703.     'Modify so that NOT will process properly
  704.     l = 0
  705.     DO
  706.         l = INSTR(l + 1, t$, "NOT")
  707.         IF l THEN
  708.             'We need to work magic on the statement so it looks pretty.
  709.             ' 1 + NOT 2 + 1 is actually processed as 1 + (NOT 2 + 1)
  710.             'Look for something not proper
  711.             l1 = INSTR(l + 1, t$, "AND")
  712.             IF l1 = 0 OR (INSTR(l + 1, t$, "OR") > 0 AND INSTR(l + 1, t$, "OR") < l1) THEN l1 = INSTR(l + 1, t$, "OR")
  713.             IF l1 = 0 OR (INSTR(l + 1, t$, "XOR") > 0 AND INSTR(l + 1, t$, "XOR") < l1) THEN l1 = INSTR(l + 1, t$, "XOR")
  714.             IF l1 = 0 OR (INSTR(l + 1, t$, "EQV") > 0 AND INSTR(l + 1, t$, "EQV") < l1) THEN l1 = INSTR(l + 1, t$, "EQV")
  715.             IF l1 = 0 OR (INSTR(l + 1, t$, "IMP") > 0 AND INSTR(l + 1, t$, "IMP") < l1) THEN l1 = INSTR(l + 1, t$, "IMP")
  716.             IF l1 = 0 THEN l1 = LEN(t$) + 1
  717.             t$ = LEFT$(t$, l - 1) + "(" + MID$(t$, l, l1 - l) + ")" + MID$(t$, l + l1 - l)
  718.             l = l + 3
  719.             'PRINT t$
  720.         END IF
  721.     LOOP UNTIL l = 0
  722.  
  723.     'Check for bad operators before a ( bracket
  724.     l = 0
  725.     DO
  726.         l = INSTR(l + 1, t$, "(")
  727.         IF l AND l > 2 THEN 'Don't check the starting bracket; there's nothing before it.
  728.             good = 0
  729.             FOR i = 1 TO UBOUND(OName)
  730.                 IF MID$(t$, l - LEN(OName(i)), LEN(OName(i))) = OName(i) AND PL(i) > 1 AND PL(i) <= 250 THEN good = -1: EXIT FOR 'We found an operator after our ), and it's not a CONST (like PI)
  731.             NEXT
  732.             IF NOT good THEN e$ = "ERROR - Improper operations before (.": EXIT SUB
  733.             l = l + 1
  734.         END IF
  735.     LOOP UNTIL l = 0
  736.  
  737.     'Check for bad operators after a ) bracket
  738.     l = 0
  739.     DO
  740.         l = INSTR(l + 1, t$, ")")
  741.         IF l AND l < LEN(t$) THEN
  742.             good = 0
  743.             FOR i = 1 TO UBOUND(OName)
  744.                 IF MID$(t$, l + 1, LEN(OName(i))) = OName(i) AND PL(i) > 1 AND PL(i) <= 250 THEN good = -1: EXIT FOR 'We found an operator after our ), and it's not a CONST (like PI)
  745.             NEXT
  746.             IF MID$(t$, l + 1, 1) = ")" THEN good = -1
  747.             IF NOT good THEN e$ = "ERROR - Improper operations after ).": EXIT SUB
  748.             l = l + 1
  749.         END IF
  750.     LOOP UNTIL l = 0 OR l = LEN(t$) 'last symbol is a bracket
  751.  
  752.     'Turn all &H (hex) numbers into decimal values for the program to process properly
  753.     l = 0
  754.     DO
  755.         l = INSTR(t$, "&H")
  756.         IF l THEN
  757.             E = l + 1: finished = 0
  758.             DO
  759.                 E = E + 1
  760.                 comp$ = MID$(t$, E, 1)
  761.                 SELECT CASE comp$
  762.                     CASE "0" TO "9", "A" TO "F" 'All is good, our next digit is a number, continue to add to the hex$
  763.                     CASE ELSE
  764.                         good = 0
  765.                         FOR i = 1 TO UBOUND(OName)
  766.                             IF MID$(t$, E, LEN(OName(i))) = OName(i) AND PL(i) > 1 AND PL(i) <= 250 THEN good = -1: EXIT FOR 'We found an operator after our ), and it's not a CONST (like PI)
  767.                         NEXT
  768.                         IF NOT good THEN e$ = "ERROR - Improper &H value. (" + comp$ + ")": EXIT SUB
  769.                         E = E - 1
  770.                         finished = -1
  771.                 END SELECT
  772.             LOOP UNTIL finished OR E = LEN(t$)
  773.             t$ = LEFT$(t$, l - 1) + LTRIM$(RTRIM$(STR$(VAL(MID$(t$, l, E - l + 1))))) + MID$(t$, E + 1)
  774.         END IF
  775.     LOOP UNTIL l = 0
  776.  
  777.     'Turn all &B (binary) numbers into decimal values for the program to process properly
  778.     l = 0
  779.     DO
  780.         l = INSTR(t$, "&B")
  781.         IF l THEN
  782.             E = l + 1: finished = 0
  783.             DO
  784.                 E = E + 1
  785.                 comp$ = MID$(t$, E, 1)
  786.                 SELECT CASE comp$
  787.                     CASE "0", "1" 'All is good, our next digit is a number, continue to add to the hex$
  788.                     CASE ELSE
  789.                         good = 0
  790.                         FOR i = 1 TO UBOUND(OName)
  791.                             IF MID$(t$, E, LEN(OName(i))) = OName(i) AND PL(i) > 1 AND PL(i) <= 250 THEN good = -1: EXIT FOR 'We found an operator after our ), and it's not a CONST (like PI)
  792.                         NEXT
  793.                         IF NOT good THEN e$ = "ERROR - Improper &B value. (" + comp$ + ")": EXIT SUB
  794.                         E = E - 1
  795.                         finished = -1
  796.                 END SELECT
  797.             LOOP UNTIL finished OR E = LEN(t$)
  798.             bin$ = MID$(t$, l + 2, E - l - 1)
  799.             FOR i = 1 TO LEN(bin$)
  800.                 IF MID$(bin$, i, 1) = "1" THEN f = f + 2 ^ (LEN(bin$) - i)
  801.             NEXT
  802.             t$ = LEFT$(t$, l - 1) + LTRIM$(RTRIM$(STR$(f))) + MID$(t$, E + 1)
  803.         END IF
  804.     LOOP UNTIL l = 0
  805.  
  806.     t$ = N2S(t$)
  807.     VerifyString t$
  808.  
  809.     e$ = t$
  810.  
  811.  
  812.  
  813. SUB VerifyString (t$)
  814.     'ERROR CHECK for unrecognized operations
  815.     j = 1
  816.     DO
  817.         comp$ = MID$(t$, j, 1)
  818.         SELECT CASE comp$
  819.             CASE "0" TO "9", ".", "(", ")": j = j + 1
  820.             CASE ELSE
  821.                 good = 0
  822.                 FOR i = 1 TO UBOUND(OName)
  823.                     IF MID$(t$, j, LEN(OName(i))) = OName(i) THEN good = -1: EXIT FOR 'We found an operator after our ), and it's not a CONST (like PI)
  824.                 NEXT
  825.                 IF NOT good THEN t$ = "ERROR - Bad Operational value. (" + comp$ + ")": EXIT SUB
  826.                 j = j + LEN(OName(i))
  827.         END SELECT
  828.     LOOP UNTIL j > LEN(t$)
  829.  
  830. FUNCTION N2S$ (exp$) 'scientific Notation to String
  831.     t$ = LTRIM$(RTRIM$(exp$))
  832.     IF LEFT$(t$, 1) = "-" THEN sign$ = "-": t$ = MID$(t$, 2)
  833.  
  834.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  835.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  836.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  837.     IF check1 < 1 OR check1 > 1 THEN N2S = exp$: EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  838.  
  839.     SELECT CASE l 'l now tells us where the SN starts at.
  840.         CASE IS < dp: l = dp
  841.         CASE IS < dm: l = dm
  842.         CASE IS < ep: l = ep
  843.         CASE IS < em: l = em
  844.     END SELECT
  845.  
  846.     l$ = LEFT$(t$, l - 1) 'The left of the SN
  847.     r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
  848.  
  849.  
  850.     IF INSTR(l$, ".") THEN 'Location of the decimal, if any
  851.         IF r&& > 0 THEN
  852.             r&& = r&& - LEN(l$) + 2
  853.         ELSE
  854.             r&& = r&& + 1
  855.         END IF
  856.         l$ = LEFT$(l$, 1) + MID$(l$, 3)
  857.     END IF
  858.  
  859.     SELECT CASE r&&
  860.         CASE 0 'what the heck? We solved it already?
  861.             'l$ = l$
  862.         CASE IS < 0
  863.             FOR i = 1 TO -r&&
  864.                 l$ = "0" + l$
  865.             NEXT
  866.             l$ = "0." + l$
  867.         CASE ELSE
  868.             FOR i = 1 TO r&&
  869.                 l$ = l$ + "0"
  870.             NEXT
  871.     END SELECT
  872.  
  873.     N2S$ = sign$ + l$


The old version of this, from ages ago, can be found over at my archive forums here: http://qb64.freeforums.net/thread/34/math-flash-card-trainer-children

This reversion should be  complete,  more-or-less, except for a high score screen which folks can have fun and compete against each other on, and a [QUIT] or [PLAY AGAIN] page before the current auto-restart.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!