Trouble Setting up a Function and Some Fluff

Good day, fellow Quanrantinos!
You may remember me from my current project of making a fast character generator for D&D in Visual Studio 19!
Thus far, I've managed to make a program that rolls and displays the core stats not unlike a player with dice.
Here's what I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <random>

using namespace std;

int main() {
	srand((unsigned) time(0));
	int RN1, RN2, RN3, RN4, totSTR, RN5, RN6, RN7, RN8, totDEX, RN9, RN10, RN11, RN12, totINT, RN13, RN14, RN15, RN16, totCON, RN17, RN18, RN19, RN20, totCHA, RN21, RN22, RN23, RN24, totWIS;
	for (int index = 0; index < 1; index++) {
		RN1 = (rand() % 6) + 1;
		RN2 = (rand() % 6) + 1;
		RN3 = (rand() % 6) + 1;
		RN4 = (rand() % 6) + 1;
		int lowest;
		lowest = 0;
		if (RN1 < RN2, RN3, RN4) RN1 = lowest;
		else if (RN2 < RN1, RN3, RN4) RN2 = lowest;
		else if (RN3 < RN1, RN2, RN4) RN3 = lowest;
		else if (RN4 < RN1, RN2, RN3) RN4 = lowest;
		totSTR = RN1 + RN2 + RN3 + RN4;
	for (int index = 0; index < 1; index++) {
		RN5 = (rand() % 6) + 1;
		RN6 = (rand() % 6) + 1;
		RN7 = (rand() % 6) + 1;
		RN8 = (rand() % 6) + 1;
		int lowest2;
		lowest2 = 0;
		if (RN5 < RN6, RN7, RN8) RN5 = lowest2;
		else if (RN6 < RN5, RN7, RN8) RN6 = lowest2;
		else if (RN7 < RN5, RN6, RN8) RN7 = lowest2;
		else if (RN5 < RN6, RN6, RN7) RN8 = lowest2;
		totDEX = RN5 + RN6 + RN7 + RN8;
	for (int index = 0; index < 1; index++) {
		RN9 = (rand() % 6) + 1;
		RN10 = (rand() % 6) + 1;
		RN11 = (rand() % 6) + 1;
		RN12 = (rand() % 6) + 1;
		int lowest3;
		lowest3 = 0;
		if (RN9 < RN10, RN11, RN12) RN9 = lowest3;
		else if (RN10 < RN9, RN11, RN12) RN10 = lowest3;
		else if (RN11 < RN9, RN10, RN12) RN11 = lowest3;
		else if (RN12 < RN9, RN10, RN11) RN12 = lowest3;
		totINT = RN9 + RN10 + RN11 + RN12;
	for (int index = 0; index < 1; index++) {
		RN13 = (rand() % 6) + 1;
		RN14 = (rand() % 6) + 1;
		RN15 = (rand() % 6) + 1;
		RN16 = (rand() % 6) + 1;
		int lowest4;
		lowest4 = 0;
		if (RN13 < RN14, RN15, RN16) RN13 = lowest4;
		else if (RN14 < RN13, RN15, RN16) RN14 = lowest4;
		else if (RN15 < RN13, RN14, RN16) RN15 = lowest4;
		else if (RN16 < RN13, RN14, RN15) RN16 = lowest4;
		totCON = RN13 + RN14 + RN15 + RN16;
	for (int index = 0; index < 1; index++) {
		RN17 = (rand() % 6) + 1;
		RN18 = (rand() % 6) + 1;
		RN19 = (rand() % 6) + 1;
		RN20 = (rand() % 6) + 1;
		int lowest5;
		lowest5 = 0;
		if (RN17 < RN18, RN19, RN20) RN17 = lowest5;
		else if (RN18 < RN17, RN19, RN20) RN18 = lowest5;
		else if (RN19 < RN18, RN17, RN20) RN19 = lowest5;
		else if (RN20 < RN17, RN18, RN19) RN20 = lowest5;
		totCHA = RN17 + RN18 + RN19 + RN20;
	for (int index = 0; index < 1; index++) {
		RN21 = (rand() % 6) + 1;
		RN22 = (rand() % 6) + 1;
		RN23 = (rand() % 6) + 1;
		RN24 = (rand() % 6) + 1;
		int lowest6;
		lowest6 = 0;
		if (RN21 < RN22, RN23, RN24) RN21 = lowest6;
		else if (RN22 < RN21, RN23, RN24) RN22 = lowest6;
		else if (RN23 < RN21, RN22, RN24) RN23 = lowest6;
		else if (RN24 < RN21, RN22, RN23) RN24 = lowest6;
		totWIS = RN21 + RN22 + RN23 + RN24;
			cout << "Your Strength is: " << totSTR << endl;
			cout << "Your Dexterity is: " << totDEX << endl;
			cout << "Your Intelligence is: " << totINT << endl;
			cout << "Your Constitution is: " << totCON << endl;
			cout << "Your Charisma is: " << totCHA << endl;
			cout << "Your Wisdom is: " << totWIS << endl;
							}
						}
					}
				}
			}
		}
	}

