private static CalcValue BinRepeat(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { List <CalcValue> ret = new List <CalcValue>(); CalcNumber numRight = (CalcNumber)right; int count = (int)numRight.Value; CalcObject _i = null; if (vars.ContainsVar("_i")) { _i = vars["_i"]; } for (int i = 0; i < count; i++) { vars["_i"] = new CalcNumber(i); ret.Add(left.GetValue(vars, context)); } if (_i != null) { vars["_i"] = _i; } return(new CalcList(ret.ToArray())); }
// Returns the left raised to the power of the right. public static CalcValue BinPowerNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcNumber numLeft = left as CalcNumber; CalcNumber numRight = right as CalcNumber; return(new CalcNumber((decimal)Math.Pow((double)(numLeft.Value), (double)(numRight.Value)))); }
// Adds two numbers. public static CalcValue BinPlusNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcNumber numLeft = left as CalcNumber; CalcNumber numRight = right as CalcNumber; return(new CalcNumber(numLeft + numRight)); }
public static CalcValue BinIntDivideNumbers(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcNumber numLeft = left as CalcNumber; CalcNumber numRight = right as CalcNumber; return(new CalcNumber(decimal.Floor(numLeft / numRight))); }
public static void Load(int factPriority = FactPriority) { LoadPostFactorial(factPriority); numE = new CalcNumber((decimal)Math.E); numPI = new CalcNumber((decimal)Math.PI); E = new CLCodeFunction("e", (pars, vars, context) => numE); PI = new CLCodeFunction("pi", (pars, vars, context) => numPI); Abs = new CLCodeFunction("abs", AbsFunction); Acos = new CLCodeFunction("acos", AcosFunction); Acosh = new CLCodeFunction("acosh", AcoshFunction); Asin = new CLCodeFunction("asin", AsinFunction); Asinh = new CLCodeFunction("asinh", AsinhFunction); Atan = new CLCodeFunction("atan", AtanFunction); Atan2 = new CLCodeFunction("atan2", Atan2Function); Atanh = new CLCodeFunction("atanh", AtanhFunction); Cos = new CLCodeFunction("cos", CosFunction); Cosh = new CLCodeFunction("cosh", CoshFunction); Sin = new CLCodeFunction("sin", SinFunction); Sinh = new CLCodeFunction("sinh", SinhFunction); Tan = new CLCodeFunction("tan", TanFunction); Tanh = new CLCodeFunction("tanh", TanhFunction); Ceiling = new CLCodeFunction("ceiling", CeilingFunction); CopySign = new CLCodeFunction("copysign", CopySignFunction); Floor = new CLCodeFunction("floor", FloorFunction); Log = new CLCodeFunction("log", LogFunction); Max = new CLCodeFunction("max", MaxFunction); MaxMagnitude = new CLCodeFunction("maxmagnitude", MaxMagnitudeFunction); Min = new CLCodeFunction("min", MinFunction); MinMagnitude = new CLCodeFunction("minmagnitude", MinMagnitudeFunction); Sign = new CLCodeFunction("sign", SignFunction); }
public static CalcValue SignFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length == 0) { throw new CLException("{!sign} requires a number."); } CalcNumber num = NumberAt(pars, 0, "!sign", vars, context); return(new CalcNumber(Math.Sign(num))); }
// Returns the natural logarithm of the parameter. public static CalcValue LogFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length == 0) { throw new CLException("{!log} requires a number."); } CalcNumber num = NumberAt(pars, 0, "!floor", vars, context); return(new CalcNumber((decimal)Math.Log((double)num.Value))); }
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)); }
public static CalcValue PostFactNumber(CalcObject param, CLLocalStore vars, CLContextProvider context) { CalcNumber num = param as CalcNumber; int o = 1; for (int i = 2; i < num.Value; i++) { o *= i; } return(new CalcNumber(o)); }
// Returns a number with magnitude x and sign of y public static CalcValue CopySignFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length < 2) { throw new CLException("{!copysign} requires two numbers."); } CalcNumber x = NumberAt(pars, 0, "!copysign", vars, context); CalcNumber y = NumberAt(pars, 1, "!copysign", vars, context); return(new CalcNumber((decimal)Math.CopySign((double)x.Value, (double)y.Value))); }
// Returns the minimum value out of the list. public static CalcValue MinFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length == 0) { throw new CLException("{!min} requires numbers."); } decimal min = Decimal.MaxValue; for (int i = 0; i < pars.Length; i++) { CalcNumber num = NumberAt(pars, i, "!min", vars, context); min = Math.Min(min, num.Value); } return(new CalcNumber(min)); }
// 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)); }
// Returns the minimum value out of the list. public static CalcValue MinMagnitudeFunction(CalcObject[] pars, CLLocalStore vars, CLContextProvider context) { if (pars.Length == 0) { throw new CLException("{!minmagnitude} requires numbers."); } decimal min = (decimal)Decimal.MinValue; for (int i = 0; i < pars.Length; i++) { CalcNumber num = NumberAt(pars, i, "!minmagnitude", vars, context); if (Math.Abs(num.Value) < min) { min = num; } } return(new CalcNumber(min)); }
// Multiplies a string by a number. public static CalcValue BinTimesString(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcString strLeft = left as CalcString; CalcNumber numRight = right as CalcNumber; int count = (int)numRight; if (count < 0) { throw new CLException("Strings cannot be repeated negative times."); } string strRet = ""; for (int i = 0; i < count; i++) { strRet += strLeft; } return(new CalcString(strRet)); }
protected void Button1_Click(object sender, EventArgs e) { double CalcNumber; try { if (DropDownList1.SelectedValue == "Add") { CalcNumber = Convert.ToDouble(resultTB.Text) + Convert.ToDouble(entryTB.Text); ViewState["Number"] = CalcNumber.ToString(); } else if (DropDownList1.SelectedValue == "Subtract") { CalcNumber = Convert.ToDouble(resultTB.Text) - Convert.ToDouble(entryTB.Text); ViewState["Number"] = CalcNumber.ToString(); } else if (DropDownList1.SelectedValue == "Divide") { CalcNumber = Convert.ToDouble(resultTB.Text) / Convert.ToDouble(entryTB.Text); ViewState["Number"] = CalcNumber.ToString(); } else { CalcNumber = Convert.ToDouble(resultTB.Text) * Convert.ToDouble(entryTB.Text); ViewState["Number"] = CalcNumber.ToString(); } } catch (FormatException) { Response.Write("Please input a number."); } }
// 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)); } }
private static CalcValue KeepCompare(CalcObject left, CLComparison comp, CalcObject right, CLLocalStore vars) { CalcList lstLeft = (CalcList)left; CalcNumber numRight = (CalcNumber)right; List <CalcValue> kept = new List <CalcValue>(); List <CalcValue> dropped = new List <CalcValue>(); foreach (CalcValue val in lstLeft) { if (comp.CompareFunction(ValueOf(val), numRight.Value)) { kept.Add(val); } else { dropped.Add(val); } } vars["_d"] = new CalcList(dropped.ToArray()); return(new CalcList(kept.ToArray())); }
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())); }
// Returns the number, negated. public static CalcValue PreMinusNumber(CalcObject param, CLLocalStore vars, CLContextProvider context) { CalcNumber numParam = param as CalcNumber; return(new CalcNumber(-numParam)); }
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); }
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); }
// Parses a single "operation chain" private static CalcObject ParseChain(List <CLObjectPiece> pieces) { // First, we can't parse an empty list. if (pieces.Count == 0) { throw new CLSyntaxException("Empty list received.", 0); } LinkedList <CLExpressionBuilder> exps = new LinkedList <CLExpressionBuilder>(); CalcObject hold = null; bool valueLast = false; // Loop through all the pieces now. while (pieces.Count != 0) { CLObjectPiece piece = pieces[0]; // Get the next value, if there is one. CalcObject obj = null; bool err = false; // If it's a ()[]}, if (piece.Type == CLObjectPieceType.Spacer) { if (piece.Contents == "(") { if (!valueLast) { obj = ParseParentheses(pieces); } else { err = true; } } else if (piece.Contents == "[") { if (!valueLast) { obj = ParseList(pieces); } else { err = true; } } else /* ], ), }, , */ { // Send control back up a parser level break; } } else if (piece.Type == CLObjectPieceType.FunctionName) { if (!valueLast) { obj = ParseFunction(pieces); } else { err = true; } } else if (piece.Type == CLObjectPieceType.Number) { if (!valueLast) { obj = new CalcNumber(Decimal.Parse(piece.Contents)); pieces.RemoveAt(0); } else { err = true; } } else if (piece.Type == CLObjectPieceType.String) { if (!valueLast) { // Strip the quotes string check = piece.Contents.Substring(1, piece.Contents.Length - 2); // Parse special characters check = check.Replace(@"\\", "\uF000") .Replace(@"\n", "\n") .Replace(@"\t", "\t") .Replace(@"\", "") .Replace("\uF000", @"\"); obj = new CalcString(check); pieces.RemoveAt(0); } else { err = true; } } if (err) { throw new CLSyntaxException("Two consecutive values", piece.Position); } // If there's a value, put it in the most recent expression if (obj != null) { valueLast = true; // If there's no expression, just hold the value. if (exps.Count == 0) { hold = obj; } else { // Put it on the most recent expression CLExpressionBuilder exp = exps.Last.Value; exp.Right = obj; } continue; } // Otherwise, this piece must be an operator. CLExpressionBuilder expNew = new CLExpressionBuilder(); CLOperator op = null; valueLast = false; if (piece.Type == CLObjectPieceType.BinaryOperator) { op = CLOperators.BinaryOperators[piece.Contents]; } else if (piece.Type == CLObjectPieceType.PrefixOperator) { op = CLOperators.PrefixOperators[piece.Contents]; } else if (piece.Type == CLObjectPieceType.PostfixOperator) { op = CLOperators.PostfixOperators[piece.Contents]; } expNew.Operator = op; // If it's the first operator... if (exps.Count == 0) { // ... use the held value if one exists if (hold != null) { expNew.Left = hold; } exps.AddLast(expNew); } // Otherwise... else { // For prefix operators we don't need to check priorities to the // left. They can just stack on in. if (op is CLPrefixOperator) { exps.Last.Value.Right = expNew; exps.AddLast(expNew); } else { CLExpressionBuilder expOld = null; CLExpressionBuilder expNext = null; // This code removes expressions from the stack that are a // higher priority than the one being removed, or that are // postfix. while (exps.Count != 0) { expNext = exps.Last.Value; if ( // The next expression is a postfix expression. expNext.Operator is CLPostfixOperator || // The next expression on the stack is still higher // priority expNext.Operator.Priority > op.Priority || // The next expression on the stack is equal priority, // but evaluated left-to-right (expNext.Operator.Priority == op.Priority && !CLOperators.IsFromRight(op.Priority)) ) { expOld = exps.Last.Value; exps.RemoveLast(); expNext = null; } else { break; } } // The last removed expression becomes the left of this one. // (If there's no such expression, then the right of the next // expression on the stack becomes our left.) if (expOld != null) { expNew.Left = expOld; } else { expNew.Left = expNext.Right; } // Then, this expression becomes the right of the next one. if (expNext != null) { expNext.Right = expNew; } exps.AddLast(expNew); } } pieces.RemoveAt(0); } if (exps.Count == 0) { return(hold); } else { return(exps.First.Value.Build()); } }
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)); } }