# random number generator help (weidu)

## Recommended Posts

So I've been using the random (1 x) thing. It has been okay, but I was wondering if someone knew a way to get a little more desirable results.

Here's the scenario with simple numbers:

Let's say that I want to pick 5 numbers.

Let's say the range from 1-4.

With that range and that amount of picks, it's possible the random numbers picked come back 4, 1, 4, 4, and 2, right?

Can someone out suggest a way to make a function or something that uses up the 1-4 combinations before picking a new number? So it could be 4, 2, 1, 3 and then after all numbers are used up it could pick a 2 again. Does that make sense?

Basically, I'd like to use all the available numbers before picking a repeating number. Is this possible with a function or something in Weidu?

A random seed is a random seed... that being said, what are you seeding ?
A dialog is a lot different than seeding an variable(timers for example) in a .spl file. Like:

OUTER_SET timer1 = RANDOM(1 100)
...
PATCH_IF (~spell_level~ = 1) BEGIN
WRITE_LONG ("%fx_off%" + 0x0e) (timer1) // User-defined values
END

Aka can it be done via "in game scripting" or ?

So I've been using the random (1 x) thing. It has been okay, but I was wondering if someone knew a way to get a little more desirable results.

Here's the scenario with simple numbers:

Let's say that I want to pick 5 numbers.

Let's say the range from 1-4.

With that range and that amount of picks, it's possible the random numbers picked come back 4, 1, 4, 4, and 2, right?

Can someone out suggest a way to make a function or something that uses up the 1-4 combinations before picking a new number? So it could be 4, 2, 1, 3 and then after all numbers are used up it could pick a 2 again. Does that make sense?

Basically, I'd like to use all the available numbers before picking a repeating number. Is this possible with a function or something in Weidu?

If it's for weidu directly, just create a list or array of all the seen variables. Here's some pseudocode:

```seen = []
final = []
N=10
r = lerandom(1,4)
while r in seen and N > 0:
r = lerandom(1,4)
if r in seen: continue
seen += r
N--
if seen.length % 4 == 0:
final += seem
seen = []
```

If it's for weidu directly, just create a list or array of all the seen variables. Here's some pseudocode:

`seen = []final = []N=10r = lerandom(1,4)while r in seen and N > 0:  r = lerandom(1,4)  if r in seen: continue  seen += r  N--  if seen.length % 4 == 0:    final += seem    seen = []`
The code is not for dialogue so I won't be patching individual baf files. I think lynx might be closest.

Let me see if I understand that correctly..

N is equal to the number of picks right? And it's a counter that counts down and when it hits 0 it resets?

That really sounds like what I need, now to test it out...

Here's my attempt at converting that into weidu tp2... I'm sure it's not right yet...

```BACKUP ~Test/backup~
AUTHOR ~Smeagolheart~
VERSION ~1.0~

BEGIN ~Test~
DESIGNATED 0

DEFINE_ACTION_MACRO ~GetRndNumber~
INT_VAR
"Max"                     = "0"
BEGIN
OUTER_SET \$seen(x) = ~~
// seen     = []

OUTER_SET \$final(x) = ~~
// final     = []

OUTER_SET r = RANDOM ( 1 ~%Max%~ )
// r = lerandom(1,4)

WHILE (r IN seen) AND (N > 0) BEGIN
// WHILE r in seen and N > 0
OUTER_SET r = RANDOM ( 1 ~%Max%~ )
// r = lerandom(1,4)
ACTION_IF (r IN seen) BEGIN
// if r in seen: continue
OUTER_SET seen += r
OUTER_SET n -= 1
// n--
END
ACTION_IF (seen.length % 4 == 0) BEGIN
// if seen.length % 4 == 0:
OUTER_SET final += seen
OUTER_SET \$seen(x) = ~~
// seen = []
END
END
END

//variables...
OUTER_SET maxnumber     = 4
OUTER_SET maxnumberB    = 32
OUTER_SET N             = 10

LAUNCH_ACTION_MACRO ~GetRndNumber~
INT_VAR
"Max"        = ~%maxnumber%~
END

/*  etc
LAUNCH_ACTION_MACRO ~GetRndNumber~
INT_VAR
"Max"        = ~%maxnumberB%~
END
*/

END```

I'm pretty sure weidu will choke on the +=. Yes, N was meant as the number of numbers you want. I also forgot to put the first r (before the loop) into seen.

