Tuesday, October 25, 2011

c0dehammer v0.1a - Combining "216" with Rerolls - Save Revision

In our last post we had the problem of how to deal with our Opponents Saving Throw if he has a reroll. What we learned is that if we take his failing sides of the dice and put that through our reroll() function it actually gives us a better chance of beating them. This obviously does that make sense. What we must do is think slightly backwards.

cout << "# of sides Opponent needs to Pass Save: ";
cin >> save;
save = (1-reroll(save));
Instead of asking what our opponents failures are we ask what the probability of passing his saving throw would be. From there we can properly get his success rate with a reroll. Now obviously we cannot use that number, as we would just run into the opposite problem as we had before. If we minus the percentage by 1, we can get the inverse percentage.

If our opponent has a 50% chance of passing, and therefore a 75% chance with a reroll, if we take 1 minus 0.75 we will get 0.25 or 25% of failing. Now that we have this we can play it right into our 216 calculation which may or may not exist anymore. Cheers.

c0dehammer v0.1a - Combining "216" with Rerolls

I am putting 216 in quotations because as we have discovered earlier... computers do not like fractions. The purpose of this lesson, is to combine what we have learned about rerolls and to combine that into the probability calculator we have already built. The easiest way to go about this is to copy and paste our code from the reroll calculator, make it its own function within the probability calculator and then get it to work. So without hesitation here it is:

#include <iostream>
using namespace std;

float reroll(float x)
{
    char a;
  
    cout << "Reroll? (y/n): ";
    cin >> a;

    if (a == 'y')
    {
        x = x / 6.0;
        x = x + ((1 - x) * x);
        return x;
    }

    else
    {
        x = x / 6.0;      
        return x;
    }
}  
  
int main()
{
      
    float hit, wound, save, result = 0.0;
  
    cout << "216 Probability Calculator" << endl;
  
    cout << "# of sides needed to Hit: ";
    cin >> hit;
    hit = reroll(hit);

    cout << "# of sides needed to Wound: ";
    cin >> wound;
    wound = reroll(wound);

    cout << "# of sides needed to Fail Save: ";
    cin >> save;
    save = save / 6.0;
  
    result = (hit * wound * save);
  
    cout << "Probability: " << result << endl;
  
  
    return 0;
}   
The first thing you will notice is this section here:

float reroll(float x)
{
    char a;
  
    cout << "Reroll? (y/n): ";
    cin >> a;

    if (a == 'y')
    {
        x = x / 6.0;
        x = x + ((1 - x) * x);
        return x;
    }

    else
    {
        x = x / 6.0;      
        return x;
    }
}    
It is almost exactly like our previous reroll calculator, with a few exceptions and less fluff. Although we could have used some IF statements after every input for hit, wound, and save, and then pasted in our piece of code, it makes much more sense to do the work only once. What happens is after we input each selection in the main() function we call up our reroll function.

cout << "# of sides needed to Hit: ";
cin >> hit;
hit = reroll(hit);
What this essentially does  is assign the value of hit to equal the the value returned by the reroll, however reroll also needs to know what we entered to hit, to come up with the modified answer. So we input hit, and then call up the function of reroll using the variable of hit, which returns the modified value of hit, and assigns it to the variable of hit overwriting what we put in. Sounds confusing yes, but trust me it makes sense. 

float reroll(float x)
What this indicated is that in order to run the function reroll() it needs an input value. This is where the reroll(float x) comes into play. The float before that indicated that the number returned will also be a float (in this case a percentage).

char a;
  
    cout << "Reroll? (y/n): ";
    cin >> a;
This is the next set of code we will concern ourselves with. In short we create a char variable (which is one single character) name a. We ask the user if they would like to reroll, they enter in "y" or "n" to the variable a. Well actually we will learn that it only matters if you enter in "y", this isnt yet user friendly and yes you can crash the program. Our next concern is this section in here:

if (a == 'y')
    {
        x = x / 6.0;
        x = x + ((1 - x) * x);
        return x;
    }

    else
    {
        x = x / 6.0;      
        return x;
    }
What we have done here is rather simple. If a equals a 'y' then we proceed with our reroll adjustment, and then return that result to the main() function. If it does not it divides x by 6. Well you might ask why we bother doing that. By dividing it by 6 we can turn it into a percentage value, and then we no longer have to divide our hit * wound * save by 216. If we did not do that then we would have to create a variable within main() to be our divisor. The calculation will still work with mixed percentages and fractions, but the divisor will change.

To Hit(%) * To Wound (fraction) * To Save (fraction) / 36
To Hit(%) * To Wound (%) * To Save (fraction) / 6