Looks a like a real mess, huh? It gets the job done, but all of those extra lines sure don't look very nice, and they make the program a little more intensive than I'd prefer, especially after I add things like Class and Race Generation.
Now, my next task is to use the very first set of numbers and commands as function to display each stat by calling them one at a time. However, despite throwing myself at the tutorials for functions, I have yet to fully grasp it.
Here's my code thus far for that version:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <random>
using namespace std;

int Roll(int RN1, int RN2, int RN3, int RN4, int lowest) //Here I name the function and its variables
{
	srand((unsigned)time(0)); //Here, the srand rolls for the four numbers and sets the lowest to 0 successfully, and is meant to be the body of the function.
	for (int index = 0; index < 1; index++) {
		int RN1, RN2, RN3, RN4, lowest;
		RN1 = (rand() % 6) + 1;
		RN2 = (rand() % 6) + 1;
		RN3 = (rand() % 6) + 1;
		RN4 = (rand() % 6) + 1;
		lowest = 0;
		if (RN1 < RN2, RN3, RN4) RN1 = lowest;
		else if (RN2 < RN1, RN3, RN4) RN2 = lowest;
		else if (RN3 < RN1, RN2, RN4) RN3 = lowest;
		else if (RN4 < RN1, RN2, RN3) RN4 = lowest;
		return 0; //If I understand correctly, this returns control to int main.
	}

	int main(); 
	int totSTR; //This declares totSTR as an integer to be given value by the int Roll Function.
	{
		totSTR = Roll(int RN1 + int RN2 + int RN3 + int RN4); //Inexplicably, the squiggly-red underline of doom is allowing all four random numbers but the first despite being properly punctuated. It claims that the type name isn't allowed.
	cout << "Your Strength is: " << totSTR << endl; //The strange thing is that despite the program actually working fine (opening the window and display the rolled value), it also opens the Unable to Open File Window as if it didn't work. This is befuddling.
	}
}//This is probably something super simple that I'm just not seeing as a novice. Not unlike when I went to the Camel first when I started Breath of the Wild and didn't realize that after getting the map, I could rotate the Camel's central room in order to get around. I ran around for a collective three hours before realizing it. 

As you can see, I've cut the excess repetition, and am lead to believe that I can call the function multiple times to assign value to different totSTAT totals, not unlike the bulky version from before.
In addition to the odd happenings mentioned in the comments on the second set, I'm also still not too sure how to actually repeat the function for different results on different lines like:
 
cout << "Your Dexterity is:" << totDEX << endl;

Rather than Strength and totSTR?

Finally, one last bit of fluff:
What is the phenomenon called when selecting text, and rather than merely marking that spot with a blinking line to designate where I"m typing, it makes a grey box and anything I type replaces what's there with each character thus forcing me to crtl+x, crtl+v what I don't want to have to type again after I've made my changes.
It's bothersome and fiddly, and I'd like to know how to control or disable it.

Regardless, any assistance rendered would also be greatly appreciated. One day soon, I'm going to understand enough of this to make a career out of it. For that, I wish I could buy you all beers/sodas for your trouble.

Have fun and Stay safe!
you can call a function with an expression, but you must call a function with a variable that is put into each parameter.
you want result = roll(rn1, rn2, rn3, rn4);
not result = roll(rn1+rn2+rn3+rn4); //this sends only 1 parameter but you needed 4, it sends the sum of all those.

