non-repeating random numbers
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
02-22-2005 04:44
i am trying to build a list of random numbers without repeating. i got this script working, but it takes too long to shuffle a complete 52 cards list integer rand(float min, float max, integer total) { integer numero = llRound(llFrand(max - min) + min);
integer i;
integer comprimento = llGetListLength(lista); // lista is a global list that stores // all numbers till now
for (i = 0; i < comprimento; i++) { if (numero == llList2Integer(lista, i)) { numero = rand(min, max, total); } } return numero; }
later in the script i call the function in a for cycle to get all cards: integer card = rand(1,53,53); // note that i want 52 cards... lista = lista + card; // global list
feel free to use this script, but is too slow. hope some1 got an improvment. note: the script can fail if "integer total" total is too big
|
Jonathan Shaftoe
... the titleless.
Join date: 11 Feb 2005
Posts: 44
|
02-22-2005 05:01
I'm not surprised it's slow. Consider what it's doing when you have already selected 51 of your cards and only have one left, it's generating a stream of random numbers constantly until finding the one that happens to match the card remaining.
Instead, you want to do something like:
Initialise a list 'cards' with all the possible card values.
To select a card - choose a random number between 0 and the current length of the list 'cards'. Remove the selected card from the list. Return the card.
This will be far more efficient, only requiring one random number to be generated for each card you want to select. To totally shuffle the pack, keep picking cards using this method, adding them to a new list (shuffledCards), until there are no cards left in your original cards list.
Hope that all makes sense.
Jonathan
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
02-22-2005 05:12
yeh u are pointing good to me
it makes sense. i know the slwoing problem was described just the way u did.
so, i will try to implement this ideia.
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
02-22-2005 07:18
Just do this: list cards = ["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"];
list card_names = ["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"]; // Edit the card_names list to whatever you want - "1 of Diamonds", "Queen of Spades," etc.
while(cards != []) { cards = llListRandomize(cards,1); integer card = llList2Integer(cards,0); llWhisper(0,"Your card is: " + llList2String(card_names,card - 1)"); llDeleteSubList(cards,0,0); } The example code will deal every card in the "deck," at a fairly rapid rate, until no cards remain. Assuming I didn't screw up, anyway. 
_____________________
---
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
02-22-2005 07:21
good. didn't tryed it yet. is perfect because the goal is return this string, like Ace of Clubs
oki donki. lets keep working! thx for help
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
02-22-2005 08:48
Also note that your original solution was buggy: inside the loop, you might well have generated a number that you'd already passed by once. Ie, your list is [1,2,3,4], you first generate a 3, then when you get to 3 you generate a 2.. now you've got a duplicate that you didn't detect 
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
final script
02-22-2005 08:50
integer cardCount; float rows; list lista;
Say (string msg) { llInstantMessage(llGetOwner(), msg); }
shufle(float total) { llTriggerSound("NN rattle", 1); list cards = []; integer i; for (i=0;i<total;i++) { cards = cards + i; }
cardCount=0; // this damn cycle could be better! i know... :\ while(cards != []) { if (cardCount<13) { cardCount++; } else { rows = rows + .3; cardCount = 1; } cards = llListRandomize(cards,1); integer card = llList2Integer(cards,0); string suit = getSuit(card); integer cardN = card - (llFloor(card/13)*13)+1; string carta = cardName(cardN) + " of " + suit; cards = llDeleteSubList(cards,0,0); lista = lista + carta; // llRezObject("Back Face", llGetPos() + <-0.2*(cardCount+1)+1, .5+rows, .51>, ZERO_VECTOR, ZERO_ROTATION, 44); // llSay(44, carta); }
}
string getSuit(integer card) { integer naipN = llFloor(card/13); string Naipe; if (naipN == 0) Naipe = "Spades"; else if (naipN == 1) Naipe = "Hearts"; else if (naipN == 2) Naipe = "Clubs"; else if (naipN == 3) Naipe = "Diamonds"; else Naipe = "*JOKER*"; return Naipe; }
string cardName(integer card) { if(card == 1) return "Ace"; if(card == 11) return "Jack"; if(card == 12) return "Queen"; if(card == 13) return "King"; return (string)card; }
string PickACard() { llTriggerSound("NN pop", 1); shufle(54); llWhisper(0, llList2CSV(lista)); return llList2CSV(lista); }
default { state_entry() { }
touch_start(integer total_number) { float startingtime = llGetTime(); llSay(44, "die"); // important for rezed objects cardCount = 0; rows = 0; integer i; string test; lista = []; test = PickACard();
float lifetime = llGetTime()-startingtime; llWhisper( 0, "This script has been running for " + (string)lifetime + " seconds" ); } }
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
02-22-2005 09:15
From: Lex Neva Also note that your original solution was buggy: inside the loop, you might well have generated a number that you'd already passed by once. Ie, your list is [1,2,3,4], you first generate a 3, then when you get to 3 you generate a 2.. now you've got a duplicate that you didn't detect  no, u are wrong. it was looping inside the same function till it was sure that i never duplicate a number before returning it
|
gene Poole
"Foolish humans!"
Join date: 16 Jun 2004
Posts: 324
|
02-22-2005 09:34
Jeffrey's solution looks fine. But I wonder if it isn't just simpler to do this: // original code by Jeffrey Gomez list cards = ["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"];
list card_names = ["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"]; // Edit the card_names list to whatever you want - "1 of Diamonds", "Queen of Spades," etc.
cards = llListRandomize(cards,1); integer i; integer j = llGetListLength(cards); for (i=0; i < j; ++i) { integer card = llList2Integer(cards,i); llWhisper(0,"Your card is: " + llList2String(card_names,card - 1)"); }
If llListRandomize() is properly implemented, it shouldn't be necessary to call it inside the loop. One curiosity: any particular reason why stringed versions of ordinals were used for cards? Note also, if one were to start the count at 0, the "- 1" could be eliminated. 
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
02-22-2005 09:50
Yeah I know. The ordinals as cards are examples - I didn't feel like writing out the card names for him. Started with one as an example, but you're correct, gene. Excuse me laziness. 
_____________________
---
|
gene Poole
"Foolish humans!"
Join date: 16 Jun 2004
Posts: 324
|
02-22-2005 10:06
No worries, Jeffrey, I am the poster child for laziness. 
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
02-22-2005 12:08
list cards = ["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"]; // Edit the cards list to whatever you want - "1 of Diamonds", "Queen of Spades," etc.
integer i; while (i = llGetListLength(cards)) { i = (integer)llFrand(i - 1); llWhisper(0,"Your card is: " + llList2String(cards,i)); cards = llDeleteSubList(cards, i, i); }

_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
02-22-2005 12:32
I give up. That's what I get for throwing that out there at work. 
_____________________
---
|
Richard Pinkerton
Registered User
Join date: 20 Jan 2005
Posts: 125
|
02-22-2005 13:14
The page below has some useful information on shuffle algorithms. Take particular note of random bias. http://www.paradisepoker.com/shuffling.html
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
02-23-2005 09:00
From: nonnux white no, u are wrong. it was looping inside the same function till it was sure that i never duplicate a number before returning it Right... I missed the recursion... but I still think your original algorithm didn't exactly do what you wanted it to do...
|
nonnux white
NN Dez!gns
Join date: 8 Oct 2004
Posts: 90
|
02-23-2005 10:58
From: Lex Neva Right... I missed the recursion... but I still think your original algorithm didn't exactly do what you wanted it to do... i tested it many times, never got any repeated card. also never crashed, but i beleive it could crash, since it produces so many iterations anyway, the solution was using a list, and remove each crad after shufle, and it is done. i am not a expert on scripting, that's why so many things can be done in another way in my solution.
|