... and so on and so forth. Its just more logical to convert everything to one value type within a program. On paper do either or, or both.

The next noticeable thing will be this:

cout << "# of sides needed to Fail Save: ";
cin >> save;
save = save / 6.0;
No I have not gone crazy. This reroll will not work right with the save. Well it does, just opposite. For example: Our opponent has a 4+ save, which means we enter a 3 to fail. If he gets a reroll he now has a 75% chance of failing as opposed to a 50% chance. Its backwards. But that augmentation will be for the next post. Hopefully I have explained this well enough for you. Good Luck.

c0dehammer v0.1a - Understanding Re-Rolls

Before we get started with this one I am going to recommend you check out Redbeards article on DakkaDakka on Basics of Mathhammer and go over the probabilities of rerolls, as I personally would not understand it if not for him. The calculation of figuring out the percentage is:

p + ((1 - p) * p(from now on multiplication will be represented as an *)

So to steal his example if something hits on a 4+, which is the same as saying 3/6 or 1/2 or 50% or 0.5

p + ((1 - p) * p)
1/2 + ((1 - 1/2) * 1/2)
1/2 + ((1/2) * 1/2)
1/2 + 1/4
3/4

Which is the same as saying:

p + ((1 - p) * p)
0.5 + ((1 - 0.5) * 0.5)
0.5 + ((0.5)*0.5)
0.5 + 0.25
0.75

Provided you understand that the calculations between fractions and decimals are the same is all that matters. Although understanding WHY that formula works is important, Redbeard does a very good job of it, and I am not going to repeat his work (anymore). So lets create a simple program to figure out our changed probabilities with rerolls in mind.


#include <iostream>
using namespace std;

int main()
{
      
    float x =0.0;
      
    cout << "Reroll Probability Calculator" << endl;
    cout << "# of sides that indicate a Success: ";
    cin >> x;
  
    x = x / 6.0;
    x = x + ((1 - x) * x);
    cout << "Probability: " << x << endl;
  
  
    return 0;
}   
This is a better case of where c0dehammer could come in handy, as this isnt as easily accomplished as the 216 method on a calculator. You should have a slight understanding of what is going on in this program. We know that we are using a float because we are dealing with decimals (or percentages), and that the program is asking us to enter the amount of sides that will give us a successful result. This means that a 2+ would mean 5 sides indicate a success whereas a 5+ would mean 2 sides would equal a 6. We will work on making stuff more user friendly later on. This brings us to the part you may not understand:

x = x / 6.0;
x = x + ((1 - x) * x);
 The first thing that is happening is we are taking our variable that we entered and dividing it by 6. Why are we doing this you might ask? Computers don't handle fractions very well, so by dividing the number of successful sides by six we are changing our fraction into a decimal percentage that the computer will have an easier time digesting. As we know from above, the formula works whether we are dealing with percentages, or fractions, so the next part should look very familiar. If we replace x with p, we have our reroll probability formula. And lastly we display it on the screen. Pretty easy eh? Now our next step is to augment this into our already built calculator.

c0dehammer v0.1a - Simple 216

Alright folks, you may all be wondering what this about and I will tell you. I recently started getting back into Warhammer 40k, and discovered this magical new concept known as Mathhammer. Mathhammer is basically calculated the probabilities of a given outcome within the confines of the Warhammer rules. I find this concept very interesting, and wish to take it on step forward -creating our own basic set of programs to do the calculations for us. It will all be open source and your free to modify it as you see fit. Note, I am not a professional programmer, nor have I even dabbled in it for years, and my understanding of the Warhammer rules may be off time to time, feel free to point these mistakes out!

Without further ado, lets go over what is known as the basic 216 rule. There is a wonderful explanation of it here. Basically, three dice are rolled (to hit, to wound, to save,) in order to get a basic probability of the outcome.

(h * w * s) / 216 = x

h = # of sides of the d6 needed to successfully hit
w = # of sides of the d6 needed to successfully wound
s = # of sides of the d6 needed for the opponent to fail the save
x = the probability as a decimal

Therefore if a model needed a 3+ to hit, 4+ to wound, and the opponent saved on a 5+:

h = 4
w = 3
s = 4

(4 x 3 x 4) / 216 = 0.22 (repeating) or 22%

I wont go to much further into how this works, as there are plenty of resources already available to understand it. What I want to do is to turn this into a program. We will be using C++, because I am using Linux I have a built in C++ compiler. If you are not using Linux you will have to download a compiler. Dev C++ works with Windows and is free, I am not familiar with Mac compilers but it should not be hard to find one. First I will give you the code:

#include <iostream>
using namespace std;

int main()
{
      
    int hit, wound, save;
    float result = 0;
  
    cout << "216 Probability Calculator" << endl;
    cout << "# of sides needed to Hit: ";
    cin >> hit;
    cout << "# of sides needed to Wound: ";
    cin >> wound;
    cout << "# of sides needed to Fail Save: ";
    cin >> save;
  
    result = (hit * wound * save) /216.0;
  
    cout << "Probability: " << result << endl;
  
  
    return 0;
}  
Now if you dont understand C++ this will probably not make a lot of sense to you, but no worries as I will explain what is going on in this program.

#include <iostream>
using namespace std;

int main() {
    return 0;
}   
   
This is the basic framework of the program, for our purposes it not entirely important to know what everything does, just that this is how we set it up. If compiled this program will run, but will not do anything. The main() function is basically that, its the function that is executing the program, and whatever is inside those parenthesis. Now that we have that out of the way lets concentrate and getting this program to do something

#include <iostream>
using namespace std;

int main()
{
     
    cout << "216 Probability Calculator";
   
    return 0;
}  
   
What this will do if compiled is display: 216 Probability Calculator on the screen. Well thats all fine and dandy but dosent really DO anything for us, other then teaches us that the cout command will print whatever is in those quotations on the screen for us. If you want a better explanation I encourage you to look up some C++ tutorials. Ok well lets look at the next stage in the code, and see if we can make sense of it.

#include <iostream>
using namespace std;

int main()
{
      
    int hit, wound, save;
    float result = 0;
  
    cout << "216 Probability Calculator" << endl;
    cout << "# of sides needed to Hit: ";
    cin >> hit;
    cout << "# of sides needed to Wound: ";
    cin >> wound;
    cout << "# of sides needed to Fail Save: ";
    cin >> save;
   
    return 0;
}   
 
We know that the cout is going to print whatever is inside those quotations on the screen, but what about this new cin command? I am sure you have assumed that if cout puts stuff on the screen, cin must surely be putting something in the screen. Well not totally wrong but to understand it better we will start with variables. Variables are exactly how you remember them from math class, variables are "x". In programming languages however there can be many different types of variables. 
 int hit, wound, save;
 float result = 0;
This is us declaring our variables. We are creating integer variables (ie whole numbers, but I will explain the difference later). In this case we are creating three integer variables hit, wound, and save. It would be the same as programming this:

int hit;
int wound;
int save;

But instead of wasting all that time, we can just separate them by commas. We also have another type of variable known as a float, and have named this result. I am not going to go too far in to explaining the difference between a float and an integer other then a float will allow us to have a decimal value whereas an integer will not (remember whole numbers). You will notice result also has a " = 0" after it. This is us giving result a value of zero, the same as saying "x = 0" in a math equation. It is also important to note that you must use semicolons after every line of code, it tells the computer to "move on" to the next set of instructions.  Now that we have our variables, which are much like our 216 equation (hit x wound x save)/216 = result. We can start to make a little more sense of whats happening in this program. But how do we enter our information?

This is where the cin command comes into play. You will notice:

 cout << "# of sides needed to Hit: ";
 cin >> hit;
Appears each time for each variable we need. So the computer displays "# of sides needed to Hit:" which prompts us to enter something. Well this dosent happen on its own, we need the cin command to allow us to type something in. In this case we see our variable hit (dont worry too much about >> just know that they go either way depending on whether its cin or cout). Basically what the computer is telling us to do is to input the value for hit. Simple.

Now that we have an idea of whats going on, and how we are giving our variables a value we need to do something with them! Well we know the basic formula that we want to solve, but how do we accomplish it?

result = (hit * wound * save) /216.0;
cout << "Probability: " << result << endl;
This should look kind of familiar. What we are doing is very similar to what we did earlier when we assigned the variable result a value of zero. This time however we are assigning it a value that is equal to our variables hit, wound, and save multiplied by each other and divided by 216. Now that we have the answer to our question how do we display it? The next line of code should be somewhat understandable. We know the computer will display "Probability: " on the screen, but what about the rest? result is our variable (well its our answer), and endl is simply telling the computer to start a new line after this one is displayed. The << is just separating what is going on in that line of code, for lack of a better term.

It is important to make sure you put 216.0 instead of 216, or you will end up with a 0 instead of a decimal (it basically tells the computer to expect a decimal number). You will also notice if you want to try, if you change the variable of result from a float to an integer (int), you will also end up with a zero. You COULD use modulus (ie the remainder of a division) but that is a whole different show.

Well that is a long explanation for a program we could have done in 10 seconds with a calculator. So why bother? Well you shouldn't to be honest, which is why we are going to expand this idea to discover some information we cant attain with a calculator. Hopefully you give it a try, and play with it a bit! Peace.