PDA

View Full Version : Selecting Randomly from an Array [FPC, Pascal]



DarknessX
01-04-2007, 08:57 PM
Hey, a quick question, how would I go about making my Pascal program select a random item from an array of about 200?

IE,

Item[1] = 'Blue' Weight: 1
Item[2] = 'Red' Weight: 3
Item[3] = 'Yellow' Weight: 2

I want it to weigh each differently, and pick one, any one. 1 means common, 3 means rare.

Without object pascal, preferably... Just plain old pascal. I don't know enough OOP to do anything like this in it, so if you give OOP code please be prepared to help me implement and understand this to every extent..

AthenaOfDelphi
01-04-2007, 09:26 PM
You can do it many many different ways, but heres couple... The first is to break the list up into three seperate lists, then depending on an initial decision, pick an item from the appropriate list.


const
_commonItems = 10;
_rareItems = 5;
_superRareItems = 5;

_chanceOfRare = 40;
_chanceOfSuperRare = 10;

commonItems = array[1.._commonItems] of string = ('common1','common2'....'commonn');
rareItems = array[1.._rareItems] of string = ('rare1'...'raren');
superRareItems = array[1.._superRareItems] of string = ('superrare1'..'superraren');

function pickItem:string;
var
crsr : integer;
begin
crsr:=random(100)+1;

if (crsr>=1) and (crsr {lessthan} =_chanceOfSuperRare) then
result:=superRareItems[random(_superRareItems)+1]
else
if (csrs>_chanceOfSuperRare) and (csrs {lessthan} =_chanceOfSuperRare+_chanceOfRare) then
result:=rareItems[random(_rareItems)+1]
else
result:=commonItems[random(_commonItems)+1];
end;


You could keep them in a single list and do something like this...


const
_items = 100;
_chanceOfRare = 40;
_chanceOfSuperRare = 10;

items : array[1.._items] of string = ('name1','name2'...'namen');
itemsWeight : array[1..items] of integer = (weight1, weight2...weightn);

function pickItem:string;
var
crsr : integer;
itemNo : integer;
begin
crsr:=random(100)+1;

if (crsr>=1) and (crsr {lessthan} =_chanceOfSuperRare) then
crsr:=3
else
if (csrs>_chanceOfSuperRare) and (csrs {lessthan} =_chanceOfSuperRare+_chanceOfRare) then
crsr:=2
else
crsr:=1;

itemNo:=random(_items)+1;

while (itemWeights[itemNo] {does not equal} crsr) do
begin
inc(itemNo);
if (itemNo>_items) then
itemNo:=1;
end;

result:=items[itemNo];
end;


Simply pick which class you want (common, rare, super rare), dive into the list at a random point and return the item of the require class you want. I've not tested any of this code, so I can't guarantee it works, but it should give you a couple of ideas.

Note:- The comments in the code should be replace by the appropriate operator... the symbols break the code parser and ruin the code fragment.

DarknessX
01-04-2007, 10:40 PM
Ok, thanks.
I have a few questions, just to figure things out.


_items = 100;
_chanceOfRare = 40;
_chanceOfSuperRare = 10;


Is there a particular reason for the underscore, aside from to distinguish items from _items?



items : array[1.._items] of string = ('name1','name2'...'namen');
itemsWeight : array[1..items] of integer = (weight1, weight2...weightn);

I take it ('name1','name2'...'namen'); is a list of all possible items in the random selection?
And what exactly does the itemsWeight actually do? I understand that random(100)+1 picks a number randomly from 1-100 (atleast, thats what I think it does...) and then from there... I'm not positive.

However, would something like this work:



Const
_items = 100;
items = Array[1.._items] of String = ('Item1','Item2'...,'Item9');

begin
selection := items[random(_items)+1];
end.



As a very very simple way? I'm going to test this soon, just to see, and I'll post my results after. Thanks for your help, though.

EDIT:

My method comes up with a single answer, every time. In this case, it picks the halfway point and adds one. So I'll keep messing with it, and then I'll post results from there on. Also, the Array has to be under the Var section not the constants section.

Also, both your examples required modifications, the second one I couldn't get working, the first just returned a blank variable.

AthenaOfDelphi
02-04-2007, 12:39 AM
Lets use the second example....

You stated you wanted some items to be rarer than others... so, the second example provides 3 weights... common, rare and super rare if you like.

The first thing we do is pick which of these we will be using... this is done by selecting a random number in the range 0 to 99 (we add 1 to bring it into range). If the number is in the range 1..10, we pick a super rare item (this is a 10% chance)... if its in the range 11..40, we pick a rare item (30% chance) and anything over 41 is common (60% chance).

Once we've done this we have a number 1 for common, 2 for rare and 3 for super rare.

This is where itemWeights comes in. Each entry in the array provides the weight of the corresponding item in the items array. So, we pick a random number in the range 1..Total Number of Items and we jump into the array... we compare the required weight and the actual weight.. if they match, we're done and we return the item.. if not, we move onto the next item.

Thats it.

The reason you're getting a single item is because random numbers generated by software are not random. They are sequential, but the sequence appears random. When your program starts, the random number generator is seeded and every call will pull off a new number in the sequence. You can alleviate this (to a point) by using randomize (or if you can, seed the generator yourself).

DarknessX
03-04-2007, 11:48 PM
Hmmm, Ok. I'm still not sure how to make it work; but I will fool around with it later. I think I understand now HOW it works, but not how to fix it to work in my program :)