Thanks in advance for your help.
void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key+ j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0,0xffffffff]-interval */
unsigned long genrand_int32(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
Quote: AhighYou need to fix when code converts subscripts to arrays with an index of i to an italic BBcode.
An autographed free copy of my book if you just do it for me...please.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
The README for that version is here:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/readme-mt.txt
It says, in part:
Quote:init_genrand(seed) initializes the state vector by using
one unsigned 32-bit integer "seed", which may be zero.
init_by_array(init_key, key_length) initializes the state vector
by using an array init_key[] of unsigned 32-bit integers
of length key_kength. If key_length is smaller than 624,
then each array of 32-bit integers gives distinct initial
state vector. This is useful if you want a larger seed space
than 32-bit word.
So either call init_genrand() with a 32-bit uint, or call init_by_array() with an array of up to 624 32-bit uints. (More than 624 will get ignored.)
And the entire website is here:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/eversions.html
Quote: WizardThanks! I am not that picky. Would it suffice to seed to capture the time at the start of the program, and keep reseeding with that same time?
System time in milliseconds is often used for a seed, but why reseed often? The period of the MT is 2^19937-1...
Read the paper if you have the interest:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/earticles.html
Quote: MathExtremistSystem time in milliseconds is often used for a seed, but why reseed often? The period of the MT is 2^19937-1...
Thanks! That occurred to me after I posted. That paper was a bit over my head.
Quote: WizardThanks! That occurred to me after I posted. That paper was a bit over my head.
Shuffling that starts from a randomly selected previously shuffled deck in a library instead of a fresh deck also helps to ensure randomness without burning too many clocks.
The library can be continuously updated as you create new decks so that no starting deck is used more than once.
The library can also be quite large and use permanent storage between runs as the storage space needed per deck is quite small.
I believe, though, if you have a good enough random number generator, the simplest shuffle is:
for( i=0; i<ncards; i++ )
{
random_card = unshuffled_deck( random_index( ncards - i ) );
shuffled_deck += random_card;
unshuffled_deck -= random_card;
}
Starting with a randomly created shuffled deck from a big library of shuffled decks doesn't hurt. But I don't think you need to take much time to shuffle if you do it right.
All the time should be in the random number generator IMO.
This will generate a random integer between 0 and 99999999. The random bits come from atmospheric noise, which is better than any PRNG. Read more at the homepage of random.org.
Now, you will have to code an HTTP client into your C++ to utilize this source, which might (will) suck. For best results, stop using C++.
Anyway, unless you were looking at the Mersenne Twister as as academic exercise, then carry on :).
Quote: AhighI believe, though, if you have a good enough random number generator, the simplest shuffle is:
for( i=0; i<ncards; i++ )
{
random_card = unshuffled_deck( random_index( ncards - i ) );
shuffled_deck += random_card;
unshuffled_deck -= random_card;
}
I'm not saying this is optimal or unbiased, but I run through the deck hundreds of times swapping the cards in two random positions.
Quote: AcesAndEightsThe random bits come from atmospheric noise, which is better than any PRNG. Read more at the homepage of random.org.
I it would take me ages to figure out how to grab the numbers from that web site into my program. My own Mersenne Twister has passed every test of randomness I've thrown at it.
Such as - take 2 stacks of a random number of cards between 20 and 32 each off the top of an 8 deck shoe, then alternate 1-4 cards from each stack into a new stack (for a riffle)
Not that it is any better or worse than what you are doing anyway, but I wonder what some of these RNG doubters would say about it.
Quote: wudgedHave you ever tried writing something to simulate an actual shuffle?
A long time ago I did try to mimic an actual shuffle. However, I think swapping two random cards is less biased and much easier to code.
Quote: WizardI'm not saying this is optimal or unbiased, but I run through the deck hundreds of times swapping the cards in two random positions.
You need to shuffle each card at least once, IMO. How many swaps between two random cards are required to make sure each card gets shuffled?
With your method, you need more swaps than the number of cards in a deck. But unless you provide an explanation for how many are required, I think there's an underlying assumption that you are doing "enough."
My method provides randomness for each card in the new deck that is 100% random and performs a minimal number of steps.
Quote: AhighYou need to shuffle each card at least once, IMO. How many swaps between two random cards are required to make sure each card gets shuffled?
No number will guarantee every card gets touched. However, if you do 416 swaps, for example, every card should get swapped twice on average. About 13.5% of cards still won't get swapped. However, that doesn't contaminate the shoe. In baccarat, it is groups of cards that count. If I were programming this for real money wagers I would do a lot more swaps, to avoid player's detecting and exploiting anything. However, for my purposes, I think this technique is sufficient.
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
You only need to pass once through the deck, swapping two cards at a time to end up with a random shuffle. It also does it in place, which is memory efficient, if such a thing matters. The trick is to avoid the newbie mistake and end up with a cyclic shuffle (Sattolo's algorithm).
Quote: WizardNo number will guarantee every card gets touched. However, if you do 416 swaps, for example, every card should get swapped twice on average. About 13.5% of cards still won't get swapped. However, that doesn't contaminate the shoe. In baccarat, it is groups of cards that count. If I were programming this for real money wagers I would do a lot more swaps, to avoid player's detecting and exploiting anything. However, for my purposes, I think this technique is sufficient.
I'm surprised with your explanation of "good enough" compared to what I would consider a complete shuffle with no hint of patterns except possibly patterns in the random number generator itself.
Quote: thecesspitAHigh, see :
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
You only need to pass once through the deck, swapping two cards at a time to end up with a random shuffle. It also does it in place, which is memory efficient, if such a thing matters. The trick is to avoid the newbie mistake and end up with a cyclic shuffle (Sattolo's algorithm).
I think efficiency always matters. Both memory and CPU. You just want to get the job done as efficiently as possible providing that it is done properly.
Swapping two random indices just seems wrong to me intuitively.
I only read briefly the wiki entry, but it appears that it also step incrementally through one index swapping with another random index.
I am not an expert here, though, nor am I research on shuffle algorithms. I would trust Knuth on the subject, for sure.
You would end up with as many shuffles as you have seeds with my algorithm, which is why you want to start with a random result from a library. So maybe you have two seeds to prevent someone from reverse engineering your process. One to look up which shuffled deck to start with, and another to use for the shuffle process, and initialize those two using some external random number generator (EG: from atmospheric data or from a natural random number in the real world). But there's no need to burn CPU to get random results is my thinking.
Quote: AhighI think efficiency always matters. Both memory and CPU. You just want to get the job done as efficiently as possible providing that it is done properly.
Swapping two random indices just seems wrong to me intuitively.
Fisher-Yates avoids any correlation between the start and end deck, for sure. Swapping two items in place also seems less effective to me, as the number of swaps is also less in a F-Y than in a random swap.
It's a bit like the various sort algorithms you can use... though the answer is clearer here.
Quote:I only read briefly the wiki entry, but it appears that it also step incrementally through one index swapping with another random index.
Pretty much, but you can do it in place as well.
Quote:I am not an expert here, though, nor am I research on shuffle algorithms. I would trust Knuth on the subject, for sure.
I've seen at least one implementation of F-Y that was actually cyclic, which caused bias in the model.
My question is, does the computer do this anyway? For example, if you want the 123rd element in a full array, can the computer jump right to that position, or does it start at the beginning and take 122 more steps until it gets to the element requested?
To phrase it yet another way, when you declare an array, are the locations in the computer's memory sequential, or do they jump around? Dealing with pointers, I would tend to think they are sequential, but I don't trust myself to be right on that one.
Originally the memory was stored sequentially as you suggest, and that's why arrays are traditionally 0 based.
The array variable would be a pointer to the memory location of the first element, and then there would be a memory offset from that address based on the index of the array you wanted. The first element is located 0 bytes away from the address pointer. For the nth element, it is located n * (1, 2, 4, 8, 16, 32, whatever - depends on the data type of the elements in the array) bytes away from the address pointer.
Quote: WizardI it would take me ages to figure out how to grab the numbers from that web site into my program. My own Mersenne Twister has passed every test of randomness I've thrown at it.
Here's a C++ library already written for you. I understand if you want to stick to your Mersenne code - but as a programmer the availability of truly random data from the environment is really "cool."
Quote: WizardThis is a little off topic, but speaks to the topic of finding the n-th element in an array with lots of gaps in it. For example, I have an array of 416 cards, but half the positions are blank, and I want to grab the 123rd non-blank position. It would be easy to code, but time consuming for the computer, to parse through the array, counting the cards.
My question is, does the computer do this anyway? For example, if you want the 123rd element in a full array, can the computer jump right to that position, or does it start at the beginning and take 122 more steps until it gets to the element requested?
To phrase it yet another way, when you declare an array, are the locations in the computer's memory sequential, or do they jump around? Dealing with pointers, I would tend to think they are sequential, but I don't trust myself to be right on that one.
Now you're speaking my language!
This question has to do with how the computer physically accesses memory locations. With an array, the data is stored as a block of contiguous memory. Accessing the Nth element is constant-time, meaning the processor doesn't have to iterate over all of the elements to get to the Nth. This is because internally, the reference to the array is stored as a memory location. When you ask for the Nth item in the array, the processor adds N*(sizeof(int)) to that memory location to get the data.
Technically this is dependent on the language's implementation of an array, but I know it's true for C and C++. And it should be true of most languages, as far as I know.
EDIT: Wudged beat me to it, and is correct. If you're using a library, all bets are off and it's implementation-specific. But for a primitive array, both of our explanations are correct.
Quote: WizardTo phrase it yet another way, when you declare an array, are the locations in the computer's memory sequential, or do they jump around? Dealing with pointers, I would tend to think they are sequential, but I don't trust myself to be right on that one.
I am guessing you are talking C++ in which case yes, they are sequential. You can take the address of the array and use that pointer as expected.
On the shuffling topic you should just use Fisher-Yates there is a correct implementation on Wikipedia. The same article talks about the need to avoid modulo bias when scaling random numbers. I seem to recall an early online poker site made this mistake resulting in biased shuffles. The common method to fix this is to treat the output of the RNG as a bitstream, grab the minimum number of bits that can express your desired maximum, and then throw away samples that are out of range.
Quote: IbeatyouracesAll this for the silly bac trenders?
The trail is more interesting than the destination.
void fisher_yates(int deck[], int NumCards)
{
int i,j,NewDeck[416];
unsigned int rn;
for (i=0; i<NumCards; i++)
{
rn=genrand_int32()%(NumCards-i);
NewDeck[i]=deck[rn];
for (j=rn; j<NumCards-1; j++)
deck[j]=deck[j+1];
}
for (i=0; i<NumCards; i++)
deck[i]=NewDeck[i];
}
Quote: WizardDo the advanced programmers on the forum approve of this Fisher-Yates shuffle I just wrote:
void fisher_yates(int deck[], int NumCards)
{
int i,j,NewDeck[416];
unsigned int rn;
for (i=0; i<NumCards; i++)
{
rn=genrand_int32()%(NumCards-i);
NewDeck[i]=deck[rn];
for (j=rn; j<NumCards-1; j++)
deck[j]=deck[j+1];
}
for (i=0; i<NumCards; i++)
deck[i]=NewDeck[i];
}
It's slightly biased.
Quiz: why?
Quote: TheCesspitThe trick is to avoid the newbie mistake and end up with a cyclic shuffle (Sattolo's algorithm).
No possibility of selecting the current card to replace itself.
I think....
However, I don't have my own answer, yet.
Quote: IbeatyouracesAll this for the silly bac trenders?
That is why I asked for the donation to charity, which it looks like I'm not going to get.
Quote: WizardDo the advanced programmers on the forum approve of this Fisher-Yates shuffle I just wrote. As you can see, after it pulls out the card in the rn-th place in the old deck it slides everything after it one position, to keep the old deck sequential and without gaps.
void fisher_yates(int deck[], int NumCards)
{
int i,j,NewDeck[416];
unsigned int rn;
for (i=0; i<NumCards; i++)
{
rn=genrand_int32()%(NumCards-i);
NewDeck[i]=deck[rn];
for (j=rn; j<NumCards-1; j++)
deck[j]=deck[j+1];
}
for (i=0; i<NumCards; i++)
deck[i]=NewDeck[i];
}
It's been a while since I've used C++, but can't you initialize the NewDeck array using NumCards instead of 416? Algorithm looks correct with the exception of the bias ME pointed out.
Quote: WizardI disagree. If the first random number is 0, the first card in the shuffled deck will be the first card from the original deck.
Apologies, I agree with your disagreement now, misread the code.
I'm not sure you need the shuffle down though, as you can do the whole think in place, and that avoids copying the shuffled deck back into the new Deck as well. But there might be reasons to keep both old and new.
Swap Position [0] with a random card from [0-n]. The swap Position [1] with a random card from 1-n, and repeat.
1) The for() loop has one iteration too many; it is better to count down from (NumCards - 1) to 1
2) The process of obtaining a random number may result in a bias because 232 % NumCards may not necessarily be zero
3) There is no need for an extra array to hold the shuffled cards; they are shuffled in place with Fisher-Yates
The following code should implement it correctly:
void fisher_yates(int deck[], int NumCards)
{
int i, r, t;
for (i = NumCards - 1; i > 0; i--)
{
do
{
r = genrand_int32();
}
while ((r < 0) || (r >= i));
t = deck[r];
deck[r] = deck[i];
deck[i] = t;
}
}
The do() loop obtains random integers repeatedly until an integer in the needed range is found. Then the card in that random position is swapped with the card in position i.
Quote: wudgedIt's been a while since I've used C++, but can't you initialize the NewDeck array using NumCards instead of 416?
Visual Studio doesn't let you. I tried. Seems that it should. I just know I'm going to get an array error when I use this code later for a bigger array.
Thanks JB for your comments. The only thing I have a hard time with is waiting for the random number to be in the desired range. That could take a while, as they are drawn from 0 to 2^32-1. I know computer are fast these days, but I can remember the punch card days.
Given this large cycle, I think taking the mod of a number as big as 4,294,967,295, would result in a very negligible bias. Perhaps that is the answer to ME's question.
Here is my new and improved code, per your other suggestions.
void fisher_yates(int deck[], int NumCards)
{
int i,j,random_card;
unsigned int rn;
for (i=NumCards-1; i>=0; i--)
{
rn=genrand_int32()%(i+1);
random_card=deck[rn];
for (j=rn; j<i-1; j++)
deck[j]=deck[j+1];
deck[i]=random_card;
}
}
Quote: WizardVisual Studio doesn't let you. I tried. Seems that it should. I just know I'm going to get an array error when I use this code later for a bigger array.
To define a variable-sized array you have to use a pointer and the new keyword. With a constant size array the compiler allocates that much space statically on the stack, but for a variable sized array you have to allocate memory on the heap. In C you would use malloc() which is what I was going to suggest, but I think in C++ you just use new.
reference.
void fisher_yates(int deck[], int NumCards)
{
int i,j,random_card, max;
unsigned int rn;
for (i=NumCards-1; i>0; i--)
{
max = floor(4294967295 / (i + 1)) * (i + 1);
do
{
rn = genrand_int32();
}
while ((rn < 0) || (rn >= max));
rn = rn % (i + 1);
random_card=deck[rn];
deck[rn] = deck;
deck = random_card;
}
}
This will strip off only the bias part and not spend "hours" trying to find a valid random number that avoids the bias.
(Edited to change the modulo to integer division when assigning the value to max)
Quote: WizardThanks JB for your comments. The only thing I have a hard time with is waiting for the random number to be in the desired range. That could take a while, as they are drawn from 0 to 2^32-1. I know computer are fast these days, but I can remember the punch card days.
I also have a problem with it...
Quote: WizardGiven this large cycle, I think taking the mod of a number as big as 4,294,967,295, would result in a very negligible bias. Perhaps that is the answer to ME's question.
A better solution would be to generate only one random number per iteration; cast it to a double; divide it by 4294967296; multiply it by i; then cast it back to an int and put it in random_card.
Quote: WizardHere is my new and improved code, per your other suggestions.
In the for loop initializer, the middle condition should be i > 0 (not i >= 0). Also, moving cards about the array is unnecessary and slows down the function. Just swap the array values located in positions i and random_card.
Here's a great article about shuffling algorithms which illustrates bias using a 3-card deck:
http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html
Quote: wudged
max = floor(4294967295 % (i + 1)) * (i + 1);
do
{
rn = genrand_int32();
}
while ((rn < 0) || (rn >= max));
This will strip off only the bias part and not spend "hours" trying to find a valid random number that avoids the bias
Yes, except that needs to be the integer-division operation, not the modulo operation.
max = floor(MAX_INT / (i + 1)) * (i + 1);
also, for clarity I'd either change the variable name to "toobig" or subtract 1 in the above formula and change the test to rn > max (strictly greater than).
The slight bias in the original code comes from doing a modulo operation on a range that does not evenly divide by the scaling range. The same bias is easier to see (and much larger) if you consider trying to use a 3-bit RNG to generate numbers between 0 and 2 inclusive. You want p(0) = p(1) = p(2) = 1/3, but without trimming the excess off the RNG range you end up with:
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
7 % 3 = 1
p(0) = p(1) = 3/8, while p(2) = 2/8. Whoops. The solution is to discard any RNG outcomes at the upper end of the range, in this case discarding 6 or 7, so then each outcome occurs with p=2/6.
Quote: JBIn the for loop initializer, the middle condition should be i > 0 (not i >= 0). Also, moving cards about the array is unnecessary and slows down the function. Just swap the array values located in positions i and random_card.
You're right, that does seem to work just as well, and I don't have to bother with the card slide. Thank you.
However, I think worrying about the bias over taking the mod of 232 is rather ridiculous for practical purposes. I'm not saying discussion about it isn't worthy, but I don't want to slow down the program over it.
I'd compare this to a video poker player memorizing an exception that increases the return by 0.000000001.
Anyway, here is version 4, I think, of my shuffle.
void fisher_yates(int deck[], int NumCards)
{
int i,hold;
unsigned int rn;
for (i=NumCards-1; i>0; i--)
{
rn=genrand_int32()%(i+1);
hold=deck[rn];
deck[rn]=deck[i];
deck[i]=hold;
}
}
Quote: WizardYou're right, that does seem to work just as well, and I don't have to bother with the card slide. Thank you.
However, I think worrying about the bias over taking the mod of 232 is rather ridiculous for practical purposes. I'm not saying discussion about it isn't worthy, but I don't want to slow down the program over it.
The slowdown would be minimal since you'd only need to redraw once every 16.8M tries. And it's fine for your personal code, but consider:
Quote: GLI Standard #11, 3.3.10 Scaling Algorithmsa) If a random number with a range shorter than that provided by the RNG is required for some purpose within the gaming device, the method of re-scaling, (i.e., converting the number to the lower range), is to be designed in such a way that all numbers within the lower range are equally probable.
b) If a particular random number selected is outside the range of equal distribution of re-scaling values, it is permissible to discard that random number and select the next in sequence for the purpose of re-scaling.
subitem (b) is exactly what we're talking about.
Quote: MathExtremistThe slowdown would be minimal since you'd only need to redraw once every 16.8M tries.
Yes, but you have to check if it is in the range EVERY time. When I do a simulation I try to get in as many billions of trials as I can, and this will just slow it down. I think the accuracy from extra trials is worth more than the microscopic bias in excess mod cycle.
Quote:subitem (b) is exactly what we're talking about.
Nice point! However, I'm not drawing a random number that is going to determine a real money outcome of a bet, but a simulation of something with billions of trials. I will keep that in mind, however, if I ever do write some code that might make it into a real money game.
Quote: WizardHowever, I'm not drawing a random number that is going to determine a real money outcome of a bet, but a simulation of something with billions of trials
Okay, but if throughput is the goal then there are other ways of generating a few new decks without using a new random shuffle each time. You could, for example, alternate between a new shuffle and a deck-reversal -- just reverse the array and re-run the shoe analysis. You'd have half the RNG calls. And then you could do a single-pass riffle-shuffle, reversing one-half of the array before interleaving. Run with that shoe, and then reverse *that* and run a 4th time. That gets you 25% of the RNG calls over time, with just deterministic array manipulations in the interim.
Assume that to generate a new deck you need 51 calls to RNG which creates [1-52],[1-51]....[1-2] for the first deck. Eventually after a number of decks you would have created a really random series of numbers. A51..A02 B51..B02 etc. Now you could generate a fixed algorithm to use (say) A51 B50 C49 etc for your next shuffle and so reuse the numbers in some predetermined (or time based) but non-obvious way.
I hope I did this right, its been 38 years. Nonetheless, this has been done with string arrays (useful in single-deck), AND
can be parsed by name ("As" = Ace of Spades) to image name ("As"=As.gif). Modern laguages do that, not this old stuff... lol.
Example using 416 cards in old-fashioned IBM-BASIC
INTEGER: REM declared all variables are integers DIM is not called to make the array dynamic
RANDOM: REM Pick the initial seed
For n = 416 to 2 step -1: REM decrement the random list by 1 each next
i = RND(n): REM will pick RND's of smaller range each pass
c(417-n)=d(i): REM position the the RND card in sequence
d(i)=0: zeroes the pick
d(n)=d(1 to i-1)&d(i+1 to )&d(i): REM decrement the RND choices as not i, maintain length of 416, ineligible picks=0
next n
c(416)=d(1): REM place the remaining card as last card in deck c
REM to shuffle these cards in c just let c(x)=d(x) and repeat from RAMDOM statement
Interesting to note that RANDOM can be called previously to determine the number of shuffles (say 1 to 9) somewhat randomly.
This was editted.
BTW, why can't I see a way to delete a post?
Quote: DRichBTW, why can't I see a way to delete a post?
You need to be an admin to do that.
Quote: DRichnevermind, this was already said.
BTW, why can't I see a way to delete a post?
Just EDIT it, and remove all of your text.......
Quote: RaleighCrapsJust EDIT it, and remove all of your text.......
Speaking of editing, Raleigh, I really needed to see this part of your signoff this morning...thanks!
"Be yourself and speak your thoughts. Those who matter won't mind, and those that mind, don't matter!"