public void TestLine(string input, bool resolve = true) { // First, let's parse it CalcObject obj1 = CLInterpreter.Interpret(input); // And put it back to string and back string code2 = obj1.ToCode(); CalcObject obj3 = CLInterpreter.Interpret(code2); string code4 = obj3.ToCode(); // code2 and code4 need to match Assert.AreEqual(code2, code4, "code2 and code4 don't match on line: " + input); // We'll stop here if we're testing non-deterministic functions if (!resolve) { return; } // Then, let's get the value CalcValue val5 = obj1.GetValue(); string code6 = val5.ToCode(); CalcObject obj7 = CLInterpreter.Interpret(code6); string code8 = obj7.ToCode(); CalcValue val9 = obj7.GetValue(); // code6 and code8 need to match Assert.AreEqual(code6, code8, "code6 and code8 don't match on line: " + input); // val5 and val9 also need to match Assert.AreEqual(val5, val9, "val5 and val9 don't match on line: " + input); }
public string TestLine(string line, CLLocalStore vars, CLContextProvider context, string expected) { // We'll parse the line as usual CalcObject obj1 = CLInterpreter.Interpret(line); string code2 = obj1.ToCode(); CalcObject obj3 = CLInterpreter.Interpret(code2); string code4 = obj3.ToCode(); // Make sure things look right Assert.AreEqual(code2, code4); // Now get the value out of it CalcValue val5 = obj3.GetValue(vars, context); string code6 = val5.ToCode(); CalcObject obj7 = CLInterpreter.Interpret(code6); string code8 = val5.ToCode(); CalcValue val9 = obj7.GetValue(vars, context); // Make sure things still look right Assert.AreEqual(code6, code8); Assert.AreEqual(val5, val9); // Now we should also make sure the values reported are as expected. Assert.AreEqual(code8, expected); // And we'll return the final value so it can be used later! return(code8); }
private void Set() { if (this.nRows == 0) { MessageBox.Show("Generate data first."); return; } try { int row = Row; int col = Col; string val = CalcValue.ToString(); this.data[row, col] = val; ShowObject(); } catch (IndexOutOfRangeException ex1) { MessageBox.Show("Please enter a valid row and column index.\r\nException: " + ex1.Message); } catch (FormatException ex2) { MessageBox.Show("Please enter a valid row and column index.\r\nException: " + ex2.Message); } }
/// <summary> /// 适用于Calc.D Calc.E /// </summary> /// <returns></returns> public ValueC AsValueC() { // value值为 >123 或 =123 或 >123 if (CalcType != CalcType.D && CalcType != CalcType.E) { return(new ValueC(false)); } if (string.IsNullOrEmpty(CalcValue)) { return(new ValueC(false)); } if (CalcValue[0] != '<' && CalcValue[0] != '=' && CalcValue[0] != '>') { return(new ValueC(false)); } try { return(new ValueC(true) { Opt = CalcValue[0], Param = Convert.ToInt32(CalcValue.Substring(1)) }); } catch (Exception) { return(new ValueC(false)); } }
private void ExecuteSetCommand(object param) { if (NRows == 0) { MessageBox.Show("Generate data first."); return; } try { int row = Row; int col = Col; string val = CalcValue.ToString(); if (this.nRows != row && this.nCols != col) { data[row, col] = val; } else { MessageBox.Show("Please enter a valid row and column index.\nThis field is belongs to Sum of the rows and columns"); } ShowObject(); } catch (IndexOutOfRangeException ex1) { MessageBox.Show("Please enter a valid row and column index.\r\nException: " + ex1.Message); } catch (FormatException ex2) { MessageBox.Show("Please enter a valid row and column index.\r\nException: " + ex2.Message); } }
// Gets the parameter at a given index in the params list as a value. public static CalcValue ValueAt(CalcObject[] pars, int index, string name, CLLocalStore vars, CLContextProvider context) { if (pars.Length <= index) { throw new CLException($"{name} parameter {index} was not specified."); } CalcValue val = pars[index].GetValue(vars, context); return(val); }
private static DiceDie FunctionDie(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length < 2) { throw new CLException("{!die} requires two params: A number and a value."); } CalcNumber num = NumberAt(pars, 0, "!die", vars, context); CalcValue val = pars[1].GetValue(); return(new DiceDie(num.Value, val)); }
// Returns the list, with all its elements negated. public static CalcValue PreMinusList(CalcObject param, CLLocalStore vars, CLContextProvider context) { CalcList lstParam = param as CalcList; CalcValue[] lstRet = new CalcValue[lstParam.Count]; for (int i = 0; i < lstRet.Length; i++) { lstRet[i] = PrefixMinus.Run(lstParam[i], vars, context); } return(new CalcList(lstRet)); }
/// <summary> /// Calc.A /// </summary> /// <returns></returns> public ValueA AsValueA() { // value值为 or:count>123,amount<789 或 and:count>123,amount<789 if (CalcType != CalcType.A) { return(new ValueA(false)); } if (string.IsNullOrEmpty(CalcValue)) { return(new ValueA(false)); } var value = CalcValue.ToLower(); if (value.StartsWith("and") || value.StartsWith("or")) { try { var o = new ValueA(true); var a = value.Split(':')[0]; if (a == "and") { o.And = true; } var tmp = value.Split(':')[1]; var vals = tmp.Split(','); var status = false; foreach (var val in vals) { if (val.StartsWith("count")) { status = true; o.CountOpt = val.Substring(5, 1)[0]; o.CountParam = Convert.ToInt32(val.Substring(6)); } else if (val.StartsWith("amount")) { status = true; o.AmountOpt = val.Substring(6, 1)[0]; o.AmountParam = Convert.ToInt32(val.Substring(7)); } } return(status ? o : new ValueA(false)); } catch (Exception) { return(new ValueA(false)); } } return(new ValueA(false)); }
// Gets the parameter at a given index in the params list as a number. internal static CalcNumber NumberAt(CalcObject[] pars, int index, string name, CLLocalStore vars, CLContextProvider context) { if (pars.Length <= index) { throw new CLException(name + " parameter " + index + " was not specified."); } CalcValue val = pars[index].GetValue(vars, context); if (!(val is CalcNumber num)) { throw new CLCastException(name + " parameter " + index + " must be a number."); } return(num); }
// Returns the quotient of a list's items over a number. public static CalcValue BinDivideList(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcList lstLeft = left as CalcList; CalcNumber numRight = right as CalcNumber; // We will *not* do string checking here // It's entirely possible someone writes a string divider and this function will use it. CalcValue[] lstRet = new CalcValue[lstLeft.Count]; for (int i = 0; i < lstRet.Length; i++) { lstRet[i] = BinaryDivide.Run(lstLeft[i], numRight, vars, context); } return(new CalcList(lstRet)); }
private void buttonEqualization_Click(object sender, EventArgs e) { if (textEkran.Text != "") { double temp; if (labelTemp.Text.EndsWith("+")) { if (Double.TryParse(textEkran.Text, out temp)) { CalcValue = CalcValue + temp; } } else if (labelTemp.Text.EndsWith("-")) { if (Double.TryParse(textEkran.Text, out temp)) { CalcValue = CalcValue - temp; } } else if (labelTemp.Text.EndsWith("*")) { if (Double.TryParse(textEkran.Text, out temp)) { CalcValue = CalcValue * temp; } } else if (labelTemp.Text.EndsWith("/") && textEkran.Text != "0" && textEkran.Text != "0." && textEkran.Text != "-0." && textEkran.Text != "-0" && textEkran.Text != "-") { if (Double.TryParse(textEkran.Text, out temp)) { CalcValue = CalcValue / temp; } } else if (textEkran.Text == "0" || textEkran.Text == "0." || textEkran.Text == "-0." || textEkran.Text == "-0" || textEkran.Text == "-") { labelTemp.Text = "Division by zero!"; } } textEkran.Text = CalcValue.ToString(); if (labelTemp.Text != "Division by zero!") { labelTemp.Text = String.Empty; } }
// Concatenates two lists. public static CalcValue BinPlusLists(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcList lstLeft = left as CalcList; CalcList lstRight = right as CalcList; CalcValue[] lstRet = new CalcValue[lstLeft.Count + lstRight.Count]; int i; for (i = 0; i < lstLeft.Count; i++) { lstRet[i] = lstLeft[i]; } for (int j = 0; j < lstRight.Count; j++) { lstRet[i + j] = lstRight[j]; } return(new CalcList(lstRet)); }
// Multiplies a list by a number. public static CalcValue BinTimesList(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcList lstLeft = left as CalcList; CalcNumber numRight = right as CalcNumber; // If it has a string, we'll just repeat the list multiple times. if (lstLeft.HasString()) { int count = (int)numRight; if (count < 0) { throw new CLException("Lists cannot be repeated negative times."); } CalcValue[] lstRet = new CalcValue[lstLeft.Count * count]; for (int i = 0; i < count; i++) { for (int j = 0; j < lstLeft.Count; j++) { lstRet[i * lstLeft.Count + j] = lstLeft[j]; } } return(new CalcList(lstRet)); } else { // Otherwise we'll multiply everything by the number. CalcValue[] lstRet = new CalcValue[lstLeft.Count]; for (int i = 0; i < lstRet.Length; i++) { lstRet[i] = BinaryTimes.Run(lstLeft[i], numRight, vars, context); } return(new CalcList(lstRet)); } }
/// <summary> /// Calc.B Calc.C /// </summary> /// <returns></returns> public ValueB AsValueB() { // value值为 or:123,789 或 and:123,789 if (CalcType != CalcType.B && CalcType != CalcType.B) { return(new ValueB(false)); } if (string.IsNullOrEmpty(CalcValue)) { return(new ValueB(false)); } var value = CalcValue.ToLower(); var tmp = value.Split(':'); var op = tmp[0]; if (op == "and" || op == "or") { if (!string.IsNullOrEmpty(tmp[0])) { try { var o = new ValueB(true); o.And = op == "and"; var v = tmp[1].Split(','); o.Param = v.Select(x => int.Parse(x)).ToArray(); return(o); } catch (Exception) { return(new ValueB(false)); } } } return(new ValueB(false)); }
private static CalcValue BinDice(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { int limit = int.MaxValue; DiceContext dc = null; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } CalcNumber numLeft = (CalcNumber)left; CalcNumber numRight = null; CalcList lstRight = null; bool list = false; // Now figure out how many dice to roll... int count = (int)(numLeft.Value); // ... and whether or not it's within limits (including the limitation that it must be positive) if (count <= 0) { throw new CLException("The number of dice to roll must be positive."); } else if (count > limit) { count = limit; } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += count; } // Now figure out how many sides each die has... int sides = 0; // (Are we using a list or a number for the sides?) if (right is CalcNumber) { numRight = (CalcNumber)right; sides = (int)(numRight.Value); } else if (right is CalcList) { lstRight = (CalcList)right; sides = lstRight.Count; list = true; } // ... and ensure it's at least one. if (sides < 1) { throw new CLException("Dice must have at least one side."); } // Now we can roll the dice! CalcValue[] ret = new CalcValue[count]; Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } for (int i = 0; i < count; i++) { int choice = rand.Next(sides); if (list) { CalcValue val = lstRight[choice]; if (val is CalcNumber valNum) { ret[i] = new DiceDie(valNum.Value, lstRight); } else if (val is CalcList valList) { ret[i] = new DiceDie(valList.Sum(), lstRight); } else { throw new CLException("Dice must be numeric values."); // maybe I'll change this one day } } else { ret[i] = new DiceDie(choice + 1, new CalcNumber(sides)); } } CalcList output = new CalcList(ret); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out Type actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}d{right.ToCode()}", output)); } return(output); }
public DiceDie(decimal value, CalcValue sides) : base(value) { Sides = sides; }
private static CalcValue KeepDropNumber(CalcList list, int count, bool keep, bool highest, CLLocalStore vars) { // Shortcuts if (list.Count == 0) { vars["_d"] = new CalcList(new CalcValue[0]); return(list); } if (count >= list.Count) { if (keep) { vars["_d"] = new CalcList(new CalcValue[0]); return(list); } else { vars["_d"] = list; return(new CalcList(new CalcValue[0])); } } else if (count <= 0) { if (keep) { vars["_d"] = list; return(new CalcList(new CalcValue[0])); } else { vars["_d"] = new CalcList(new CalcValue[0]); return(list); } } // The long way int found = 0; bool[] action = new bool[list.Count]; decimal next = highest ? decimal.MinValue : decimal.MaxValue; decimal current = next; decimal[] values = new decimal[list.Count]; for (int i = 0; i < list.Count; i++) { // Get value of list item CalcValue val = list[i]; CalcNumber num = val as CalcNumber; if (num == null) { num = ListToNum(val); } values[i] = num.Value; } while (found < count) { for (int i = 0; i < list.Count && found < count; i++) { // If this is already one we found, skip it if (action[i]) { continue; } // Otherwise, if it's the next value, grab it if (values[i] == current) { action[i] = true; found++; } // Otherwise, check to see if it can be the next value if (highest) { next = Math.Max(next, values[i]); } else { next = Math.Min(next, values[i]); } } current = next; next = highest ? decimal.MinValue : decimal.MaxValue; } // Now make the outputs CalcValue[] fits = new CalcValue[count]; CalcValue[] noFits = new CalcValue[list.Count - count]; // Split the values into the two lists int fitCount = 0; int noFitCount = 0; for (int i = 0; i < list.Count; i++) { if (action[i]) { fits[fitCount++] = list[i]; } else { noFits[noFitCount++] = list[i]; } } if (keep) { vars["_d"] = new CalcList(noFits); return(new CalcList(fits)); } else { vars["_d"] = new CalcList(fits); return(new CalcList(noFits)); } }
private static CalcValue CompRerolls(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context, bool keep = false, bool recurse = false) { CalcList lstLeft = (CalcList)left; CalcNumber numRight = (CalcNumber)right; List <CalcValue> output = new List <CalcValue>(); DiceContext dc = null; int limit = 0; int limitUsed = 0; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } // Go through the list foreach (CalcValue val in lstLeft) { decimal value; if (val is CalcNumber valNum) { value = valNum.Value; } else if (val is CalcList valList) { value = valList.Sum(); } else { throw new CLException("Re-rolls only work with numeric values."); } // If it's a value we need to re-roll if (comp.CompareFunction(value, numRight.Value)) { // Keep the original value ("x" and "xr" operators) if (keep) { output.Add(val); } // Now make another value (or recurse) bool redo = true; // Now figure out how many sides each die has... int sides = 0; bool list = false; CalcValue dSides; CalcList lstSides = null; if (val is DiceDie die) { dSides = die.Sides; // (Are we using a list or a number for the sides?) if (dSides is CalcNumber nSides) { sides = (int)(nSides.Value); } else if (dSides is CalcList lSides) { lstSides = lSides; sides = lSides.Count; list = true; } } else { decimal valValue = 0; if (val is CalcNumber nVal) { valValue = nVal.Value; } else if (val is CalcList lVal) { valValue = lVal.Sum(); } else { throw new CLException("Reroll only works with numeric values."); } if (valValue < 0) { valValue *= -1; } sides = (valValue <= 6) ? 6 : (valValue <= 20) ? 20 : (valValue <= 100) ? 100 : (valValue <= 1000) ? 1000 : (valValue <= 10000) ? 10000 : (valValue <= 100000) ? 100000 : (valValue <= 1000000) ? 1000000 : (valValue <= 10000000) ? 10000000 : (valValue <= 100000000) ? 100000000 : (valValue <= 1000000000) ? 1000000000 : 2147483647; dSides = new CalcNumber(sides); } // Now we can roll the dice! Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } while (redo && limitUsed < limit) { int choice = rand.Next(sides); limitUsed++; decimal cValue = 0; if (list) { CalcValue cVal = lstSides[choice]; if (cVal is CalcNumber cNum) { cValue = cNum.Value; output.Add(new DiceDie(cValue, lstSides)); } else if (cVal is CalcList cList) { cValue = cList.Sum(); output.Add(new DiceDie(cValue, lstSides)); } } else { cValue = choice + 1; output.Add(new DiceDie(cValue, new CalcNumber(sides))); } // recursion? if (recurse) { redo = comp.CompareFunction(cValue, numRight.Value); } else { redo = false; } } } else { // The reroll comparison wasn't satisfied output.Add(val); } } return(new CalcList(output.ToArray())); }
private static CalcValue CompUntil(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars, CLContextProvider context) { int limit = int.MaxValue; DiceContext dc = null; // We need to get the limits if they've been set if (context.ContainsDerived(typeof(DiceContext), out Type actualDiceContext)) { dc = (DiceContext)(context.Get(actualDiceContext)); limit = Math.Min(dc.PerRollLimit, dc.PerFunctionLimit - dc.PerFunctionUsed); if (limit == 0) { throw new LimitedDiceException(); } } CalcNumber numLeft = null; CalcList lstLeft = null; bool list = false; CalcNumber numRight = (CalcNumber)right; // Now figure out how many sides each die has... int sides = 0; // (Are we using a list or a number for the sides?) if (left is CalcNumber) { numLeft = (CalcNumber)left; sides = (int)(numLeft.Value); } else if (left is CalcList) { lstLeft = (CalcList)left; sides = lstLeft.Count; list = true; } // ... and ensure it's at least one. if (sides < 1) { throw new CLException("Dice must have at least one side."); } // Now we can roll the dice! List <CalcValue> lstRet = new List <CalcValue>(); Random rand = null; if (context.ContainsDerived(typeof(Random), out Type actualRandom)) { rand = (Random)(context.Get(actualRandom)); } else { rand = new Random(); } CalcList output = null; Type actual = null; for (int i = 0; i < limit; i++) { // First determine the value int choice = rand.Next(sides); CalcNumber value = null; if (list) { CalcValue val = lstLeft[choice]; if (val is CalcList valList) { value = new DiceDie(valList.Sum(), lstLeft); } else if (val is CalcNumber valNum) { value = new DiceDie(valNum.Value, lstLeft); } } else { value = new DiceDie(choice + 1, new CalcNumber(sides)); } // See if it satisfies the comparison if (comp.CompareFunction(value.Value, numRight.Value)) { vars["_u"] = value; output = new CalcList(lstRet.ToArray()); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output)); history.Add(($"Killed above roll:", ValToList(value))); } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += i + 1; } return(output); } else { lstRet.Add(value); } } vars["_u"] = new CalcNumber(0); output = new CalcList(lstRet.ToArray()); // Add to roll history if (context.ContainsDerived(typeof(List <(string, CalcList)>), out actual)) { List <(string, CalcList)> history = (List <(string, CalcList)>)context.Get(actual); history.Add(($"{left.ToCode()}u{comp.PostfixSymbol}{right.ToCode()}", output)); } // also remember to actually UPDATE the limits! (╯°□°)╯︵ ┻━┻ if (dc != null) { dc.PerFunctionUsed += limit; } return(output); }