其实很简单,就是把每次随机抽取出来的牌存到一个数组里面就好,而这就是FisherYates算法。你如果不同意的话,可以分析一下。我贴一下代码:
void ShuffleArray_Fisher_Yates(char* arr, const int len) { int i = len, j; char temp; if ( i == 0 ) return; while ( --i ) { j = rand() % (i+1); temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }PS:这段代码我第一次是在http://coolshell.cn/articles/8593.html看到的,原帖作者的代码中,数组是字符型的,这个不重要。
void ShuffleArray_General(char* arr, int len) { const int suff_time = len; for(int idx=0; idx<suff_time; idx++) { int i = rand() % len; int j = rand() % len; char temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }这段代码的原理,就是从牌堆里面,随机抽取两张牌交换位置。
#include <stdio.h> #include <time.h> #include <ctype.h> #include <stdlib.h> #define CARDSNUM 10 /* 牌数 */ #define NUMXIPAI 1 /* 洗牌次数 */ #define TONGJINUM 10000000 /* 统计次数 */ #define CARDS cards /* 扑克数组 */ #define TONGJI tongji /* 统计数组 */ #define CARDS_F int CARDS[CARDSNUM] /* 扑克数组定义及函数参数 */ #define TONGJI_F __int64 TONGJI[CARDSNUM][CARDSNUM] /* 统计数组定义及函数参数 */ /* 洗牌函数声明 */ void InitCards(CARDS_F); void ShuffleArray_Fisher_Yates(CARDS_F); void PrintCards(CARDS_F); void Puke(CARDS_F); /* 统计函数声明 */ void InitTongji(TONGJI_F); void Tongjisum(CARDS_F, TONGJI_F); void PrintTongji(TONGJI_F); void Tongji(CARDS_F, TONGJI_F); main() { time_t t; CARDS_F; TONGJI_F; srand(time(&t)); // Puke(CARDS); // PrintCards(CARDS); Tongji(CARDS, TONGJI); PrintTongji(TONGJI); return 0; } void InitCards(CARDS_F) /*码牌 扑克数组初始化 */ { int i; for(i = 0; i < CARDSNUM; i++) { CARDS[i] = i+1; } } void ShuffleArray_Fisher_Yates(CARDS_F) /* Fisher_Yates算法 */ { int i, j, k; for(i = CARDSNUM; i > 0; i--) { j = (rand()%(i)); k = CARDS[i-1]; CARDS[i-1] = CARDS[j]; CARDS[j] = k; } } void PrintCards(CARDS_F) /* 输出牌 */ { int j; printf("\nYour Cards Is: "); for(j = 0; j < CARDSNUM; j++) { if(!(j%10)) { printf("\n"); } printf("%d ", CARDS[j]); } } void Puke(CARDS_F) /* 洗牌 */ { int i; InitCards(CARDS); for(i = 1; i <= NUMXIPAI; i++) { ShuffleArray_Fisher_Yates(CARDS); } } void InitTongji(TONGJI_F) /* 统计数组初始化 */ { int j, k; for(j = 0; j < CARDSNUM; j++) { for(k = 0; k < CARDSNUM; k++) { TONGJI[j][k] = 0; } } } void Tongjisum(CARDS_F, TONGJI_F) /* 统计扑克牌的出现位置 */ { int j, k; Puke(CARDS); for(j = 0; j < CARDSNUM; j++) { k = CARDS[j]; TONGJI[j][k-1] += 1; } } void PrintTongji(TONGJI_F) /* 输出统计结果 */ { int i, j; printf("\nTongji Result Is: \n"); for(i = 0; i < CARDSNUM; i++) { for(j = 0; j < CARDSNUM; j++) { printf("%d ", TONGJI[i][j]); } printf("\n"); } } void Tongji(CARDS_F, TONGJI_F) /* 扑克牌的概率统计 */ { __int64 i; InitTongji(TONGJI); for(i = 0; i < TONGJINUM; i++) { Tongjisum(CARDS, TONGJI); } }需要说明的是,我默认用了10个数字测试,测试次数是1千万次。对于洗牌次数,我最初认为洗牌算法开始的时候是按照顺序洗牌的,那么我们可以把已经洗好的牌在用算法洗一次,效果不应该更好吗。但是从测试结果看来,其实没有多大改变,也就是说没有必要反复洗牌。
/* filename: 21game.cpp This program plays a game of Blackjack with you. */ /******************************************************** ANSI C standard header files appear next */ #include <stdio.h> #include <time.h> #include <ctype.h> #include <stdlib.h> /******************************************************** Defined constants appear next */ #define BELL '\a' #define DEALER 0 #define PLAYER 1 /* Must keep two sets of totals for dealer and for player. The first set counts Aces as 1 and the second counts Aces as 11.Unlike "real world" Blackjeck,this program doesn't allow some Aces to be 1 while others Aces are 11 in the same hand. */ #define ACELOW 0 #define ACEHIGH 1 /* Only one global variable is used in this entire program. The variable holds 0,which means fales initially. Once the user enters his or her name in initCardsScreen(), this variable is set to 1 (for true), so the name is never asked for again the rest of the progame. */ int askedForName = 0; /* False initially*/ /********************************************************* This progame's specific prototypes */ void dispTitle(void); void initCardsScreen(int cards[52], int playerpoints[2], int dealerPoints[2], int total[2], int * numCards); int dealCard(int * numCards, int cards[52]); void dispCard(int cardDrawn, int points[2]); void totalIt(int points[2], int total[2], int who); void dealerGetsCard(int * numCards, int cards[52], int dealerPoints[2]); void playerGetsCard(int * numCards, int cards[52], int playerPoints[2]); char getAns(char mesg[]); void findWinner(int total[2]); /********************************************************* C's program execution always begins at main() here */ main() { int numCards; /* Equals 52 at beginning of each game */ int cards[52], playerPoints[2], dealerPoints[2], total[2]; char ans; /* For user's Hit/Stand or Yes/No pesponse */ do { initCardsScreen(cards, playerPoints, dealerPoints, total, &numCards); dealerGetsCard(&numCards, cards, dealerPoints); printf("\n"); /*Prints a blank line*/ playerGetsCard(&numCards, cards, playerPoints); playerGetsCard(&numCards, cards, playerPoints); do { ans = getAns("Hit or stand (H/S)?"); if (ans == 'H') { playerGetsCard(&numCards, cards, playerPoints); } } while (ans != 'S'); totalIt(playerPoints, total, PLAYER); /* Player's total */ do { dealerGetsCard(&numCards, cards, dealerPoints); } while (dealerPoints[ACEHIGH] < 17); /* 17: Dealer stops */ totalIt(dealerPoints, total, DEALER); /* Dealer's total */ findWinner(total); ans = getAns("\nPlay again (Y/N)? "); } while (ans == 'Y'); return 0; } /*************************************************************** This function initializes the face values of the deck of cards by putting four sets of 1-13 in the 52-card array .Also clears the screen and displays a title. */ void initCardsScreen(int cards[52], int playerPoints[2], int dealerPoints[2], int total[2], int * numCards ) { int sub , val = 1; /* This function's Work variables */ char firstName[15]; /* Holds user's first name */ *numCards = 52; /* Holds running total of number of cards */ for (sub = 0; sub <= 51; sub++) /* Counts from 0 to 51 */ { val = (val == 14) ? 1 : val; /* If val is 14,resets to 1 */ cards[sub] = val; val++; } for(sub = 0; sub <= 1; sub++) /* Counts from 0 to 1 */ { playerPoints[sub] = dealerPoints[sub] = total[sub] = 0; } dispTitle(); if (askedForName == 0) /* Name asked for only once */ { printf("\nWhat is your first name? "); scanf(" %s", firstName); askedForName = 1; /* Don't ask prompt again */ printf("Ok, %s, get ready for casino action!\n\n", firstName); getchar(); /* Discards newline. You can safely */ } /* ignore comliler warning here. */ return; } /********************************************************* This function gets a card for the player and updates the player's points. */ void playerGetsCard(int *numCards, int cards[52], int playerPoints[2]) { int newCard; newCard = dealCard(numCards, cards); printf("You draw: "); dispCard(newCard, playerPoints); } /*********************************************************** This function gets a card for the dealer and updates the dealer's points. */ void dealerGetsCard(int *numCards, int cards[52], int dealerPoints[2]) { int newCard; newCard = dealCard(numCards, cards); printf("The dealer draws: "); dispCard(newCard, dealerPoints); } /***************************************************** This function gets a card from the deck and stores it in either the dealer's or the player's hold of cards. */ int dealCard(int * numCards, int cards[52]) { int cardDrawn, subDraw; time_t t; /* Gets for a random value */ srand(time(&t)); /* Seeds random-number generator */ subDraw = (rand()%(*numCards)); /* From 0 to numCards */ cardDrawn = cards[subDraw]; cards[subDraw] = cards[*numCards - 1]; /* Puts top card */ (*numCards)--; /* in place of drawn one */ return cardDrawn; } /******************************************************** Displays the last-drawn card and updates points with it. */ void dispCard(int cardDrawn, int points[2]) { switch (cardDrawn) { case(11): printf("%s\n", "Jack"); points[ACELOW] += 10; points[ACEHIGH] += 10; break; case(12): printf("%s\n", "Queen"); points[ACELOW] += 10; points[ACEHIGH] += 10; break; case(13): printf("%s\n", "King"); points[ACELOW] += 10; points[ACEHIGH] += 10; break; default: points[ACELOW] += cardDrawn; if (cardDrawn ==1) { printf("%s\n", "Ace"); points[ACEHIGH] += 11; } else { points[ACEHIGH] += cardDrawn; printf("%d\n", cardDrawn); } } return; } /************************************************************** Figurs the total for player or dealer to see who won. This function takes into account the face that Ace is either 1 or 11. */ void totalIt(int points[2], int total[2], int who) { /* The following routine first looks to see if the total points counting Aces as 1 is equal to the total points counting Aces as 11. If so, or if the total points counting Aces as 11 is more than 21, the program uses the total with Aces as 1 only. */ if ((points[ACELOW] == points[ACEHIGH]) || (points[ACEHIGH] > 21)) { total[who] = points[ACELOW]; /* Keep all Aces as 1 */ } else { total[who] = points[ACEHIGH]; /* Keeps all Aces as 11 */ } if (who == PLAYER) /* Determines the message printed */ { printf("You have a total of %d\n\n", total[PLAYER]); } else { printf("The house stands with a total of %d\n\n", total[DEALER]); } return; } /*********************************************************** Prints the winning player. */ void findWinner(int total[2]) { if (total[DEALER] == 21) { printf("The house wins.\n"); return; } if ((total[DEALER] > 21) && (total[PLAYER] > 21)) { printf("%s", "Nobody wins.\n"); return; } if ((total[DEALER] >= total[PLAYER]) && (total[DEALER] < 21)) { printf("The house wins.\n"); return; } if ((total[PLAYER] > 21) && (total[DEALER] < 21)) { printf("The house wins.\n"); return; } printf("%s%c", "You win!", BELL); return; } /************************************************************** Gets the user's uppercase, single-character response. */ char getAns(char mesg[]) { char ans; printf("%s", mesg); /* Prints the prompt message passed */ ans = getchar(); getchar(); /* Discards newline. You can safely ignore */ return toupper(ans); /* compiler warning here. */ } /************************************************************ Clears everything off the screen. */ void dispTitle(void) { int i = 0; while (i < 25) /* Clears screen by printing 25 blank */ { /* lines to "push off" stuff that */ printf("\n"); /* might be left over on the screen */ i++; /* before this program */ } printf("\n\n*Step right up to the Blackjack tables*\n\n"); return; }