#include
#include
#include
int
d[6];
int
i,n,a,b,t;
int
c,j;
void
main() {
srand
(
time
(NULL));
printf
(
"shuffle 0..n-1 demo\n"
);
for
(n=1;n<=5;n++) {
/* 测试1~5个元素 */
printf
(
"_____n=%d_____\n"
,n);
j=1;
for
(c=1;c<=n;c++) j=j*c;
/* j为n! */
j*=n*2;
for
(c=1;c<=j;c++) {
/* 测试n*2*n!次 */
for
(i=0;i
/* 填写0~n-1 */
for
(i=n;i>0;i--) {
/* 打乱0~n-1 */
a=i-1;b=
rand
()%i;
if
(a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
}
printf
(
"%04d:"
,c);
for
(i=0;i
printf
(
"%d"
,d[i]);
printf
(
"\n"
);
}
}
printf
(
"shuffle 1..n demo\n"
);
for
(n=1;n<=5;n++) {
/* 测试1~5个元素 */
printf
(
"_____n=%d_____\n"
,n);
j=1;
for
(c=1;c<=n;c++) j=j*c;
/* j为n! */
j*=n*2;
for
(c=1;c<=j;c++) {
/* 测试n*2*n!次 */
for
(i=1;i<=n;i++) d[i]=i;
/* 填写1~n */
for
(i=n;i>1;i--) {
/* 打乱1~n */
a=i;b=
rand
()%i+1;
if
(a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
}
printf
(
"%04d:"
,c);
for
(i=1;i<=n;i++)
printf
(
"%d"
,d[i]);
printf
(
"\n"
);
}
}
}
洗牌的算法有很多,这里主要介绍下几种主要的算法。
方法一:每次找一个随机的位置,然后将这54个数放到找的位置中。
步骤:1.用一个整型数组记录各个位置是否已经放置了数,如果放置了则不为0,否则为0。所以在算法开始的时候,初始化此数组每个元素的值都为0.
2.每次产生一个0-53之间的数,看这个位置是否放置了数,如果已经放置了,则继续采用同样的方法找一个随机的位置进行判断,如果这个位置还未放置,则设置此位置。
3.反复执行步骤2,直到所有的位置都放好了数。
代码实现如下:
1 void shuffle(int *dest,int N) 2 { 3 int pos,card; 4 for (card=1;card<=N;card++) 5 { 6 do 7 { 8 pos=rand()%(N-1); 9 } while (dest[pos]!=0); 10 11 dest[pos]=card; 12 } 13 } 14 15 void main() 16 { 17 int dest[54]={0}; 18 shuffle(dest,54); 19 for (int i=0;i<54;i++) 20 { 21 cout<" "; 22 } 23 }
此方法有个缺点就是很耗时间,因为随着空位置越来越少,寻找会越来越困难。
方法二:就是先对数组进行初始化,然后随机交换数组中任意两个元素。交换的次数越多就越随机。此方法也很简单,而且时间复杂度也比较低,计算量也不大。
代码实现如下:
1 void shuffle ( int a[], int n ) 2 { 3 int tmp = 0, p1, p2; 4 int cnt = rand() % 1023; 5 while (cnt--) 6 { 7 p1 = rand() % n; 8 p2 = rand() % n; 9 tmp = a[p1]; 10 a[p1] = a[p2]; 11 a[p2] = tmp; 12 } 13 }
方法三:它的基本思想是初始化一个vector,顺序加入所有牌,即1-54个数,然后从这个vector中随机抽取一个到另一个vector中,将这个过程执行54次即可完成。
代码的实现如下:
1 void vectorShuffle(vector<int> &unshuffle,vector<int> &shuffled) 2 { 3 unsigned int temp,len=unshuffle.size(); 4 while(len) 5 { 6 temp=rand()%(len--); 7 shuffled.push_back(unshuffle[temp]); 8 unshuffle.erase(unshuffle.begin()+temp); 9 } 10 } 11 12 13 void main() 14 { 15 vector<int> uncard,carded; 16 for (int i=0;i<54;i++) 17 { 18 uncard.push_back(i+1); 19 } 20 vectorShuffle(uncard,carded); 21 for (int j=0;j<54;j++) 22 { 23 cout<" "; 24 } 25 }
PS:STL中也有一个封装好了的洗牌算法-random_shuffle。使用方法:如果定义有 vector
[code=html]
本程序实现了一般扑克牌游戏的洗牌、发牌和理牌过程,程序模拟了对四个玩家的发牌,且能让各自玩家按大小顺序整理自己的手牌。牌的大小顺序按斗地主的规则(但无大小王)。
本程序定义了一个牌的结构体,其成员变量是两个字符指针。一个指向点数的字符数组,另一个指向花色的字符数组。考虑到牌的整理需要比较两张牌的大小,而字符不太好比较,从而构造了一个辅助函数Value来实现将字符转换为整数。程序得最后还对桌牌和手牌进行了检测,看是否有重复的牌。
算法说明:
发牌算法
Void Deal(CARD *Deck,CARD (*player)[13]){
for (i = 0;i < 4; i++){
// 遍历四个玩家
for (j = 0;j < 13; j++){
// 洗牌第i个玩家的第j张牌是手牌中的第4*j+i张(轮流发牌)
player[i][j] = Deck[4*j+i];
}
}
}
排序算法
void InsertSort ( CARD *R) { // 对某一玩家R作直接插入排序,有13张牌
for ( i=1; i
for ( j=i-1; j>=0; --j )
if(Value(R[j].face)
? Value(R[j].suit) < Value(temp.suit) ? 1 : 0 : 0) break;
for (k = j-1; k > j;k--)
R[j+1] = R[j]; // 记录后移
R[k+1] = temp; // 插入到正确位置
}
} // InsertSort
测试算法
测试桌牌和手牌是否有重复的牌。其思想是从第一张开始与后面的牌一次比较,直到找到一张与待比较的牌相同的或者倒数第二张与最后一张牌比较后终止。
算法描述:
For(I = 0; I < 13; I++ ){
Temp = R[I]; // 将待检测的牌放入temp中
If( Locat(Temp,R)){
Print :ERROR!
break; // 如果Temp在R[I+1…13]中则返回1
}
// 若没有重复的牌不提示任何信息
变量说明:
一. 张牌(Card)都用一个 strcut card 结构体类型来表示具体定义如下 struct card{
char *face; // 指针 face 指向不同纸牌的点数
char *suit; // 指针 suit 指向不同纸牌的花色
} CARD;
再定义两个字符数组分别存储牌的点数和花色:
char *face[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K","A", "2"};
char *suit[] = {"/004", "/005", "/003", "/006"};
定义两个CARD型数组 deck[52],player[4][13],deck用与存储桌牌,player用于存储玩家手牌。
[/code]