(SOLVED) Enumerated Types, function inside function & probability...

Started by alexhans, Thu 22/11/2007 00:49:50

Previous topic - Next topic

alexhans

Hi, Im trying to code a function with enumerated types where i can choose different sets of probabilities for each option.  If I do it for a single probability it works allrigth but if I increase the number it doesnt recognize the other probabilities.  I imagine that the problem involves the way I coded the function because I use the function a number of times in a while for example:

[EDIT1]
THIS IS THE PROBLEM!!!! HERE:
It doesnt seem to recognize the different enums this way (gives me always the 50-50):

function somethingelse () {
while (intsomething > 500) {
                DoStuff(enum1);
                DoStuff(enum2);
                etc...
               
                intsomething++;
   }
}
[EDIT1]

Ive tried to code it directly in the while function,not making separate functions & without enum parameters and it worked but its much more messy...

Any ideas or help will be highly apprecciated... Sorry for the spelling I'm really running against de clock.

Code: ags

// Script header for module 'as'
int TeamCount[10];
int tipo;

struct Mankind {
  int Team;
};

int returno;

Mankind Man[500];

	enum SecondOption {
  primero, 
  segundo, 
  tercero
};

function second (SecondOption param) {
  int RanNo;
  RanNo = Random(99);
  if (param == primero) {
  if(RanNo < 0) returno = 1;                            // Its meant to be ALWAYS 2  (for testing)
  else if(RanNo < 100) returno = 2;
  }
  if (param == segundo) {
  if(RanNo < 50) returno = 1;                          // Its meant to be 1 or 2 50% each  (for testing)

  else if(RanNo < 100) returno = 2;
  }
  if (param == tercero) {
  if(RanNo < 100) returno = 1;                        // Its meant to be ALWAYS 1  (for testing)
  else if(RanNo < 0) returno = 2;
  }
}

function first () {
  int auxiliar,counter;
  //Pone todo en 0
  while (counter < 10) {
		TeamCount[counter] = 0;
		counter++;
		}
		counter = 0;
		
  while (counter < 500) {
    if((tipo > 3) || (tipo < 1)) { tipo = 1;}
    if(tipo == 1) {
		second(primero);
		auxiliar = returno;
		}
		if(tipo == 2) {
		second(segundo);
		auxiliar = returno;
		}
		if(tipo == 3) {
		second(tercero);
		auxiliar = returno;
		}
    TeamCount[auxiliar]++;
    counter++;
    tipo++;
  }

}
//END OF MODULE HEADER

I DID THE FOLLOWING TO CHECK AND IT CHOOSES THE 50 50 VALUES NO MATTER WHAT ENUM I RUN.  IVE TRIED IT WITH OTHER EXAMPLES...
// main global script file
#sectionstart repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE
function repeatedly_execute() {
  
  if(IsKeyPressed(32)) {
    first();
    Display("Tipo %d",tipo);
    Display("0 %d, 1 %d, 2 %d, 3 %d, 4 %d, 5 %d", TeamCount[0], TeamCount[1], TeamCount[2], TeamCount[3], TeamCount[4], TeamCount[5]);
  }
}
[CODE]
[/code]
Never let your sense of morals prevent you from doing what is right.

Dowland

Hello,

Could you explain what is wrong?

Code: ags
function second (SecondOption param) {
  int RanNo;
  RanNo = Random(99);
  if (param == primero) {
  if(RanNo < 0) returno = 1;
  else if(RanNo < 100) returno = 2;
  //else if(RanNo < 0) return 3;
  //else if(RanNo < 0) return 4;
  //else if(RanNo < 100) return 5;
  }
  if (param == segundo) {
  if(RanNo < 50) returno = 1;
  else if(RanNo < 100) returno = 2;
  //else if(RanNo < 50) return 3;
  //else if(RanNo < 75) return 4;
  //else if(RanNo < 100) return 5;
  }
  if (param == tercero) {
  if(RanNo < 100) returno = 1;
  else if(RanNo < 0) returno = 2;
  //else if(RanNo < 60) return 3;
  //else if(RanNo < 80) return 4;
  //else if(RanNo < 100) return 5;
  }
}

From what I see this function has several problems:

* first of all, Random(99) returns a number that is either 0, 1 ... 58 ... 99, so the case (RanNo < 0) should never occur (and is thus obsolete);

* second: a lot of stuff is commented out (I imagine you realize that?), or misordered.

Right now, this is what your function looks like:

Code: ags
function second (SecondOption param) {
  int RanNo;
  RanNo = Random(99);
  if (param == primero) {
    returno = 2;
  }
  if (param == segundo) {
    if(RanNo < 50) returno = 1;
    else returno = 2;
  }
  if (param == tercero) {
    returno = 1;
  }
}


Is that what you are trying to do? Perhaps, you could explain precisely what is you are trying to do, as opposed to what is wrong?

BTW ... what, exactly, is a "ManJob"? It sounds nice! ;D

alexhans

I did it on purpose "< 0" to have odds that give me 50 50, 100 0 or 0 100 in each case so I can see clearly if it works (its not gonna be like that after ive solved it)... but try it... it doesnt for enumerated types inside a function...

                           ALexhans

When i have time ill make it a little bit tidier,but if you get the point and know the answer HELP! 

Im trying to put a lot of different probabilities that can be called by one function with different enum parameters.



jeh... Manjob is something for a game but i need to sort this out (Exactly the Job of each character... ;)
Never let your sense of morals prevent you from doing what is right.

Dowland

I would definitely put the probabilities in a table with a big enough distribution.  I'm sorry, I'm too tired to be any clearer than mud!

Ashen

What exactly is the problem? It seems to work OK for me - but as I'm not entirely sure what it's meant to do, it's hard to tell...
It looks like it should be assigning 500 people to either teaam 1 or team 2 (eventually one of 5 teams), and it's doing that fine.
Enum parameters in a function should work - they always have for me - but in this case they all do the same thing, so it's not immediately obvious which is running (or why you've bothered with parameters in the first place). Mix up the return values a little, and it should be clearer what's working (or not).

One other thing: Have you really got everything declared in the Module Header, as the comment line at the top suggests? Try it with the struct and enums in the Header, and everything else declared in the Module Script and imported into the Header.
I know what you're thinking ... Don't think that.

Khris

alexhans:
You really don't need enums here. They are useful to replace arbitrary numbers with concrete readable descriptions, but in your case, they just clutter up the code.

Inside first() / while (<500), it makes much more sense to simply call second(tipo);.

You seem to want to distribute 500 team members to 5 teams according to three different, alternating probability schemes.

This process can be shortened by combining the probabilities.
I'll clarify using your testing scheme:
      Team 1   Team 2
     -----------------
1:  |    0   |  100   |
2:  |   50   |   50   |
3:  |  100   |    0   |

One third ends up in team 2, one third is split evenly between 1&2 and one third ends up on team 1.
In the end, they are distributed evenly among the two teams.
The probability for ending up in team 1 can be calculated: 0.33*0 + 0.33*50 + 0.33*100 = 50
Same for team 2 in this case.

Long story short: you don't need tables.

I'm wondering about the commented-out lines though.
The first one looks like it was 0,0,0,0,100, the second 0,25,50,75,100 and the third 20,40,60,80,100.

In the first one, everybody will end up in team 5; the second one doesn't add any members to team 1.
Is this what you intended?

If it is, the probabilities for the teams are 6.66, 15, 15, 15, 48.33.

alexhans

Ive edited the post...  Its not just three teams... its gonna be a lot more stuff like Weight (imagine 40 % fat 30 normal 20 skinny 10 obese whatever) and lots of other stufff that need to be identified by its enum name
Never let your sense of morals prevent you from doing what is right.

Khris

Quote from: alexhans on Thu 22/11/2007 00:49:50It doesnt seem to recognize the different enums this way (gives me always the 50-50)
Like Ashen explained and I did in my previous post, using 0-100, 50-50 and 100-0 will naturally result in 50-50.
Just switch the primero return values in second() and you'll end up with 83-17.

Also, regardless how many enum types there are going to be, you can always break it down to a single probability distribution. It's math. It works ;)

Ashen

Khris beat me to it, but here goes anyway:
Quote
It doesnt seem to recognize the different enums this way (gives me always the 50-50):

Nope, that's not the case. Add a couple of Displays to the if (param == conditions, and you'll see they ARE all getting run. (You'll probably want to lower that 500, if you do this - skipping 500 Display commands will get a bit tedious...) It's just that - as Khris said - the way you've done the distribution currently averages out at about a 50/50 split (the first run is always 2, the second is either 1 or 2, the third is always 1; repeat for the other 497 and you have about 250 in each team). It'd probably be more obvious if you have the different parameters add to teams other than 1 or 2 (if only second(tercero) can add to team 5 and there are some people in team 5, it must be working, right?)

So, the code's doing exactly what it should, that just doesn't seem to be what you want... (Which is why I had difficulty seeing the problem - sorry about that.)

If you want to choose a single distribution plan for all 500, I think the function would look more like this:
Code: ags

function first () {
  int auxiliar,counter;
  //Pone todo en 0
  while (counter < 10) {
	TeamCount[counter] = 0;
	counter++;
  }
  counter = 0;
  tipo = 1 + Random(2); // 1, 2 or 3
  while (counter < 500) {
	second(tipo);
	auxiliar = returno;
	TeamCount[auxiliar]++;
	counter++;
  }
}


Or, move the tipo = 1 + Random(2); inside the while loop, to have a slightly more random distribution (decides which to use on the fly - not just in a loop as it currently is).
I know what you're thinking ... Don't think that.

alexhans

mmmm I kinda get the point now  :-\

imagine this

Weight
20 % fat
50 % normal
30 % skinny

Height
20 % tall
40 % normal
40 % short

Skin
34 % caucasian
33% black
33 % asian

now you have a function with a while (and lots of extra stuff)

function Create () {
    while (counter < 40) {
    character.Weight = SPecialfunction(Weight);   // returning the value that belongs
    character.Height = SPecialfunction(height);        // returning the value that belongs   
    character.Skin = SPecialfunction(skin);             // returning the value that belongs      
    counter++;
}
}


How can I achieve this? bear in mind there are more than 3 options...
Never let your sense of morals prevent you from doing what is right.

Ashen

I think you where mostly there before you commented the code down to only return 1 or 2. Try something like:

Code: ags

function GetStat (StatName param) {
  int RanNo = Random(99);
  if (param == pWeight) {
    if (RanNo < 20) return wFat;
    if (RanNo < 70) return wNormal; // 20 + 50
    return wSkinny;
  }
  else if (param == pHeight) {
    if (RanNo < 20) return hTall;
    if (RanNo < 60) return hNormal;
    return hShort;
  }
  else if (param == pSkin) {
    if (RanNo < 34) return sCaucasian;
    if (RanNo < 67) return sBlack;
    return sAsian;
  }
  // Etc
}


function Create() {
  int counter;
  while (counter < 40) {
    Man[counter].Weight = GetStat(pWeight);
    Man[counter].Height = GetStat(pHeight);
    Man[counter].Skin = GetStat(pSkin);
    // Etc
    counter ++;
  }
}


And the enums would look like:
Code: ags

enum StatName {
  pWeight,
  pHeight,
  pSkin,
  // Etc
};

enum StatWeight {
  wFat,
  wNormal,
  wSkinny,
  // Etc
};

enum StatHeight {
  hTall,
  hNormal,
  hShort,
  // Etc
};

enum StatSkin {
  sCaucasian,
  sBlack,
  sAsian,
  // Etc
};

// Etc, with other enums for other statistics, if needed

You don't HAVE to have enums for all the statistics but you might find it's easier to check than, e.g. Man[27].Height = 2;.
I know what you're thinking ... Don't think that.

alexhans

I Finally found out my problem thanks to your ideas & help, The problem was the way I counted the stuff all together and it is solved by using different counters for each Probability set (this can be done as a struct).

                                 Thank you all for your help     :D

                                                                Alexhans
Code: ags

// Script header for module 'as'
int CountFirst[10];
int CountSecond[10];
int CountThird[10];

struct Mankind {
  int Team;
};

int returno;

Mankind Man[500];

	enum FirstOption {
  primero, 
  segundo, 
  tercero
};

function first (FirstOption tipos) {
  int auxiliar,counter;
  int RanNo;
  RanNo = Random(99);
  if(tipos == primero) {
    if(RanNo < 0) returno = 1;
    else if(RanNo < 100) returno = 2;
  }
  if(tipos == segundo) {
    if(RanNo < 100) returno = 1;
    else if(RanNo < 100) returno = 2;
  }
  if(tipos == tercero) {
    if(RanNo < 50) returno = 1;
    else if(RanNo < 100) returno = 2;
  }
  auxiliar = returno;
  if(tipos == 1) {CountFirst[auxiliar]++; }
	if(tipos == 2) {CountSecond[auxiliar]++; }
	if(tipos == 3) {CountThird[auxiliar]++; }
}

function RAPIDO () {
  int auxiliar,counter;
  //Makes all cero
  while (counter < 10) {
    CountFirst[counter] = 0;
    CountSecond[counter] = 0;
    CountThird[counter] = 0;
    counter++;
  }
  counter = 0;
  while (counter < 500) {
    first(1);
    first(2);
    first(3);
    counter++;
  }
}

// IN GLOBLAL SCRIPT
if(IsKeyPressed(32)) {
    RAPIDO();
    Display("First  0 %d, 1 %d, 2 %d, 3 %d, 4 %d, 5 %d", CountFirst[0], CountFirst[1], CountFirst[2], CountFirst[3], CountFirst[4], CountFirst[5]);
    Display("Second 0 %d, 1 %d, 2 %d, 3 %d, 4 %d, 5 %d", CountSecond[0], CountSecond[1], CountSecond[2], CountSecond[3], CountSecond[4], CountSecond[5]);
    Display("Third  0 %d, 1 %d, 2 %d, 3 %d, 4 %d, 5 %d", CountThird[0], CountThird[1], CountThird[2], CountThird[3], CountThird[4], CountThird[5]);
  }

Quoteif (RanNo < 20) return wFat;
QuoteMan[counter].Weight = GetStat(pWeight);
Ashen... Im seeing your solution right now and I think it works... but as it is if
RanNo < 20: Man[counter].Weight = wFat, can a variable like the weight that must be an int take that kind of value? What do you do with it?

                               Thanks anyway
Never let your sense of morals prevent you from doing what is right.

Ashen

Quote
RanNo < 20: Man[counter].Weight = wFat, can a variable like the weight that must be an int take that kind of value? What do you do with it?

That's pretty much what happens, yes, but I don't understand your question. Enum values are ints, they're just 'named' to make it easier to read. Man[counter].Weight = wFat is just the same as Man[counter].Weight = 1 but makes it more obvious what weight is being assigned (Fat, Normal or Skinny instead of 1, 2 or 3). In your new code you use (tipos == primero) and (tipos == 1) - and they both mean the same thing.

You can change what the enum values are (e.g. so the Weight values are pounds instead of arbitary numbers) by editing the enum declaration:
Code: ags

enum test {
  tFirst = 2, // By default, the first value is 1
  tSecond = 37,
  tThird , // No set value, so it'll be the last value + 1 (38 in this case)
  tFourth = 9
};
I know what you're thinking ... Don't think that.

SMF spam blocked by CleanTalk