SemlerPDX

AVCS Voice Calculator & Unit Conversions (v1.1) Inline Function in VB.net for VoiceAttack

Jan 26th, 2021 (edited)
350
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'AVCS Voice Calculator & Conversions (v1.1) -- Calculate expressions with up to 2 operations and 3 values "Any way you say it"
  2. 'by SemlerPDX Mar2020/Feb2021
  3. 'VETERANS-GAMING.COM
  4.  
  5. 'demonstration video on youtube:  https://youtu.be/bCjuYh92M-I
  6.  
  7. 'When I say: *[divided by;divide by;divided that;divide that;divided;divide;multiply;times;multiplied by;multiply that;multiplied that;times that;add;add that;added that;plus;subtract;subtracted;minus;% of;to the power of;percent of;swear;square;square root of;square of;squared;cubed;cube;cuban;° c;° f;kelvin;celcius;celsius;centigrade;fahrenheit;kelvin;calvin;cm;centimeters;centimetres;inches;foot;feet;meters;metres;yards;yours;miles;km;kilometers;kilometres;feet per second;mph;miles per hour;kph;kilometers per hour;kilometres per hour;knots;mach;mock;mark]*
  8. 'Set text [~avcs_cmd] to '{TXTWORDTONUM:"{CMD}"}' (Trim) (Lower Case)
  9.  
  10. Imports Microsoft.VisualBasic
  11. Imports System
  12. Imports System.Linq
  13. Imports System.Math
  14. Imports System.Globalization
  15.  
  16. Public Class VAInline
  17.     dim decimalSeparator as string = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
  18.     dim decimalPlaces as Int32 = 3   'Default = 3   |  rounds results -- change via voice command 'Set Decimal Places [to;] [0..16]'
  19.    
  20.     'Operational Keyword Arrays
  21.     dim OperatorsArray() as string = {
  22.         "divided",
  23.         "divide",
  24.         "times",
  25.         "multiplied",
  26.         "multiply",
  27.         "add",
  28.         "plus",
  29.         "subtract",
  30.         "subtracted",
  31.         "minus",
  32.         "-",
  33.         "%",
  34.         "percent",
  35.         "power",
  36.         "square",
  37.         "squared",
  38.         "squareroot",
  39.         "cubed",
  40.         "cubes",
  41.         "cube",
  42.         "cuban",
  43.         "cuba"
  44.     }
  45.     dim ConvertorsArray() as string = {
  46.         "c",
  47.         "f",
  48.         "k",
  49.         "cm",
  50.         "celsius",
  51.         "celcius",
  52.         "centigrade",
  53.         "fahrenheit",
  54.         "kelvin",
  55.         "calvin",
  56.         "inches",
  57.         "centimeters",
  58.         "centimetres",
  59.         "foot",
  60.         "feet",
  61.         "m",
  62.         "meters",
  63.         "metres",
  64.         "yards",
  65.         "yours",
  66.         "miles",
  67.         "km",
  68.         "kilometers",
  69.         "kilometres",
  70.         "fps",
  71.         "feetpersecond",
  72.         "mps",
  73.         "meterspersecond",
  74.         "metrespersecond",
  75.         "mph",
  76.         "milesperhour",
  77.         "kph",
  78.         "kilometersperhour",
  79.         "kilometresperhour",
  80.         "knots",
  81.         "mach",
  82.         "mark",
  83.         "mock"
  84.     }
  85.     dim OpsArray() as string = {
  86.         "sum",
  87.         "sub",
  88.         "prd",
  89.         "dif",
  90.         "exp",
  91.         "per",
  92.         "sqr"
  93.     }
  94.     dim DoubleOpsArray() as string = {
  95.         "sum",
  96.         "sub",
  97.         "prd",
  98.         "dif"
  99.     }
  100.     dim SymbolsArray() as string = {
  101.         "°",
  102.         "%",
  103.         "^",
  104.         "-",
  105.         ":",
  106.         "$",
  107.         "£",
  108.         "€",
  109.         "¢",
  110.         "¥",
  111.         "ƒ"
  112.     }
  113.     dim PiArray() as string = {
  114.         "pi",
  115.         "pie",
  116.         "tie",
  117.         "high",
  118.         "bye",
  119.         "eye",
  120.         "espy",
  121.         "pine",
  122.         "pied",
  123.         "ply",
  124.         "tie"
  125.     }
  126.    
  127.     'Speech Parsing Vars
  128.     dim cmd as string = ""
  129.     dim charArray() as char
  130.     dim cmdSegments() as string
  131.     'Values Decimal Vars
  132.     dim operand1 as decimal?
  133.     dim operand2 as decimal?
  134.     dim operand3 as decimal?
  135.     dim operandLast as decimal?
  136.     dim result as decimal?
  137.     dim resultLast as decimal?
  138.     'Operations String Vars
  139.     dim operator1 as string
  140.     dim operator2 as string
  141.     dim operatorText1 as string = ""
  142.     dim operatorText2 as string = ""
  143.     dim equationText as string = ""
  144.     'Calc Systems Vars
  145.     dim operationsOrder as integer = 0
  146.     dim countHistory as integer = 1
  147.     dim countFaults as integer = 0
  148.     dim randomText as string
  149.     dim subReverse as boolean
  150.     dim calcActive as boolean
  151.    
  152.    
  153.     'Function to fix large number separators by culture
  154.     Private Function FixLargeNumberSeparator(ByRef cmd as string)
  155.         'ex. (7,000.32 into 7000.32)  [or]  (7.000,32 into 7000,32)
  156.         if ((cmd.Contains(".")) or (cmd.Contains(",")))
  157.             if (decimalSeparator <> ".")
  158.                 if (cmd.Contains("."))
  159.                     cmd = cmd.Replace(".", "")
  160.                 end if
  161.             elseif (decimalSeparator <> ",")
  162.                 if (cmd.Contains(","))
  163.                     cmd = cmd.Replace(",", "")
  164.                 end if
  165.             end if
  166.         end if 
  167.     end function
  168.    
  169.    
  170.     'Function to transform large number words and concat with the number said just before
  171.     Private Function FixLargeWordNum(ByRef largeType as string, ByRef lastNum as decimal?)
  172.         select case largeType
  173.             case "million"
  174.                 lastNum *= 1000000
  175.             case "billion"
  176.                 lastNum *= 1000000000
  177.             case "trillion"
  178.                 lastNum *= 1000000000000
  179.             case "quadrillion"
  180.                 lastNum *= 1000000000000000
  181.             case else
  182.                 largeType = "AVCS Calculation Error - unable to resolve '" + lastNum.ToString() + " " + largeType + "' as an opperand"
  183.         end select
  184.     end function
  185.    
  186.    
  187.     'Function to test for "by" as Pi in specific cases
  188.     Private Function HasPi(ByVal operatorName as string)
  189.         if (not((operatorName.Contains("root")) or (operatorName.StartsWith("square")) or (operatorName.StartsWith("cub"))))
  190.             cmd = cmd.Replace("   "," ").Replace("  "," ").Replace("divided by","").Replace("divide by","").Replace("multiplied by","").Replace("multiply by","").Replace("that by","")
  191.             if ((cmd.StartsWith("by ")) or (cmd.Contains(" by ")) or (cmd.EndsWith(" by")))
  192.                 Return true
  193.             end if
  194.         end if
  195.     end function
  196.    
  197.    
  198.     'Function to set keyword and readable text/symbol for Operators
  199.     Private Function SetOperator(ByRef operatorName as string, ByRef operatorText as string)
  200.         if ((operatorName.Contains("%")) or (operatorName.Contains("percent")))
  201.             operatorText = "% of"
  202.             operatorName = "per"
  203.         elseif (operatorName.StartsWith("divide"))
  204.             operatorText = "/"
  205.             operatorName = "dif"
  206.         elseif ((operatorName.Contains("times")) or (operatorName.StartsWith("multipl")))
  207.             operatorText = "x"
  208.             operatorName = "prd"
  209.         elseif ((operatorName.Contains("plus")) or (operatorName.StartsWith("add")))
  210.             operatorText = "+"
  211.             operatorName = "sum"
  212.         elseif ((operatorName.StartsWith("subtract")) or (operatorName.Contains("minus")) or (operatorName.Contains("-")))
  213.             operatorText = "-"
  214.             operatorName = "sub"
  215.         elseif (operatorName.Contains("power"))
  216.             operatorText = "ⁿ" 'to the power of
  217.             operatorName = "exp"
  218.         elseif (operatorName.Contains("squareroot"))
  219.             operatorText = "√" 'the square root of
  220.             operatorName = "sqr"
  221.         elseif (operatorName.StartsWith("square"))
  222.             operatorText = "²" 'squared
  223.             operatorName = "exp"
  224.         elseif (operatorName.StartsWith("cub"))
  225.             operatorText = "³" 'cubed
  226.             operatorName = "exp"
  227.         end if
  228.     end function
  229.    
  230.    
  231.     'Function to set keyword and readable text/symbol for Conversions
  232.     Private Function SetConvertor(ByRef operatorName as string, ByRef operatorText as string)
  233.         'VELOCITY CONVERSIONS==============
  234.         if ((operatorName.Contains("fps")) or (operatorName.Contains("feetpersecond")))
  235.             operatorText = "feet per second"
  236.             operatorName = "fps2"
  237.         elseif ((operatorName.Contains("mps")) or (operatorName.Contains("meterspersecond")) or (operatorName.Contains("metrespersecond")))
  238.             operatorText = "meters per second"
  239.             operatorName = "mps2"
  240.         elseif ((operatorName.Contains("mph")) or (operatorName.Contains("milesperhour")))
  241.             operatorText = "miles per hour"
  242.             operatorName = "mph2"
  243.         elseif ((operatorName.Contains("kph")) or (operatorName.Contains("kilometersperhour")) or (operatorName.Contains("kilometresperhour")))
  244.             operatorText = "kilometers per hour"
  245.             operatorName = "kph2"
  246.         elseif (operatorName.Contains("knots"))
  247.             operatorText = "knots"
  248.             operatorName = "kts2"
  249.         elseif ((operatorName.Contains("mach")) or (operatorName.Contains("mock")) or (operatorName.Contains("mark")))
  250.             operatorText = "mach"
  251.             operatorName = "mch2"
  252.         'DISTANCE CONVERSIONS==============
  253.         elseif (operatorName.Contains("inches"))
  254.             operatorText = "inches"
  255.             operatorName = "in2"
  256.         elseif ((operatorName.Contains("cm")) or (operatorName.Contains("centimeters")) or (operatorName.Contains("centimetres")))
  257.             operatorText = "centimeters"
  258.             operatorName = "cm2"
  259.         elseif ((operatorName.Contains("feet")) or (operatorName.Contains("foot")))
  260.             operatorText = "feet"
  261.             operatorName = "ft2"
  262.         elseif ((operatorName.Contains("yards")) or (operatorName.Contains("yours")))
  263.             operatorText = "yards"
  264.             operatorName = "yd2"
  265.         elseif ((operatorName.Contains("km")) or (operatorName.Contains("kilometers")) or (operatorName.Contains("kilometres")))
  266.             operatorText = "kilometers"
  267.             operatorName = "km2"
  268.         elseif ((operatorName.Contains("mi")) or (operatorName.Contains("miles")))
  269.             operatorText = "miles"
  270.             operatorName = "mi2"
  271.         elseif ((operatorName.Contains("meters")) or (operatorName.Contains("metres")))
  272.             operatorText = "meters"
  273.             operatorName = "mt2"
  274.         'TEMPERATURE CONVERSIONS==============
  275.         elseif (operatorName.Contains("fahrenheit"))
  276.             operatorText = "degrees fahrenheit"
  277.             operatorName = "f2"
  278.         elseif ((operatorName.Contains("celcius")) or (operatorName.Contains("celsius")))
  279.             operatorText = "degrees celcius"
  280.             operatorName = "c2"
  281.         elseif (operatorName.Contains("centigrade"))
  282.             operatorText = "degrees centigrade"
  283.             operatorName = "c2"
  284.         elseif ((operatorName.Contains("kelvin")) or (operatorName.Contains("calvin")))
  285.             operatorText = "kelvin"
  286.             operatorName = "k2"
  287.         end if
  288.     end function
  289.    
  290.    
  291.     'Main Maths Function
  292.     Private Function GetResult(ByVal ops as string, ByVal val1 as decimal?, Optional ByVal val2 as decimal? = 0)
  293.         select case ops
  294.             case "sum"
  295.                 val1 += val2
  296.             case "sub"
  297.                 val1 -= val2
  298.             case "prd"
  299.                 val1 *=  val2
  300.             case "dif"
  301.                 val1 /= val2
  302.             case "per"
  303.                 val1 *= (val2 / 100)
  304.             case "exp"
  305.                 val1 = Pow(val1, val2)
  306.             case "sqr"
  307.                 val1 = Sqrt(val1)
  308.             case else
  309.                 val1 = nothing
  310.         end select
  311.         Return val1
  312.     end function
  313.    
  314.    
  315.     'Main Conversions Function
  316.     Private Function GetConversion(ByVal ops as string, ByVal val as decimal?)
  317.         select case ops
  318.             '==DISTANCE===========
  319.             'inches
  320.             case "in2cm"
  321.                 val *= 0.393701
  322.             case "in2ft"
  323.                 val *= 0.0833333
  324.             case "in2mt"
  325.                 val *= 0.0254
  326.             case "in2yd"
  327.                 val *= 0.0277778
  328.             case "in2km"
  329.                 val /= 39370
  330.             case "in2mi"
  331.                 val /= 63360
  332.             'cm
  333.             case "cm2in"
  334.                 val *= 0.393701
  335.             case "cm2ft"
  336.                 val *= 0.0328084
  337.             case "cm2mt"
  338.                 val /= 100
  339.             case "cm2yd"
  340.                 val *= 0.0109361
  341.             case "cm2km"
  342.                 val /= 100000
  343.             case "cm2mi"
  344.                 val /= 160934
  345.             'ft
  346.             case "ft2in"
  347.                 val *= 12
  348.             case "ft2cm"
  349.                 val *= 30.48
  350.             case "ft2mt"
  351.                 val *= 0.3048
  352.             case "ft2yd"
  353.                 val *= 0.333333
  354.             case "ft2km"
  355.                 val /= 3280.84
  356.             case "ft2mi"
  357.                 val /= 5280
  358.             'mt
  359.             case "mt2in"
  360.                 val *= 39.3701
  361.             case "mt2cm"
  362.                 val *= 100
  363.             case "mt2ft"
  364.                 val *= 3.28084
  365.             case "mt2yd"
  366.                 val *= 1.09361
  367.             case "mt2km"
  368.                 val /= 1000
  369.             case "mt2mi"
  370.                 val /= 1609
  371.             'yd
  372.             case "yd2in"
  373.                 val *= 36
  374.             case "yd2cm"
  375.                 val *= 91.44
  376.             case "yd2ft"
  377.                 val *= 3
  378.             case "yd2mt"
  379.                 val *= 0.9144
  380.             case "yd2km"
  381.                 val /= 1093.61
  382.             case "yd2mi"
  383.                 val /= 1760
  384.             'km
  385.             case "km2in"
  386.                 val *= 39370.1
  387.             case "km2cm"
  388.                 val *= 100000
  389.             case "km2ft"
  390.                 val *= 3280.84
  391.             case "km2mt"
  392.                 val *= 1000
  393.             case "km2yd"
  394.                 val *= 1093.61
  395.             case "km2mi"
  396.                 val *= 0.621371
  397.             'miles
  398.             case "mi2in"
  399.                 val *= 63360
  400.             case "mi2cm"
  401.                 val *= 160934.4
  402.             case "mi2ft"
  403.                 val *= 5280
  404.             case "mi2mt"
  405.                 val *= 1609.34
  406.             case "mi2yd"
  407.                 val *= 1760
  408.             case "mi2km"
  409.                 val *= 1.60934
  410.             '==VELOCITY===========
  411.             'fps
  412.             case "fps2mps"
  413.                 val *= 0.3048
  414.             case "fps2kph"
  415.                 val *= 1.09728
  416.             case "fps2mph"
  417.                 val *= 0.681818
  418.             case "fps2kts"
  419.                 val *= 0.592484
  420.             case "fps2mch"
  421.                 val *= 0.00088863
  422.             'mps
  423.             case "mps2fps"
  424.                 val *= 3.28084
  425.             case "mps2kph"
  426.                 val *= 3.6
  427.             case "mps2mph"
  428.                 val *= 2.23694
  429.             case "mps2kts"
  430.                 val *= 1.94384
  431.             case "mps2mch"
  432.                 val *= 0.00291545
  433.             'kph
  434.             case "kph2fps"
  435.                 val *= 0.911344
  436.             case "kph2mps"
  437.                 val *= 0.277778
  438.             case "kph2mph"
  439.                 val *= 0.6214
  440.             case "kph2kts"
  441.                 val *= 1.852
  442.             case "kph2mch"
  443.                 val *= 1234.8
  444.             'mph
  445.             case "mph2fps"
  446.                 val *= 1.46667
  447.             case "mph2mps"
  448.                 val *= 0.44704
  449.             case "mph2kph"
  450.                 val *= 1.60934
  451.             case "mph2kts"
  452.                 val *= 0.868976
  453.             case "mph2mch"
  454.                 val *= 0.00130332
  455.             'knots
  456.             case "kts2fps"
  457.                 val *= 1.68781
  458.             case "kts2mps"
  459.                 val *= 0.514444
  460.             case "kts2mph"
  461.                 val *= 1.15078
  462.             case "kts2kph"
  463.                 val *= 1.852
  464.             case "kts2mch"
  465.                 val *= 0.0015
  466.             'mach
  467.             case "mch2fps"
  468.                 val *= 1125.33
  469.             case "mch2mps"
  470.                 val *= 343
  471.             case "mch2mph"
  472.                 val *= 767.269
  473.             case "mch2kph"
  474.                 val *= 1234.8
  475.             case "mch2kts"
  476.                 val *= 666.73866
  477.             '==TEMPERATURE===========
  478.             'f
  479.             case "f2c"
  480.                 val = ((val - 32) * 5) / 9
  481.             case "f2k"
  482.                 val = ((val + 459.67) * 5) / 9
  483.             'c
  484.             case "c2f"
  485.                 val = ((val * 9) / 5) + 32
  486.             case "c2k"
  487.                 val = ((val * 9) / 5) + 32
  488.                 val = ((val + 459.67) * 5) / 9
  489.             'kelvin
  490.             case "k2f"
  491.                 val = ((val * 9) / 5) - 459.67
  492.             case "k2c"
  493.                 val = ((val * 9) / 5) - 459.67
  494.                 val = ((val - 32) * 5) / 9
  495.             case else
  496.                 val = nothing
  497.         end select
  498.         Return val
  499.     end function
  500.    
  501.    
  502.     Public Sub Main()
  503.        
  504.         VA.SetText("avcs_calc_return", nothing)
  505.        
  506.         'Debugging and Testing Check (bypassed if called via spoken command)
  507.         dim cmdTest as string = vaProxy.Utility.ParseTokens("{CMD}")
  508.         if (cmdTest = "")
  509.             VA.SetText("~avcs_cmd","by the way what is 3 plus 3 times by")'  "200 subtract the square root of 128"  "what is -78° f in celcius"  "what is 3 zillion divided by 2"
  510.             'VA.SetInt("AVCS_CALC_ResultsDecimalPlaces",2)
  511.             cmdTest = VA.GetText("~avcs_cmd")
  512.         else
  513.            
  514.             'Check Calc Mode state, exit of off
  515.             if ((VA.GetBoolean("AVCS_CALC_MODE_ON")) isNot nothing)
  516.                 calcActive = VA.GetBoolean("AVCS_CALC_MODE_ON")
  517.             end if
  518.            
  519.             'Provide Message for wildcard recognition when Calculator Mode OFF (infrequent prompt in case user does not know)
  520.             if (not(calcActive))
  521.                 if ((VA.GetInt("AVCS_CALC_FAULT")) isNot nothing)
  522.                     countFaults = VA.GetInt("AVCS_CALC_FAULT")
  523.                     countFaults += 1
  524.                     if (countFaults >= 3)
  525.                         if (countFaults >= 15)
  526.                             VA.WriteToLog("Calculation recognized, but won't be computed  (this is common when calculator is OFF)", "purple")
  527.                             VA.SetInt("AVCS_CALC_FAULT", nothing)
  528.                             countFaults = 0
  529.                         end if
  530.                     else
  531.                         randomText = "Calculator is OFF.  To enable, say, '" + vaProxy.Utility.ParseTokens("{TXTRANDOM:Enable;Begin;Turn On;Start}") + " Voice Calculator'"
  532.                         VA.WriteToLog(randomText, "purple")
  533.                     end if
  534.                     VA.SetInt("AVCS_CALC_FAULT", countFaults)
  535.                 else
  536.                     VA.SetInt("AVCS_CALC_FAULT", 1)
  537.                 end if
  538.                 'Exit Calc Function when Mode OFF
  539.                 Exit Sub
  540.             end if
  541.         end if
  542.        
  543.         'Get Custom Decimal Place Settings (if exists)
  544.         if (VA.GetInt("AVCS_CALC_ResultsDecimalPlaces")) isNot nothing
  545.             decimalPlaces = Convert.ToInt32(VA.GetInt("AVCS_CALC_ResultsDecimalPlaces"))
  546.         end if
  547.        
  548.         'Parse Spoken Command for Equation(s)
  549.         if (VA.GetText("~avcs_cmd")) isNot nothing
  550.            
  551.             'Remove large number separators, spaces from keywords, known "to" and "1", and handle edge case words
  552.             cmd = VA.GetText("~avcs_cmd").Replace("swear ","square ").Replace("square root","squareroot").Replace("to the power","power").Replace("too value"," value").Replace("to value"," value").Replace("2 value"," value").Replace("value ","value").Replace(" per ","per").Replace(" ad ","add").Replace("added to","add ").Replace("added 2","add ").Replace("add that 2","add that ").Replace("add that to","add that ").Replace("÷"," divided by ").Replace("¼","0.25").Replace("½","0.5").Replace("¾" ,"0.75")
  553.             FixLargeNumberSeparator(cmd)
  554.             if (cmd.StartsWith("fore to"))
  555.                 cmd = cmd.Substring(7, cmd.Length - 7)
  556.             elseif (cmd.StartsWith("for to"))
  557.                 cmd = cmd.Substring(6, cmd.Length - 6)
  558.             elseif (cmd.StartsWith("or to"))
  559.                 cmd = cmd.Substring(5, cmd.Length - 5)
  560.             elseif (cmd.StartsWith("1 is"))
  561.                 cmd = cmd.Substring(4, cmd.Length - 4)
  562.             end if
  563.            
  564.             'Evaluate spoken command split at each character and space out symbols
  565.             charArray = cmd.ToCharArray
  566.             cmd = ""
  567.             for each character as string in charArray
  568.                 if (SymbolsArray.Contains(character))
  569.                     cmd += " " + character.ToString() + " "
  570.                 else
  571.                     cmd += character.ToString()
  572.                 end if
  573.             next
  574.            
  575.             'Evaluate all segments of speech split at {SPACE} and parse for operands and operators
  576.             cmdSegments = cmd.Split(New String() {" "},StringSplitOptions.None)
  577.             for each segment as string in cmdSegments
  578.                 if (segment <> "")
  579.                    
  580.                     'Handle numbers recognized as homonym words
  581.                     select case segment
  582.                         case "too"
  583.                             segment = "2"
  584.                         case "to"
  585.                             segment = "2"
  586.                         case "trees"
  587.                             segment = "3"
  588.                         case "tree"
  589.                             segment = "3"
  590.                         case "fore"
  591.                             segment = "4"
  592.                         case "for"
  593.                             segment = "4"
  594.                         case "ate"
  595.                             segment = "8"
  596.                         case "ape"
  597.                             segment = "8"
  598.                         case "valuetoo"
  599.                             segment = "value2"
  600.                         case "valueto"
  601.                             segment = "value2"
  602.                         case "valuetrees"
  603.                             segment = "value3"
  604.                         case "valuetree"
  605.                             segment = "value3"
  606.                         case "valuefore"
  607.                             segment = "value4"
  608.                         case "valuefor"
  609.                             segment = "value4"
  610.                         case "valueate"
  611.                             segment = "value8"
  612.                     end select
  613.                    
  614.                     'Handle short form of convertors
  615.                     select case segment
  616.                         case "c"
  617.                             segment = "celcius"
  618.                         case "f"
  619.                             segment = "fahrenheit"
  620.                         case "k"
  621.                             segment = "kelvin"
  622.                         case "m"
  623.                             segment = "meters"
  624.                     end select
  625.                    
  626.                     'Handle "subtract A from B" order of operations error
  627.                     if (segment.Contains("from"))
  628.                         if ((operand2 is nothing) and(operand1 isNot nothing) and ((operator1 isNot nothing) and (operator1.Contains("subtract"))))
  629.                             subReverse = true
  630.                         end if
  631.                     end if
  632.                    
  633.                     'Handle "that" reference to previous calculation result
  634.                     if (segment.Contains("that"))
  635.                         if ((VA.GetDecimal("AVCS_CALC_LastResult")) isNot nothing)
  636.                             segment = VA.GetDecimal("AVCS_CALC_LastResult").ToString()
  637.                         end if
  638.                     end if
  639.                    
  640.                     'Handle MEM reference to previous calculation result
  641.                     if ((segment.StartsWith("value")) and (IsNumeric(segment.Substring(segment.Length - 1, 1))))
  642.                         if ((VA.GetDecimal(segment)) isNot nothing)
  643.                             segment = VA.GetDecimal(segment).ToString()
  644.                         else
  645.                             VA.WriteToLog(segment + " does not exist in memory", "red")
  646.                             Exit Sub
  647.                         end if
  648.                     end if
  649.                    
  650.                     'Handle negative temperatures
  651.                     if ((operator2 isNot nothing) and (operand1 isNot nothing))
  652.                         if ((operationsOrder = 2) and (ConvertorsArray.Contains(operator2)))
  653.                             operator1 = operator2
  654.                             operator2 = nothing
  655.                             operand1 -= (operand1 * 2)
  656.                             operationsOrder = 5
  657.                         end if
  658.                     end if
  659.                    
  660.                     'Handle "pi" and homonym variants
  661.                     if (PiArray.Contains(segment))
  662.                         if (operand1 is nothing)
  663.                             operand1 = Pi
  664.                         elseif (operand2 is nothing)
  665.                             operand2 = Pi
  666.                         elseif (operand3 is nothing)
  667.                             operand3 = Pi
  668.                         end if
  669.                        
  670.                     'Set Operands -------
  671.                     elseif ((IsNumeric(segment)) and (operand1 is nothing))
  672.                         try
  673.                             operand1 = Convert.ToDecimal(segment)
  674.                             operandLast = operand1
  675.                             if (operationsOrder = 0)
  676.                                 operationsOrder = 1 'for edge case:  (b = Pi)
  677.                             end if
  678.                         catch
  679.                             VA.WriteToLog("AVCS Calculation Error at Operand 1", "red")
  680.                         end try
  681.                     elseif ((IsNumeric(segment)) and (operand2 is nothing))
  682.                         try
  683.                             operand2 = Convert.ToDecimal(segment)
  684.                             operandLast = operand2
  685.                         catch
  686.                             VA.WriteToLog("AVCS Calculation Error at Operand 2", "red")
  687.                         end try
  688.                     elseif ((IsNumeric(segment)) and (operand3 is nothing))
  689.                         try
  690.                             operand3 = Convert.ToDecimal(segment)
  691.                             operandLast = operand3
  692.                         catch
  693.                             VA.WriteToLog("AVCS Calculation Error at Operand 3", "red")
  694.                         end try
  695.                        
  696.                     'Set Operators -------
  697.                     elseif ((OperatorsArray.Contains(segment)) and (operator1 is nothing))
  698.                         operator1 = segment
  699.                         if (operationsOrder = 0)
  700.                             operationsOrder = 2 'for edge case:  (a = Pi)
  701.                         end if
  702.                     elseif ((OperatorsArray.Contains(segment)) and (operator2 is nothing))
  703.                         operator2 = segment
  704.                         if ((operationsOrder = 1) and (operand2 isNot nothing))
  705.                             operationsOrder = 3 'for edge case:  (c = b and b = Pi)
  706.                         elseif ((operationsOrder = 1) and (operand2 is nothing))
  707.                             operationsOrder = 4 'for edge case:  (c = Pi)
  708.                         end if
  709.                        
  710.                     'Set Convertors -------
  711.                     elseif ((ConvertorsArray.Contains(segment)) and (operator1 is nothing))
  712.                         operator1 = segment
  713.                         operationsOrder = 5 'for edge case null:  (no way Pi)
  714.                     elseif ((ConvertorsArray.Contains(segment)) and (operator2 is nothing))
  715.                         operator2 = segment
  716.                        
  717.                     'Handle "..illions" -------
  718.                     elseif (segment.EndsWith("illion"))
  719.                         if ((operand1 isNot nothing) and (operandLast = operand1))
  720.                             FixLargeWordNum(segment,operand1)
  721.                         elseif ((operand2 isNot nothing) and (operandLast = operand2))
  722.                             FixLargeWordNum(segment,operand2)
  723.                         elseif ((operand3 isNot nothing) and (operandLast = operand3))
  724.                             FixLargeWordNum(segment,operand3)
  725.                         end if
  726.                         if (segment.StartsWith("AVCS Calculation Error"))
  727.                             VA.WriteToLog(segment, "red")
  728.                             Exit Sub
  729.                         end if
  730.                     end if
  731.                    
  732.                 end if
  733.             next
  734.            
  735.            
  736.             'Evaluate for Pi recognized as "by" (edge cases)
  737.             if (operationsOrder < 5)
  738.                 '-- 1 operation catch
  739.                 if ((operator2 is nothing) and (operand2 is nothing))
  740.                     if (HasPi(operator1))
  741.                         if (operationsOrder = 1)
  742.                             operand2 = Pi
  743.                         elseif (operationsOrder = 2)
  744.                             operand2 = operand1
  745.                             operand1 = Pi
  746.                         end if
  747.                     end if
  748.                 '-- 2 operations catch
  749.                 elseif ((operator2 isNot nothing) and (operand3 is nothing))
  750.                     if ((HasPi(operator1)) or (HasPi(operator2)))
  751.                         if (operationsOrder = 4)
  752.                             operand3 = operand2
  753.                             operand2 = Pi
  754.                         elseif (operationsOrder = 3)
  755.                             operand3 = Pi
  756.                         elseif (operationsOrder = 2)
  757.                             operand3 = operand2
  758.                             operand2 = operand1
  759.                             operand1 = Pi
  760.                         end if
  761.                     end if
  762.                 end if
  763.             end if
  764.            
  765.             'Evaluate Operator 1 ======
  766.             if (operator1 isNot nothing)
  767.                
  768.                 'Handle null operands on Squared/Cubed operators
  769.                 if ((operator1.StartsWith("square")) and (not(operator1.Contains("root"))))
  770.                     operand2 = 2
  771.                 elseif (operator1.StartsWith("cub"))
  772.                     operand2 = 3
  773.                 'Handle Reverse order of operations on Subtract
  774.                 elseif ((operator1.Contains("subtract")) and (subReverse))
  775.                     dim operand4 as decimal? = operand2
  776.                     operand2 = operand1
  777.                     operand1 = operand4
  778.                 end if
  779.                
  780.                 'Set Operator 1 keyword and get text form of Operator/Convertor
  781.                 if (not(OperatorsArray.Contains(operator1)))
  782.                     SetConvertor(operator1,operatorText1)
  783.                 else
  784.                     SetOperator(operator1,operatorText1)
  785.                 end if
  786.             else
  787.                 VA.WriteToLog("AVCS Calculation Error on Null Operator 1", "red")
  788.                 Exit Sub
  789.             end if
  790.            
  791.             'Evaluate Operator 2 ======
  792.             if (operator2 isNot nothing)
  793.                
  794.                 'Handle null operands on Squared/Cubed operators
  795.                 if ((operator2.StartsWith("square")) and (not(operator2.Contains("root"))))
  796.                     operand3 = 2
  797.                 elseif (operator2.Contains("cub"))
  798.                     operand3 = 3
  799.                 end if
  800.                
  801.                 'Set Operator 2 keyword and get text form of Operator/Convertor
  802.                 if (not(OpsArray.Contains(operator1)))
  803.                     SetConvertor(operator2,operatorText2)
  804.                     operator1 = operator1 + operator2.Substring(0, operator2.Length - 1)
  805.                     operator2 = nothing
  806.                 else
  807.                     SetOperator(operator2,operatorText2)
  808.                     'Calculate Square Root on Multi-Part Equation to avoid errors on null operand3
  809.                     'ex. 200 subtract square root of 128 = 188.69 = a-(Sqrt(b))
  810.                     if ((operator2 = "sqr") and (operand3 is nothing))
  811.                         equationText = operand1.ToString() + " " + operatorText1 + " " + operatorText2 + " " + operand2.ToString() + " "
  812.                         operand2 = Sqrt(operand2)
  813.                         operator2 = nothing
  814.                    
  815.                     'Calculate Percentage before to avoid order of operations and text display errors
  816.                     'ex. 200 subtract 20 % = 160 = a-(b*(a/100))
  817.                     elseif ((operator2 = "per") and (operand3 is nothing))
  818.                         equationText = operand1.ToString() + " " + operatorText1 + " " + operand2.ToString() + " " + operatorText2 + " " + operand1.ToString() + " "
  819.                         operand3 = operand1
  820.                         operand2 = operand2*(operand3 / 100)
  821.                         operand3 = nothing
  822.                         operator2 = nothing
  823.                     'ex. 200 subtract 20 % of 100 = 180 = a-(b*(c/100)
  824.                     elseif ((operator2 = "per") and (operand3 isNot nothing))
  825.                         equationText = operand1.ToString() + " " + operatorText1 + " " + operand2.ToString() + " " + operatorText2 + " " + operand3.ToString() + " "
  826.                         operand2 = operand2*(operand3 / 100)
  827.                         operand3 = nothing
  828.                         operator2 = nothing
  829.                    
  830.                     'Calculate Exponents before to avoid order of operations and text display errors
  831.                     'ex. 4 plus 7 to the power of 3 = 347 = a+(b^c)
  832.                     elseif (((operator2 = "exp") and (operatorText2.StartsWith("to"))) and (operand3 isNot nothing))
  833.                         equationText = operand1.ToString() + " " + operatorText1 + " " + operand2.ToString() + " " + operatorText2 + " " + operand3.ToString() + " "
  834.                         operand2 = Pow(operand2, operand3)
  835.                         operand3 = nothing
  836.                         operator2 = nothing
  837.                     'ex. 4 plus 7 cubed = 347 = a+b³   [or]   4 plus 7 squared = 53 = a+b²
  838.                     elseif (((operator2 = "exp") and (not(operatorText2.StartsWith("to")))) and (operand3 isNot nothing))
  839.                         equationText = operand1.ToString() + " " + operatorText1 + " " + operand2.ToString() + " " + operatorText2 + " "
  840.                         operand2 = Pow(operand2, operand3)
  841.                         operand3 = nothing
  842.                         operator2 = nothing
  843.                     end if
  844.                 end if
  845.             end if
  846.            
  847.             'Final Evaluation for "8" recognized as "a"
  848.             if ((DoubleOpsArray.Contains(operator1)) and (operator2 is nothing) and (operand1 isNot nothing) and (operand2 is nothing))
  849.                 if ((cmd.Contains(" a ")) or (cmd.EndsWith(" a")))
  850.                     if (operationsOrder = 1)
  851.                         operand2 = 8
  852.                     else
  853.                         operand2 = operand1
  854.                         operand1 = 8
  855.                     end if
  856.                 end if
  857.             end if
  858.            
  859.            
  860.             '==CALCULATE RESULT==
  861.             if (OpsArray.Contains(operator1))
  862.                
  863.                 'Build Equation Text for display in VA Event log
  864.                 if (equationText = "")
  865.                     if (operand1 isNot nothing)
  866.                         equationText += operand1.ToString() + " "
  867.                     end if
  868.                     if (operator1 isNot nothing)
  869.                         equationText += operatorText1 + " "
  870.                     end if
  871.                     if (operand2 isNot nothing)
  872.                         equationText += operand2.ToString() + " "
  873.                     end if
  874.                     if (operator2 isNot nothing)
  875.                         equationText += operatorText2 + " "
  876.                     end if
  877.                     if (operand3 isNot nothing)
  878.                         equationText += operand3.ToString() + " "
  879.                     end if
  880.                    
  881.                     'Calculate Square Root on Multi-Part Equation to avoid incorrect operations math and display text
  882.                     'ex. square root of 144 times 7 = 84 = b*(Sqrt(a))
  883.                     if ((operator1 = "sqr") and ((operator2 isNot nothing) and (operand2 isNot nothing)))
  884.                         equationText = operatorText1 + " " + operand1.ToString() + " " + operatorText2 + " " + operand2.ToString() + " "
  885.                     end if
  886.                    
  887.                     'Remove any whitespace between % and number(s)
  888.                     if (equationText.Contains(" %"))
  889.                         equationText = equationText.Replace(" %","%")
  890.                     end if
  891.                 end if
  892.                
  893.                 'MATHS BEGIN--------------------------------
  894.                 'If there are 2 operations
  895.                 if (operator2 isNot nothing)
  896.                     'If there are 2 operations with 3 values
  897.                     if (operand3 isNot nothing)
  898.                         if ((operand1 isNot nothing) and (operand2 isNot nothing))
  899.                             result = GetResult(operator1,operand1,operand2)
  900.                         end if
  901.                         if (result isNot nothing)
  902.                             result = GetResult(operator2,result,operand3)
  903.                         end if
  904.                     'Else if there are 2 operations with 2 values
  905.                     elseif (operand2 isNot nothing)
  906.                         'Handle Square Root on Second Operand
  907.                         if ((operator1 = "sqr") and (operand1 isNot nothing))
  908.                             result = Sqrt(operand1)
  909.                         else
  910.                             result = nothing
  911.                         end if
  912.                        
  913.                         if ((operator1 = "sqr") and (result isNot nothing))
  914.                             result = GetResult(operator2,result,operand2)
  915.                         else
  916.                             if ((result isNot nothing) and (operand1 isNot nothing))
  917.                                 result = GetResult(operator1,operand1,result)
  918.                             elseif (operand1 isNot nothing)
  919.                                 result = GetResult(operator2,operand1,operand2)
  920.                             end if
  921.                         end if
  922.                     end if
  923.                
  924.                 'Else if there is 1 operation with up to 2 values
  925.                 elseif (operator1 isNot nothing)
  926.                     if ((operand1 isNot nothing) and  (operand2 isNot nothing))
  927.                         result = GetResult(operator1,operand1,operand2)
  928.                         if ((operatorText1 = "cubed") or (operatorText1 = "squared"))
  929.                             equationText = equationText.Replace(" " + operand2.ToString() + " "," ")
  930.                         end if
  931.                     elseif ((operand1 isNot nothing) and (not(DoubleOpsArray.Contains(operator1))))
  932.                         result = GetResult(operator1,operand1)
  933.                         equationText = equationText.Replace(operand1.ToString() + " ","") + operand1.ToString() + " "
  934.                     end if
  935.                 end if
  936.             else
  937.                 'Else this is a Unit Conversion with 1 value
  938.                 if (operator1 isNot nothing)
  939.                     if (operand1 isNot nothing)
  940.                         result = GetConversion(operator1,operand1)
  941.                         equationText = operand1.ToString() + " " + operatorText1 + " = "
  942.                     end if
  943.                 else
  944.                     VA.WriteToLog("AVCS Calculation Error on Null Operator 1", "red")
  945.                 end if
  946.             end if
  947.            
  948.            
  949.             'Evaluate Result ======
  950.             if (result isNot nothing)
  951.                 try
  952.                     'Try to compare decimal with integer version of itself to discover decimal places, then round
  953.                     dim checkResult as Int32 = Convert.ToInt32(result)
  954.                     if (result = checkResult)
  955.                         'For TTS brevity use the one that couldn't end with .000
  956.                         result = checkResult
  957.                     elseif (checkResult <> result)
  958.                         dim roundResult as Double = result
  959.                         result = Round(roundResult, decimalPlaces)
  960.                     end if
  961.                 catch
  962.                     'Result is a whole number already, does not need rounding for TTS brevity
  963.                 end try
  964.                
  965.                 'Correct Pi in equation text string to 2 decimal places for TTS brevity
  966.                 if(equationText.Contains(Pi.ToString()))
  967.                     equationText = equationText.Replace(Pi.ToString(), "3.14")
  968.                 end if
  969.                
  970.                 'Get/Increment/Set Current Operations History Count
  971.                 if((VA.GetInt("AVCS_CALC_CountOperations")) isNot nothing)
  972.                     countHistory = VA.GetInt("AVCS_CALC_CountOperations")
  973.                     countHistory += 1
  974.                     if (countHistory > 99)
  975.                         countHistory = 1
  976.                     end if
  977.                 end if
  978.                 VA.SetInt("AVCS_CALC_CountOperations", countHistory)
  979.                
  980.                 'Save to Calc History & Display Last complete equation with result in Event Log
  981.                 if (OpsArray.Contains(operator1))
  982.                     equationText = equationText.Replace(" ²","²").Replace(" ³","³").Replace(" ⁿ " ,"ⁿ").Replace("√ ","√")
  983.                     VA.SetText("AVCS_CALC_LastOperation", equationText + "= " + result.ToString())
  984.                     VA.SetText("AVCS_CALC_LastOperation_" + countHistory.ToString(), equationText + "= " + result.ToString())
  985.                     VA.WriteToLog("Value " + countHistory.ToString() + " = " + equationText + "= " + result.ToString(), "green")
  986.                 else
  987.                     VA.SetText("AVCS_CALC_LastOperation", equationText + result.ToString() + " " + operatorText2)
  988.                     VA.SetText("AVCS_CALC_LastOperation_" + countHistory.ToString(), equationText + result.ToString() + " " + operatorText2)
  989.                     VA.WriteToLog("Value " + countHistory.ToString() + " = " + equationText + result.ToString() + " " + operatorText2, "green")                
  990.                 end if
  991.                
  992.                 'Save to Memory, Set Last for "that" reference, and Return Result for TTS
  993.                 VA.SetDecimal("value" + countHistory.ToString(), result)
  994.                 VA.SetDecimal("AVCS_CALC_LastResult", result)
  995.                 VA.SetText("avcs_calc_return", result.ToString())              
  996.             end if
  997.            
  998.         end if
  999.        
  1000.     End Sub
  1001.    
  1002. End Class
RAW Paste Data