Advertisement
Guest User

Untitled

a guest
Apr 7th, 2020
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 16.95 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using MonKey.Extensions;
  4. using QFSW.QC;
  5. using Sirenix.Utilities;
  6. using UnityEngine;
  7. using Random = UnityEngine.Random;
  8. namespace Overfors.Dices
  9. {
  10.     public static class Dice
  11.     {
  12.         public static int Roll(int sides, bool debug = false)
  13.         {
  14.             int result = Random.Range(1, sides + 1);
  15.             //if(debug) Debug.LogFormat("d{0} => {1}", sides, result);
  16.             return result;
  17.         }
  18.        
  19.         public static int Roll(int sides, DiceMod modifier, int modParameter)
  20.         {
  21.             int result = 0;
  22.             switch (modifier)
  23.             {
  24.                 case DiceMod.Advantage:
  25.                     result = Advantage(1, sides);
  26.                     break;
  27.                 case DiceMod.Disadvantage:
  28.                     result = Disadvantage(1, sides);
  29.                     break;
  30.                 case DiceMod.KeepHighest:
  31.                     result = KeepHighest(1, sides, modParameter);
  32.                     break;
  33.                 case DiceMod.KeepLowest:
  34.                     result = KeepLowest(1, sides, modParameter);
  35.                     break;
  36.                 case DiceMod.BaseAll:
  37.                     result = BaseAll(1, sides, modParameter);
  38.                     break;
  39.                 case DiceMod.BaseEach:
  40.                     result = BaseEach(1, sides, modParameter);
  41.                     break;
  42.             }
  43.             return result;
  44.         }
  45.  
  46.         public static int Roll(int nbr, int sides, bool debug = false)
  47.         {
  48.             int result = 0;
  49.             for (int i = 0; i < nbr; i++)
  50.             {
  51.                 result += Roll(sides);
  52.             }
  53.             //if(debug) Debug.LogFormat("{0}d{1} => {2}", nbr, sides, result);
  54.             return result;
  55.         }
  56.        
  57.         public static int Roll(int nbr, int sides, DiceMod modifier, int modParameter = 0)
  58.         {
  59.             int result = 0;
  60.             switch (modifier)
  61.             {
  62.                 case DiceMod.Advantage:
  63.                     result = Advantage(nbr, sides);
  64.                     break;
  65.                 case DiceMod.Disadvantage:
  66.                     result = Disadvantage(nbr, sides);
  67.                     break;
  68.                 case DiceMod.KeepHighest:
  69.                     result = KeepHighest(nbr, sides, modParameter);
  70.                     break;
  71.                 case DiceMod.KeepLowest:
  72.                     result = KeepLowest(nbr, sides, modParameter);
  73.                     break;
  74.                 case DiceMod.BaseAll:
  75.                     result = BaseAll(nbr, sides, modParameter);
  76.                     break;
  77.                 case DiceMod.BaseEach:
  78.                     result = BaseEach(nbr, sides, modParameter);
  79.                     break;
  80.             }
  81.             return result;
  82.         }
  83.        
  84.         private static int Advantage(int nbr, int sides)
  85.         {
  86.             (int first, int second) results = (Roll(nbr, sides), Roll(nbr, sides));
  87.             int result = results.first < results.second ? results.second : results.first;
  88.             string message = string.Format("Advantage {0}d{1} =>\n", nbr, sides);
  89.             //Debug.LogFormat(message + "1st {0}d{1}: {2} | 2nd {0}d{1}: {3} | Result: {4}", nbr, sides, results.first, results.second, result);
  90.             return result;
  91.         }
  92.         private static int Disadvantage(int nbr, int sides)
  93.         {
  94.             (int first, int second) results = (Roll(nbr, sides), Roll(nbr, sides));
  95.             int result = results.first < results.second ? results.first : results.second;
  96.             string message = string.Format("Disadvantage {0}d{1} =>\n", nbr, sides);
  97.             //Debug.LogFormat(message + "1st {0}d{1}: {2} | 2nd {0}d{1}: {3} | Result: {4}", nbr, sides, results.first, results.second, result);
  98.             return result;
  99.         }
  100.        
  101.         private static int KeepHighest(int nbr, int sides, int modParameter)
  102.         {
  103.             if (modParameter > nbr)
  104.             {
  105.                 //Debug.Log("Asked to keep more dice than there is. If you use KeepHighest or KeepLowest, you need to throw at least as much dices as you keep.");
  106.                 return 0;
  107.             }
  108.             int[] results = new int[nbr];
  109.             int result = 0;
  110.             for (int i = 0; i < results.Length; i++)
  111.             {
  112.                 results[i] = Roll(sides);
  113.             }
  114.             results.Sort();
  115.             results = results.Reverse().ToArray();
  116.             string message = string.Format("KeepHighest {0}d{1} keep {2} =>\n", nbr, sides, modParameter);
  117.             for (int i = 0; i < modParameter; i++)
  118.             {
  119.                 result += results[i];
  120.                 message += string.Format("{0}{1} Best d{2}: {3}\n", i+1, NbrSuffixe(i+1), sides, results[i]);
  121.             }
  122.             message += string.Format("Result: {0}", result);
  123.             //Debug.Log(message);
  124.             return result;
  125.         }
  126.         private static int KeepLowest(int nbr, int sides, int modParameter)
  127.         {
  128.             if (modParameter > nbr)
  129.             {
  130.                 Debug.Log("Asked to keep more dice than there is. If you use KeepHighest or KeepLowest, you need to throw at least as much dices as you keep.");
  131.                 return 0;
  132.             }
  133.            
  134.             int[] results = new int[nbr];
  135.             int result = 0;
  136.             for (int i = 0; i < results.Length; i++)
  137.             {
  138.                 results[i] = Roll(sides);
  139.             }
  140.             results.Sort();
  141.             string message = string.Format("KeepLowest {0}d{1} keep {2} =>\n", nbr, sides, modParameter);
  142.             for (int i = 0; i < modParameter; i++)
  143.             {
  144.                 result += results[i];
  145.                 message += string.Format("{0}{1} Worst d{2}: {3}\n", i+1, NbrSuffixe(i+1), sides, results[i]);
  146.             }
  147.             message += string.Format("Result: {0}", result);
  148.             //Debug.Log(message);
  149.             return result;
  150.         }
  151.        
  152.         private static int BaseAll(int nbr, int sides, int modParameter)
  153.         {
  154.             int rolls = Roll(nbr, sides);
  155.             int result = rolls < modParameter ? modParameter : rolls;
  156.             //Debug.LogFormat("BaseAll {0}d{1} =>\nBase: {2} | Rolls: {3} | Result: {4}", nbr, sides, modParameter, rolls, result);
  157.             return result;
  158.         }
  159.         private static int BaseEach(int nbr, int sides, int modParameter)
  160.         {
  161.             int result = 0;
  162.             string message = string.Format("BaseEach {0}d{1} =>\n", nbr, sides);
  163.             for (int i = 0; i < nbr; i++)
  164.             {
  165.                 int roll = Roll(sides);
  166.                 int rollResult = roll < modParameter ? modParameter : roll;
  167.                 message += string.Format("{0}{1} d{2} => Base: {3} | Roll: {4} | Result: {5}\n", i+1, NbrSuffixe(i+1), sides, modParameter, roll, rollResult);
  168.                 result += rollResult;
  169.             }
  170.             //Debug.LogFormat(message + "Final Result for {0}d{1}: {2}", nbr, sides, result);
  171.             return result;
  172.         }
  173.  
  174.         public static int StringToRoll(string diceString, bool debug = false)
  175.         {
  176.             //If doesn't contain d, it's not a dice roll
  177.             if (!diceString.Contains('d') && !diceString.Contains('D')) { WrongSyntax();
  178.                 return 0;
  179.             }
  180.            
  181.             //Turn d6 into 1d6
  182.             if (diceString[0] == 'd') diceString = diceString.Insert(0, "1");
  183.  
  184.             //Split in: Dice, Modifier, Modifier Amount
  185.             List<string> split = diceString.Split('[', ':', ']').ToList();
  186.             string dice = split[0];
  187.            
  188.             //Parse nbr and sides
  189.             int nbr = int.Parse(dice.Split('d', 'D')[0]);
  190.             int sides = int.Parse(dice.Split('d', 'D')[1]);
  191.            
  192.             //Remove empty splits
  193.             for (int i = 0; i < split.Count; i++)
  194.             {
  195.                 if(split[i] == "") {
  196.                     split.RemoveAt(i);
  197.                     i--;
  198.                 }
  199.             }
  200.            
  201.             //Debug every split
  202.             /*
  203.             foreach (var line in _split)
  204.             {
  205.                 Debug.Log(line);
  206.             }*/
  207.            
  208.             //If more than 1 split, means there's a modifier
  209.             if (split.Count > 1)
  210.             {
  211.                 //If more than 2 splits, means the modifier has a value
  212.                 if (split.Count > 2) return Roll(nbr, sides, StringToMod(split[1]), int.Parse(split[2]));
  213.                 return Roll(nbr, sides, StringToMod(split[1]));
  214.             }
  215.             return Roll(nbr, sides, debug);
  216.  
  217.             void WrongSyntax(string[] line = null)
  218.             {
  219.                 string message = "";
  220.                 if (line != null)
  221.                 {
  222.                     for (int i = 0; i < line.Length; i++)
  223.                     {
  224.                         message += string.Format("({0})", line[i]);
  225.                     }
  226.                 }
  227.                 Debug.LogFormat("Syntax isn't parseable into a dice. Syntax:\n" +
  228.                                "Roll 1 dice: dX | Note: d isn't case sensitive\n" +
  229.                                "Roll N dice: NdX | Note: can roll 1 dice\n" +
  230.                                "Roll N dice with mod: NdX[mod:modValue] | Note: modValue is optional\n" +
  231.                                "N => number of dice rolls | X number of sides\n" +
  232.                                "You typed : {0}", message);
  233.             }
  234.  
  235.             DiceMod StringToMod(string modString)
  236.             {
  237.                 switch (@modString)
  238.                 {
  239.                     case "KeepHigh":
  240.                     case "k":
  241.                     case "K":
  242.                     case "kh":
  243.                     case "Kh":
  244.                         return DiceMod.KeepHighest;
  245.                    
  246.                     case "KeepLow":
  247.                     case "kl":
  248.                     case "Kl":
  249.                         return DiceMod.KeepLowest;
  250.                    
  251.                     case "Base":
  252.                     case "BaseAll":
  253.                     case "b":
  254.                     case "B":
  255.                     case "ba":
  256.                     case "Ba":
  257.                     case "<":
  258.                         return DiceMod.BaseAll;
  259.                    
  260.                     case "BaseEach":
  261.                     case "be":
  262.                     case "Be":
  263.                     case "<<":
  264.                         return DiceMod.BaseEach;
  265.                    
  266.                     case "Advantage":
  267.                     case "adv":
  268.                     case "Adv":
  269.                     case "a":
  270.                     case "a²":
  271.                     case "best²":
  272.                         return DiceMod.Advantage;
  273.                    
  274.                     case "Disadvantage":
  275.                     case "dis":
  276.                     case "Dis":
  277.                     case "d":
  278.                     case "d²":
  279.                     case "worst²":
  280.                         return DiceMod.Disadvantage;
  281.                 }//
  282.                 return DiceMod.None;
  283.             }
  284.         }
  285.  
  286.         private static float StringToFloat(string value)
  287.         {
  288.             if (value.Contains('d') || value.Contains('D')) return StringToRoll(value);
  289.             else return float.Parse(value);
  290.         }
  291.  
  292.         private static readonly Dictionary<char, Operation> OperationDico = new Dictionary<char, Operation>()
  293.         {
  294.             {'+', Operation.Add},
  295.             {'-', Operation.Subtract},
  296.             {'*', Operation.Multiply},
  297.             {'x', Operation.Multiply},
  298.             {'/', Operation.Divide},
  299.             {'^', Operation.Power}
  300.         };
  301.  
  302.         [Command("roll", "Roll a macro of dices. Ex : 1d6 * 3d5")]
  303.         public static string StringRollCommand(string macro)
  304.         {
  305.             StringToOperation(macro, out string message);
  306.             return message;
  307.         }
  308.         public static float StringToOperation(string macro, out string description)
  309.         {
  310.             description = "Operation Failed";
  311.             //Check if it is an operation or just a simple roll
  312.             #region isOperation?
  313.             List<char> opChars = OperationDico.Keys.ToList();
  314.             bool isOperation = false;
  315.             for (int i = 0; i < opChars.Count; i++)
  316.             {
  317.                 if (macro.Contains(opChars[i])) isOperation = true;
  318.             }
  319.             if (!isOperation) return StringToRoll(macro, true);
  320.             #endregion
  321.            
  322.             //Remove every space
  323.             string operation = macro.Replace(" ", "");
  324.             //Parenthesis work in progress
  325.             /*
  326.             List<string> splits = operation.Split('(', ')').ToList();
  327.            
  328.             if (splits.Count == 1 && splits[0].IsNullOrEmpty()) return 0;
  329.             for (int i = 0; i < splits.Count; i++)
  330.             {
  331.                 if (splits[i].IsNullOrEmpty())
  332.                 {
  333.                     splits.RemoveAt(i);
  334.                     i--;
  335.                 }
  336.             }
  337.             Debug.Log(splits.Count);*/
  338.  
  339.             Dictionary<int, Operation> splitIndexes = new Dictionary<int, Operation>();
  340.             //Split at every operation and memorize operation
  341.             for (int i = 0; i < operation.Length; i++)
  342.             {
  343.                 foreach (var opChar in OperationDico.Keys)
  344.                 {
  345.                     if (operation[i] == opChar)
  346.                     {
  347.                         splitIndexes.Add(i, OperationDico[opChar]);
  348.                         operation = operation.Remove(i, 1);
  349.                         i--;
  350.                         break;
  351.                     }
  352.                 }
  353.             }
  354.            
  355.             var stringValues = operation.SplitAt(splitIndexes.Keys.ToArray()).ToList();
  356.             List<Operation> operations = splitIndexes.Values.ToList();
  357.            
  358.             List<float> values = new List<float>();
  359.            
  360.             //Convert strings to floats
  361.             for (int i = 0; i < stringValues.Count; i++)
  362.             {
  363.                 values.Add(StringToFloat(stringValues[i]));
  364.             }
  365.  
  366.             description = "";
  367.             for (int i = 0; i < values.Count; i++)
  368.             {
  369.                 description +=  $" {values[i]}";
  370.                 if (values[i].ToString() != stringValues[i]) description += $"({stringValues[i]})";
  371.                 if(i+1 != values.Count) description += $" {operationSymbols[operations[i]]} ";
  372.             }
  373.            
  374.             //Priority one operations: Multiply, Divide, Power
  375.             for (int i = 0; i < operations.Count; i++)
  376.             {
  377.                 if(operations[i] == Operation.Add || operations[i] == Operation.Subtract) continue;
  378.                 values[i] = ValuesOperation(values[i], values[i + 1], operations[i]);
  379.                 values.RemoveAt(i+1);
  380.                 operations.RemoveAt(i);
  381.                 i--;
  382.             }
  383.             //Priority two operations: Add, Substract
  384.             for (int i = 0; i < operations.Count; i++)
  385.             {
  386.                 values[i] = ValuesOperation(values[i], values[i + 1], operations[i]);
  387.                 values.RemoveAt(i+1);
  388.                 operations.RemoveAt(i);
  389.                 i--;
  390.             }
  391.             //Debug.LogFormat("{0} => {1}", macro, values[0]);
  392.             return values[0];
  393.         }
  394.  
  395.         public static Dictionary<Operation, string> operationSymbols = new Dictionary<Operation, string>()
  396.         {
  397.             {Operation.Add, "+"},
  398.             {Operation.Subtract, "-"},
  399.             {Operation.Multiply, "*"},
  400.             {Operation.Divide, "/"},
  401.             {Operation.Power, "^"},
  402.         };
  403.         private static float ValuesOperation(float valueOne, float valueTwo, Operation operation)
  404.         {
  405.             switch (operation)
  406.             {
  407.                 case Operation.Add:
  408.                     return valueOne + valueTwo;
  409.                 case Operation.Subtract:
  410.                     return valueOne - valueTwo;
  411.                 case Operation.Multiply:
  412.                     return valueOne * valueTwo;
  413.                 case Operation.Divide:
  414.                     return valueOne / valueTwo;
  415.                 case Operation.Power:
  416.                     return Mathf.Pow(valueOne, valueTwo);
  417.             }
  418.             Debug.LogError("Operation not Added");
  419.             return 0;
  420.         }
  421.         public static string NbrSuffixe(int nbr)
  422.         {
  423.             Dictionary<int, string> suffixes = new Dictionary<int, string>()
  424.             {
  425.                 {1, "st"},
  426.                 {2, "nd"},
  427.                 {3, "rd"}
  428.             };
  429.             if (nbr < 4) return suffixes[nbr];
  430.             else return "th";
  431.         }
  432.     }
  433.     public enum DiceMod
  434.     {
  435.         None,
  436.         KeepHighest,
  437.         KeepLowest,
  438.         BaseAll,
  439.         BaseEach,
  440.         Advantage,
  441.         Disadvantage
  442.     }
  443.    
  444.     public enum Operation{
  445.         Add,
  446.         Subtract,
  447.         Multiply,
  448.         Divide,
  449.         Power
  450.     }
  451.  
  452. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement