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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }