SemlerPDX

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

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