Menu
News
All News
Dungeons & Dragons
Level Up: Advanced 5th Edition
Pathfinder
Starfinder
Warhammer
2d20 System
Year Zero Engine
Industry News
Reviews
Dragon Reflections
White Dwarf Reflections
Columns
Weekly Digests
Weekly News Digest
Freebies, Sales & Bundles
RPG Print News
RPG Crowdfunding News
Game Content
ENterplanetary DimENsions
Mythological Figures
Opinion
Worlds of Design
Peregrine's Nest
RPG Evolution
Other Columns
From the Freelancing Frontline
Monster ENcyclopedia
WotC/TSR Alumni Look Back
4 Hours w/RSD (Ryan Dancey)
The Road to 3E (Jonathan Tweet)
Greenwood's Realms (Ed Greenwood)
Drawmij's TSR (Jim Ward)
Community
Forums & Topics
Forum List
Latest Posts
Forum list
*Dungeons & Dragons
Level Up: Advanced 5th Edition
D&D Older Editions
*TTRPGs General
*Pathfinder & Starfinder
EN Publishing
*Geek Talk & Media
Search forums
Chat/Discord
Resources
Wiki
Pages
Latest activity
Media
New media
New comments
Search media
Downloads
Latest reviews
Search resources
EN Publishing
Store
EN5ider
Adventures in ZEITGEIST
Awfully Cheerful Engine
What's OLD is NEW
Judge Dredd & The Worlds Of 2000AD
War of the Burning Sky
Level Up: Advanced 5E
Events & Releases
Upcoming Events
Private Events
Featured Events
Socials!
EN Publishing
Twitter
BlueSky
Facebook
Instagram
EN World
BlueSky
YouTube
Facebook
Twitter
Twitch
Podcast
Features
Top 5 RPGs Compiled Charts 2004-Present
Adventure Game Industry Market Research Summary (RPGs) V1.0
Ryan Dancey: Acquiring TSR
Q&A With Gary Gygax
D&D Rules FAQs
TSR, WotC, & Paizo: A Comparative History
D&D Pronunciation Guide
Million Dollar TTRPG Kickstarters
Tabletop RPG Podcast Hall of Fame
Eric Noah's Unofficial D&D 3rd Edition News
D&D in the Mainstream
D&D & RPG History
About Morrus
Log in
Register
What's new
Search
Search
Search titles only
By:
Forums & Topics
Forum List
Latest Posts
Forum list
*Dungeons & Dragons
Level Up: Advanced 5th Edition
D&D Older Editions
*TTRPGs General
*Pathfinder & Starfinder
EN Publishing
*Geek Talk & Media
Search forums
Chat/Discord
Menu
Log in
Register
Install the app
Install
Community
General Tabletop Discussion
*Geek Talk & Media
d20 die roll string parser and roller in C#
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="FormerlyDickensC" data-source="post: 4104415" data-attributes="member: 53954"><p><strong>A bug fix</strong></p><p></p><p>Had to make a fix to the code where if you passed a die-string using only one die it would malfunction. So now, if you pass in "1d6" or "1d1000" or whatever it will. </p><p></p><p>I have also pasted the code here in the post below. </p><p></p><p>PS. I hate that I have to zip the file in order to upload it. </p><p></p><p>[CODE]</p><p> public static class Dice</p><p> {</p><p> private static Random randomGenerator = new Random();</p><p></p><p> /// <summary></p><p> /// Pass a die roll string in any standard d20-type format, including </p><p> /// parenthetical rolls, and it will output a string breaking down each </p><p> /// roll as well as summing the total. This works very nicely. The code was</p><p> /// hacked from java code from Malar's RPG Dice Version 0.9 By Simon Cederqvist </p><p> /// (simon.cederqvist(INSERT AT HERE) gmail.com). 13.March.2007</p><p> /// http://users.tkk.fi/~scederqv/Dice/</p><p> /// His same license still applies to this code. But if you figure out how to</p><p> /// make a million dollars off this code, then you're smarter than me and </p><p> /// you deserve to keep it. On the other hand, share and share alike. </p><p> /// </summary></p><p> /// <param name="diceString">This is a standard d20 die roll string, parenthesis </p><p> /// are allowed. Example Input: (2d8+9)+(3d6+1)-10</param></p><p> /// <returns>A string breaking down and summing the roll. Example Output: </p><p> /// (2d8+9)+(3d6+1)-10 = 7+4+9+5+1+2+1-10 = 20+9-10 = 19</returns></p><p> public static string Roll(string diceString)</p><p> {</p><p> StringBuilder finalResultBuilder = new StringBuilder();</p><p> string tempString = "";</p><p> int intermediateTotal = 0;</p><p> ArrayList sums = new ArrayList();</p><p> ArrayList items = new ArrayList();</p><p> ArrayList dice = new ArrayList();</p><p> int totals = 0;</p><p> bool collate = false;</p><p> bool positive = true;</p><p> string validChars = "1234567890d";</p><p> char[] diceCharArray = diceString.ToLower().ToCharArray();</p><p></p><p> for (int i = 0; i < diceString.Length; i++)</p><p> {</p><p> switch (diceCharArray[i])</p><p> {</p><p> case '+':</p><p> {</p><p> if (tempString.Length < 1)</p><p> {</p><p> positive = true;</p><p> break;</p><p> }</p><p> dice = calcSubStringRoll(tempString);</p><p> for (int j = 0; j < dice.Count; j++)</p><p> {</p><p> if (!positive)</p><p> {</p><p> items.Add(-1 * Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> else</p><p> {</p><p> items.Add(Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> }</p><p> if (!collate)</p><p> {</p><p> sums.Add(intermediateTotal);</p><p> intermediateTotal = 0;</p><p> }</p><p> positive = true;</p><p> tempString = "";</p><p> break;</p><p> }</p><p> case '-':</p><p> {</p><p> if (tempString.Length < 1)</p><p> {</p><p> positive = false;</p><p> break;</p><p> }</p><p> dice = calcSubStringRoll(tempString);</p><p> for (int j = 0; j < dice.Count; j++)</p><p> {</p><p> if (!positive)</p><p> {</p><p> items.Add(-1 * Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> else</p><p> {</p><p> items.Add(Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> }</p><p> if (!collate)</p><p> {</p><p> sums.Add(intermediateTotal);</p><p> intermediateTotal = 0;</p><p> }</p><p> positive = false;</p><p> tempString = "";</p><p> break;</p><p> }</p><p> case '(': collate = true; break;</p><p> case ')': collate = false; break;</p><p> default:</p><p> {</p><p> if (validChars.Contains("" + diceCharArray[i]))</p><p> tempString += diceCharArray[i];</p><p> break;</p><p> }</p><p> }</p><p> }</p><p></p><p> // And once more for the remaining text</p><p> if (tempString.Length > 0)</p><p> {</p><p> dice = calcSubStringRoll(tempString);</p><p> for (int j = 0; j < dice.Count; j++)</p><p> {</p><p> if (!positive)</p><p> {</p><p> items.Add(-1 * Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> else</p><p> {</p><p> items.Add(Convert.ToInt32(dice[j].ToString()));</p><p> intermediateTotal += (Convert.ToInt32(dice[j].ToString()));</p><p> }</p><p> }</p><p> sums.Add(intermediateTotal);</p><p> intermediateTotal = 0;</p><p> }</p><p></p><p> //// Print it all.</p><p> finalResultBuilder.Append(diceString + " = ");</p><p> for (int i = 0; i < items.Count; i++)</p><p> {</p><p> if (Convert.ToInt32(items[i].ToString()) > 0 && i > 0)</p><p> finalResultBuilder.Append("+" + items[i].ToString());</p><p> else</p><p> finalResultBuilder.Append(items[i].ToString());</p><p> }</p><p> if (sums.Count > 1 && items.Count > sums.Count)</p><p> { // Don't print just one, or items again.</p><p> finalResultBuilder.Append(" = ");</p><p> for (int i = 0; i < sums.Count; i++)</p><p> {</p><p> if (Convert.ToInt32(sums[i].ToString()) > 0 && i > 0)</p><p> finalResultBuilder.Append("+" + sums[i].ToString());</p><p> else</p><p> finalResultBuilder.Append(sums[i].ToString());</p><p> }</p><p> }</p><p> for (int i = 0; i < sums.Count; i++)</p><p> totals += Convert.ToInt32(sums[i].ToString());</p><p> finalResultBuilder.Append(" = " + totals + "\n");</p><p></p><p> return finalResultBuilder.ToString();</p><p> }</p><p></p><p></p><p> /// <summary></p><p> /// Rolls the specified number of die each with the specified number of</p><p> /// sides and returns the numeric result as a string. I had to introduce a </p><p> /// call to Thread.Sleep() so that the random num gen would seed differently on </p><p> /// each iteration. </p><p> /// </summary></p><p> /// <param name="numberOfDice">The number of die to roll.</param></p><p> /// <param name="numberOfSides">The number of faces on each dice rolled.</param></p><p> /// <param name="rollMod"></param></p><p> /// <returns>A string containing the result of the roll.</returns></p><p> public static string Roll(int numberOfDice, int numberOfSides, int rollMod)</p><p> {</p><p> // don't allow a Number of Dice less than or equal to zero</p><p> if (numberOfDice <= 0)</p><p> throw new ApplicationException("Number of die must be greater than zero.");</p><p></p><p> // don't allow a Number of Sides less than or equal to zero</p><p> if (numberOfSides <= 0)</p><p> throw new ApplicationException("Number of sides must be greater than zero.");</p><p></p><p> //// Create the string builder class used to build the string</p><p> //// we return with the result of the die rolls.</p><p> //// See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemtextstringbuilderclasstopic.asp</p><p> //StringBuilder result = new StringBuilder();</p><p></p><p> // Declare the integer in which we will keep the total of the rolls</p><p> int total = 0;</p><p> </p><p> // repeat once for each number of dice</p><p> for (int i = 0; i < numberOfDice; i++)</p><p> {</p><p> // Create the random class used to generate random numbers.</p><p> // See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemRandomClassTopic.asp</p><p></p><p> // Get a pseudo-random result for this roll</p><p> int roll = randomGenerator.Next(1, numberOfSides);</p><p></p><p> // Add the result of this roll to the total</p><p> total += roll;</p><p></p><p> //// Add the result of this roll to the string builder</p><p> //result.AppendFormat("Dice {0:00}:\t{1}\n", i + 1, roll);</p><p> }</p><p> </p><p> return (total + rollMod).ToString();</p><p></p><p> //// Add a line to the result to seperate the rolls from the total</p><p> //result.Append("\t\t--\n");</p><p></p><p> //// Add the total to the result</p><p> //result.AppendFormat("TOTAL:\t\t{0}\n", total);</p><p></p><p> //// Now that we've finished building the result, get the string</p><p> //// that we've been building and return it.</p><p> //return result.ToString(); </p><p></p><p> }</p><p></p><p> /// <summary></p><p> /// This function merely breaks down the *basic* die roll string</p><p> /// into the requsite integers. It is used by the above Roll(string) </p><p> /// method. </p><p> /// </summary></p><p> /// <param name="s">A simple die roll string, such as 3d6. Nothing more.</param></p><p> /// <returns>Returns an ArrayList of int's containing the various die</p><p> /// rolls as passed in as a parameter.</returns></p><p> public static ArrayList calcSubStringRoll(string s)</p><p> {</p><p> int x, d;</p><p> ArrayList dice = new ArrayList();</p><p> if (s.Contains("d"))</p><p> {</p><p> x = Convert.ToInt32(s.Split('d')[0]);</p><p> d = Convert.ToInt32(s.Split('d')[1]);</p><p></p><p> // I loop here so that each roll is added to the ArrayList, and </p><p> // therefore works properly with the code I hacked from java above. </p><p> for (int i = 0; i < x; i++)</p><p> dice.Add(Dice.Roll(1, d, 0));</p><p> }</p><p> else</p><p> dice.Add(Convert.ToInt32(s));</p><p></p><p> return dice;</p><p> }</p><p> }</p><p>[/CODE]</p></blockquote><p></p>
[QUOTE="FormerlyDickensC, post: 4104415, member: 53954"] [b]A bug fix[/b] Had to make a fix to the code where if you passed a die-string using only one die it would malfunction. So now, if you pass in "1d6" or "1d1000" or whatever it will. I have also pasted the code here in the post below. PS. I hate that I have to zip the file in order to upload it. [CODE] public static class Dice { private static Random randomGenerator = new Random(); /// <summary> /// Pass a die roll string in any standard d20-type format, including /// parenthetical rolls, and it will output a string breaking down each /// roll as well as summing the total. This works very nicely. The code was /// hacked from java code from Malar's RPG Dice Version 0.9 By Simon Cederqvist /// (simon.cederqvist(INSERT AT HERE) gmail.com). 13.March.2007 /// http://users.tkk.fi/~scederqv/Dice/ /// His same license still applies to this code. But if you figure out how to /// make a million dollars off this code, then you're smarter than me and /// you deserve to keep it. On the other hand, share and share alike. /// </summary> /// <param name="diceString">This is a standard d20 die roll string, parenthesis /// are allowed. Example Input: (2d8+9)+(3d6+1)-10</param> /// <returns>A string breaking down and summing the roll. Example Output: /// (2d8+9)+(3d6+1)-10 = 7+4+9+5+1+2+1-10 = 20+9-10 = 19</returns> public static string Roll(string diceString) { StringBuilder finalResultBuilder = new StringBuilder(); string tempString = ""; int intermediateTotal = 0; ArrayList sums = new ArrayList(); ArrayList items = new ArrayList(); ArrayList dice = new ArrayList(); int totals = 0; bool collate = false; bool positive = true; string validChars = "1234567890d"; char[] diceCharArray = diceString.ToLower().ToCharArray(); for (int i = 0; i < diceString.Length; i++) { switch (diceCharArray[i]) { case '+': { if (tempString.Length < 1) { positive = true; break; } dice = calcSubStringRoll(tempString); for (int j = 0; j < dice.Count; j++) { if (!positive) { items.Add(-1 * Convert.ToInt32(dice[j].ToString())); intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString())); } else { items.Add(Convert.ToInt32(dice[j].ToString())); intermediateTotal += (Convert.ToInt32(dice[j].ToString())); } } if (!collate) { sums.Add(intermediateTotal); intermediateTotal = 0; } positive = true; tempString = ""; break; } case '-': { if (tempString.Length < 1) { positive = false; break; } dice = calcSubStringRoll(tempString); for (int j = 0; j < dice.Count; j++) { if (!positive) { items.Add(-1 * Convert.ToInt32(dice[j].ToString())); intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString())); } else { items.Add(Convert.ToInt32(dice[j].ToString())); intermediateTotal += (Convert.ToInt32(dice[j].ToString())); } } if (!collate) { sums.Add(intermediateTotal); intermediateTotal = 0; } positive = false; tempString = ""; break; } case '(': collate = true; break; case ')': collate = false; break; default: { if (validChars.Contains("" + diceCharArray[i])) tempString += diceCharArray[i]; break; } } } // And once more for the remaining text if (tempString.Length > 0) { dice = calcSubStringRoll(tempString); for (int j = 0; j < dice.Count; j++) { if (!positive) { items.Add(-1 * Convert.ToInt32(dice[j].ToString())); intermediateTotal += (-1 * Convert.ToInt32(dice[j].ToString())); } else { items.Add(Convert.ToInt32(dice[j].ToString())); intermediateTotal += (Convert.ToInt32(dice[j].ToString())); } } sums.Add(intermediateTotal); intermediateTotal = 0; } //// Print it all. finalResultBuilder.Append(diceString + " = "); for (int i = 0; i < items.Count; i++) { if (Convert.ToInt32(items[i].ToString()) > 0 && i > 0) finalResultBuilder.Append("+" + items[i].ToString()); else finalResultBuilder.Append(items[i].ToString()); } if (sums.Count > 1 && items.Count > sums.Count) { // Don't print just one, or items again. finalResultBuilder.Append(" = "); for (int i = 0; i < sums.Count; i++) { if (Convert.ToInt32(sums[i].ToString()) > 0 && i > 0) finalResultBuilder.Append("+" + sums[i].ToString()); else finalResultBuilder.Append(sums[i].ToString()); } } for (int i = 0; i < sums.Count; i++) totals += Convert.ToInt32(sums[i].ToString()); finalResultBuilder.Append(" = " + totals + "\n"); return finalResultBuilder.ToString(); } /// <summary> /// Rolls the specified number of die each with the specified number of /// sides and returns the numeric result as a string. I had to introduce a /// call to Thread.Sleep() so that the random num gen would seed differently on /// each iteration. /// </summary> /// <param name="numberOfDice">The number of die to roll.</param> /// <param name="numberOfSides">The number of faces on each dice rolled.</param> /// <param name="rollMod"></param> /// <returns>A string containing the result of the roll.</returns> public static string Roll(int numberOfDice, int numberOfSides, int rollMod) { // don't allow a Number of Dice less than or equal to zero if (numberOfDice <= 0) throw new ApplicationException("Number of die must be greater than zero."); // don't allow a Number of Sides less than or equal to zero if (numberOfSides <= 0) throw new ApplicationException("Number of sides must be greater than zero."); //// Create the string builder class used to build the string //// we return with the result of the die rolls. //// See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemtextstringbuilderclasstopic.asp //StringBuilder result = new StringBuilder(); // Declare the integer in which we will keep the total of the rolls int total = 0; // repeat once for each number of dice for (int i = 0; i < numberOfDice; i++) { // Create the random class used to generate random numbers. // See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemRandomClassTopic.asp // Get a pseudo-random result for this roll int roll = randomGenerator.Next(1, numberOfSides); // Add the result of this roll to the total total += roll; //// Add the result of this roll to the string builder //result.AppendFormat("Dice {0:00}:\t{1}\n", i + 1, roll); } return (total + rollMod).ToString(); //// Add a line to the result to seperate the rolls from the total //result.Append("\t\t--\n"); //// Add the total to the result //result.AppendFormat("TOTAL:\t\t{0}\n", total); //// Now that we've finished building the result, get the string //// that we've been building and return it. //return result.ToString(); } /// <summary> /// This function merely breaks down the *basic* die roll string /// into the requsite integers. It is used by the above Roll(string) /// method. /// </summary> /// <param name="s">A simple die roll string, such as 3d6. Nothing more.</param> /// <returns>Returns an ArrayList of int's containing the various die /// rolls as passed in as a parameter.</returns> public static ArrayList calcSubStringRoll(string s) { int x, d; ArrayList dice = new ArrayList(); if (s.Contains("d")) { x = Convert.ToInt32(s.Split('d')[0]); d = Convert.ToInt32(s.Split('d')[1]); // I loop here so that each roll is added to the ArrayList, and // therefore works properly with the code I hacked from java above. for (int i = 0; i < x; i++) dice.Add(Dice.Roll(1, d, 0)); } else dice.Add(Convert.ToInt32(s)); return dice; } } [/CODE] [/QUOTE]
Insert quotes…
Verification
Post reply
Community
General Tabletop Discussion
*Geek Talk & Media
d20 die roll string parser and roller in C#
Top