also you don't put type in the use part, only when building it do you need the types.

but lets stop here and make it even better, maybe.

another issuue is that srand should only be called once in a program unless you want to repeat a stream by intent (there are reasons to do that).

hang on a min.

move srand call to main. remove parameters -- parameters are inputs to a function that change its behavior or provide a way to return data, but you do not need them here. Use local variables instead, as shown below. return the value you computed not just a hard coded zero. remove extra variables and clutter. and we get:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int Roll() //Here I name the function and its variables
{
    int result = 0;
    int lowest = 7;
    int tmp;
    
    for(int i = 0; i < 4; i++)	
	{
	   tmp = rand()%6+1;
	   result += tmp;
	   if(tmp < lowest) lowest = tmp;
	}
    return(result - lowest); 
}


at the cost of easy to read this is doable in less code, but for now, see if this makes sense?

and main becomes
cout << "Your Strength is: " << roll() << endl; //if you need to save the result of roll, see next line
int str = roll();
cout << "Your Strength is: " << str << endl;

you include <random> but do not use it. why? srand is a very poor quality C tool, you should use the tools in <random> but do not.
Last edited on
with random: this is not ideal. Ideally you would put the random generation stuff into a little wrapper and not just shovel it into your function. But I am going to shovel it into your function anyway, along with a new idea: static variables in functions are only created one time. so in the below sample, once is created one time, with a value of true. if it is true, which it is the first time, it sets it to false. next time the function executes, it is still false, though: it skips the creation step and retains its last old value, which is false. so it only does that section one time, as desired. Like calling srand repeatedly, random is meant to be set up once and then consumed, not repeatedly set up, and I use static to do that rather than going into a more complicated but better solution.

with that in mind:


int Roll() //Here I name the function and its variables
{
   static default_random_engine generator;         
   static uniform_int_distribution<unsigned int> dp = uniform_int_distribution<unsigned int>(1,6);       
   static bool once = true;
   if(once)
   {  
     once = false; 
     generator.seed(time(0));  
     dp(generator); //workaround, my compiler gives 0 for first result, is bug
   }
   
    int result = 0;
	int lowest = 7;
	int tmp;
    for(int i = 0; i < 4; i++)	
	{
	   tmp = dp(generator);
	   result += tmp;
	   if(tmp < lowest) lowest = tmp;
	}
	return(result - lowest); 
}


yes, srand is less setup. But it is also far less flexible on top of being less than random: again, its a poor tool. The extra few lines of setup are well worth it, esp once you have them poked into a clean, reusable interface. Note that I was able to tell it to be from 1-6, so all that +1 and %6 junk goes away. Its really only 3 lines of setup compared to 1 (both need the seed statement).
Last edited on
Thank you for the help! I'm going to take the time and read through this as well as checking out your sample code.

The hardest part for me is getting myself to absorb what seems like complex information. However, once I understand it, it's in there, and actually making something and seeing it run is really satisfying.

You've been so good to me, thank you for helping me start this!
I see lots of use of commas in your code, in statements like:

if (RN1 < RN2, RN3, RN4)

Do you know what the comma operator actually means in C and C++? Does it achieve what you actuallly want these lines to do?
@MikeyBoy

It sure does! However, I both want and need to improve it before I can add more to it, and I'll learn in the process.
The point MikeyBoy was making was that's not how you check multiple conditions.
If you want to make sure that a is less than b, c, and d, then you do:
1
2
3
4
if (a < b && a < c && a < d)
{

}
Last edited on
It sure does!

Are you saying that you do understand what the comma operator means in C++?

Can you explain it in your own words?
@Ganado

Alright, then would that replace my else lines below the first if, or is it just superior syntax?
Alright, then would that replace my else lines below the first if

It's an example of how to do a compound conditional test in C++. You need to replace your code everywhere you do such a test. Obviously, just copying and pasting it won't work - you don't even have variables called a, b etc. But you need to adapt the technique that Ganado is showing you, so that it's suitable for each test you're doing.

or is it just superior syntax?


It's "superior" in the sense that it actually makes your code do what you clearly want it to, for all values, as opposed to the code you've written.
Topic archived. No new replies allowed.