+= and -= work well if you place SET or OUTER_SET in front of the instruction.

SET/OUTER_SET won't work for assigning strings however. Use OUTER_TEXT_SPRINT or TEXT_SPRINT instead.

so is my array stuff correct? it's something I'm not sure of here, also I've never used them before in weidu. I saw the array construct section in weidu instructions and I'm all confused.

I rarely use weidu, so can't be of much help. Just try it and repeat. You also have a n/N typo in there.

Come to think of it, it would be faster if you took a different approach. Generate all possible numbers and add them to a list. Then use random indices and resizing. Can't loop indefinitely that way.

Generate all possible numbers and add them to a list.

Ok I can do that.

Then use random indices and resizing.

Yeah that part I have no idea in Weidu how to do it.

EDIT:

Now that I think about it, I'm going to be passing multiple numbers (set of numbers A, B, C, etc) to this random thing so I'm going to need multiple lists to maintain of my numbers. That will get unwieldy fast.

I'm curious what you're using this for. Does it have to be decided at install-time? WeiDU is not the best language for manipulating lists.

Well, I tried to tackle the problem myself (loosely based on the algorithm lynx had in mind):

```// Global definitions
OUTER_SET randomRangeMin  = 0     // lower bound
OUTER_SET randomRangeMax  = 1     // upper bound
OUTER_SET randomNumValues = 0     // internally used to keep track of spent values
OUTER_SET randomResult    = randomRangeMin // contains the random value from the last GetUniqueRandom call
// RANDOM_SEED 1234          // uncomment and set to get reproducible results

// Returns a random value in "randomResult" that does not repeat until all values of the defined range have been spent
DEFINE_ACTION_MACRO GetUniqueRandom
BEGIN
LOCAL_SET rangeCount = randomRangeMax - randomRangeMin + 1
LOCAL_SET idx = 0
LOCAL_SET value = 0

// array initialization
ACTION_IF (randomNumValues = 0) BEGIN
LOG ~DEBUG: Initializing random list~

OUTER_WHILE (randomNumValues < rangeCount) BEGIN
OUTER_SET value = RANDOM (randomRangeMin randomRangeMax)
OUTER_FOR (idx = 0; idx < randomNumValues; ++idx) BEGIN
ACTION_IF (EVAL "randomArray_%idx%" = value) BEGIN
OUTER_SET value = randomRangeMin - 1
OUTER_SET idx = randomNumValues
END
END
ACTION_IF (value >= randomRangeMin) BEGIN
OUTER_SET EVAL "randomArray_%randomNumValues%" = value
OUTER_SET randomNumValues += 1
END
END
END

// "randomResult" contains the new random value
OUTER_SET randomNumValues -= 1
OUTER_SET randomResult = EVAL "randomArray_%randomNumValues%"
END
```

I had some trouble using the array notation "\$myArray(x)", so I used the slightly more complicated notation of EVAL "myArray_%x%".

And a short test sequence:

```OUTER_SET randomRangeMin = 1
OUTER_SET randomRangeMax = 8
OUTER_FOR (idx = 0; idx < 24; ++idx) BEGIN
LAM GetUniqueRandom
PRINT ~Random value: %randomResult%~
END
```

This is for a portraits mod I'm making that's going to cover all portraits for IWDEE, BGEE and BG2EE. It should go well with EET. The number of things that speak in those games is around 4500. That's a big number. I'm not going to make individual portraits for all of them, that's just too many so I'm creating banks of pictures - eg Drow, Elf, Halfling, Human, etc etc etc.that I will hand out at install time. There are two ways to hand them out in order or randomly. I've got install options for either. I don't know about you but I tend to restart games often and with different loads of mods sometimes and I like the idea of random guys getting random portraits.

I have this working now (install options of sequential or random application of my portrait banks). The random option uses repeats some as you would expect with random numbers - you can get 5 guys using portrait #6 before using up all combinations. So I'd prefer it to use up all the portraits before reusing them. To be clear - if you have 45 drow male speakers and only 20 portraits, there will be repeats anyway but I just want to reduce the repeats a bit.

These portrait banks will be for guys named generically like "Drow" or "Guard". I try and make individual drow unique like Captain Elgard or something would get his own portrait.

If that code works on the code framework there then it should work for the mod. I'll test it out and report back. I'm going to have to keep track of each bank with separate counters (drow random index, Halfling random index, etc)