我找了此资料,一起共享
下面直接介绍经典数组洗牌法的算法原理:
假如你有一个布袋或者抽屉,里面有m=10个不同号码的球,
你要随机抽取,并保证不重复……
那么正确的做法是:
1 每次从布袋中随机抽取一个球; 注意到rnd()函数的正确抽取目数应该是=m
2 抽取出来的这一个球要另外放置开;
如果不另外放置,而只是记下号码后再把球返回布袋,接下来就无法保证这个已经被抽到过的球又被重复抽到。
而这个,就是1楼代码中没有考虑到而产生的重大bug
3 继续从布袋中随机抽取另一个球;
注意到此时布袋中剩余球的数量少了一个是m-1了,因此rnd()函数的正确抽取目数应该是=m-1
4 抽取出来的这第2个球和已经抽取出来的第1个球放置在一齐,并且按新的序列排放。
5 重复以上随机抽取过程,注意到关键是:
a 每次抽取的母数即剩余球数要递减1个
b 每次抽取出来的新球要分开放置,不能放回布袋!
c 新抽取出来的球,要和前面已经取出的球按新的序列整齐排放。
d 剩下最最重要一点,但是看到这里好多人都可能不会意识到的一个问题:
布袋中剩余球如何放置?
即,假定布袋中球也是像放置在抽屉中那样,有序地排放着的,
那么每次抽走一个球,必然留下一个空格……这就很麻烦了!
因为大家知道,实际上数组中用rnd()函数只能是返回一个一定区间内的值及数组位置,
而如果留有空位的话,随机性就无法保证高效……万一抽到空格怎么办?难道重新再抽一次?
如果抽到只剩最后一个求时,则原先的布袋/抽屉中,将留下9个空格,则每次随机函数的计算结果,将有90%的概率仍旧抽到空格……
这就完蛋了。
经典数组洗牌法的真正原理是:
1 从m个值中随机确定一个位置r (利用Rnd()随机函数计算,具体算法是以剩余数m为母数区间进行随机值计算并取整返回位置)
2 把这个位置即要被抽取的元素(球)先取出拿在手中存入临时变量t,腾出一个空位。
3 把数组的第1位置(Lbound)元素拿出来,放入刚才腾出的r空位。并随即腾出了数组第一位置作为新的空位
(也可以以数组的最末位置(UBound)作为开始位置进行处理,具体算法代码就不太一样了)
4 把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入新的空位,即数组第一位置。
这个数组第一位置中的新元素,就是已经被有效抽取的第1个不重复值。
然后,继续
1 抽第2个数时,以剩余母数m-1作为随机计算区间而返回一个随机值并计算取整返回第2个不重复的随机位置r
2 把这个位置r即要被抽取的第2个元素(球)先取出拿在手中存入临时变量t,腾出一个空位。
3 把数组的第2位置元素拿出来,放入刚才腾出的r空位。并随即腾出了数组第2位置作为新的空位
(也可以以数组的最末倒数第2位置进行处理,具体算法代码就不太一样了)
4 把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入新的空位,即数组第2位置。
这个数组第2位置中的新元素,就是已经被有效抽取的第2个不重复值。
以上述方式反复进行,抽取、置换,存放,直到最后一个,也不会产生重复抽取了。
下面是经典数组洗牌法实际代码中最简单的代码例子:
对于一个下标1开始的一维数组,从中随机抽取n个元素返回。
Sub GetRnd(arr, n)Randomize
For i = 1 To n '正序洗牌 1 to n 简化代码
r = Int(Rnd() (n - i + 1)) + i
t = arr(r): arr(r) = arr(i): arr(i) = t '下标1开始一维代码
Next
End Sub
'正序洗牌 1 to n 简化代码详解:
Sub GetRnd(arr, n)
Randomize '随机种子初始化,保证每次代码运行或打开文件时出现的随机序列是和上次文件保存/运行时不同的序列。
For i = 1 To n '遍历1 to n
r = Int(Rnd() (n - i + 1)) + i 、
'按每次剩余母数(n - i + 1) 作为随机计算区间,计算Rnd() (n - i + 1) 然后用int()函数去整,得到剩余数中的随机位置。
'紧接着,这个随机位置后面+i处理,转化成从新的起点i开始的随机位置r。即不再包括已经抽取出的结果,避免重复。
t = arr(r) '把这个随机位置r中的元素取出,存入临时变量t
arr(r) = arr(i) '把第i个位置中的元素放入刚才腾出的r空位(实际数据 *** 作时并没有腾出,而只是用新的值直接覆盖掉。)
arr(i) = t '把上面刚刚腾出的i空位放入刚才存放在临时变量t中的当前最新抽取元素,完成一次抽取过程。
Next '循环抽取、置换、存贮抽取结果
End Sub
#include <stdioh>
#include <stdlibh>
#include <timeh>
int main()
{
int poke[13][4],joker[2],last_four_card[4]; //定义四类十三张牌、双王
int i,j,card,count,tank[54],player[20],computer[2][20];
bool flag;
srand(time(NULL)); //初始化随机种子
for(i=0;i<54;i++)
tank[i]=-1; //初始化容器
for(i=0;i<54;i++)
{
flag=1;
while(flag)
{
flag=0;
card=rand()%54;
for(j=0;j<=i;j++)
if(card==tank[j]) flag=1;
}
tank[i]=card;
}
count=0;
for(i=0;i<54;i++)
{
if(tank[i]==52) printf("jok ");
else if(tank[i]==53) printf("JOK ");
else if(tank[i]%13==0) printf("%c%c ",tank[i]/13+3,'A');
else if(tank[i]%13==10) printf("%c%c ",tank[i]/13+3,'J');
else if(tank[i]%13==11) printf("%c%c ",tank[i]/13+3,'Q');
else if(tank[i]%13==12) printf("%c%c ",tank[i]/13+3,'K');
else if(tank[i]%13<10) printf("%c%-2d ",tank[i]/13+3,tank[i]%13+1);
count++;
if(count%20==0) printf("\n");
}
count=0;
for(i=0;i<16;i++)
{
player[i]=tank[i];
computer[0][i]=tank[i+16];
computer[1][i]=tank[i+32];
}
for(i=0;i<4;i++)
last_four_card[i]=tank[53-i];
printf("\n\n你的牌是:\n\n");
for(i=0;i<16;i++)
{
if(player[i]==52) printf("jok ");
else if(player[i]==53) printf("JOK ");
else if(player[i]%13==0) printf("%c%c ",player[i]/13+3,'A');
else if(player[i]%13==10) printf("%c%c ",player[i]/13+3,'J');
else if(player[i]%13==11) printf("%c%c ",player[i]/13+3,'Q');
else if(player[i]%13==12) printf("%c%c ",player[i]/13+3,'K');
else if(player[i]%13<10) printf("%c%-2d ",player[i]/13+3,player[i]%13+1);
count++;
if(count%20==0) printf("\n");
}
getchar();
getchar();
return 0;
}
以前无聊写的 给你作参考吧
import javautilHashMap;
import javautilMap;
import javautilRandom;
/
Author:danagao
java 发牌程序,
不含大王,小王
可设定发牌人数
/
public class Pai {
HashMap<String, String> map = new HashMap<String, String>();
private static final String[] colors = {"红桃", "方块", "梅花", "黑桃"};
private static final String[] values = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
private String[] newpai; private int len;
//初始化52张牌
public Pai() {
len = colorslength valueslength;
newpai = new String[len];
int k = 0;
for (int i = 0; i < colorslength; i++) {
for (int j = 0; j < valueslength; j++) {
newpai[k] = colors[i] + values[j];
k++;
}
}
}
//洗牌(把牌打乱)
private void getNums() {
Random r = new Random();
int i = rnextInt(len);
String s;
if (i >= 0 && !mapcontainsKey(StringvalueOf(i))) {
s = StringvalueOf(i);
mapput(s, newpai[i]);
} else {
getNums();
}
}
//发牌
public void showResult(int p) {
for (int i = 0; i < len; i++) {
getNums();
}
int l = len/p; //每人发几张牌
int j=1;//计人数
int k=0;//计牌数
for (MapEntry<String, String> entry : mapentrySet()) {
if(k%l==0 && j<=p){
Systemoutprintln("第"+j+"个人的牌:");
j++;
} else if(len-k <= len%p){
Systemoutprintln("剩余的牌:");
}
k++;
Systemoutprintln(entrygetValue());
} }
public static void main(String[] args) {
DbColorBall dbColorBall = new DbColorBall();
dbColorBallshowResult(4);
}
}
分类: 电脑/网络 >> 程序设计 >> 其他编程语言
解析:
用随机函数来模拟比较合适
扑克牌有54张,可以先约定好,比如:
大猫----------0
小猫----------1
黑桃A---------1
黑桃2---------黑桃A + 1
黑桃3---------黑桃A + 2
黑桃K---------黑桃A + 12
红心A---------黑桃A + 13
红心2---------红心A + 1
这样就可以把整副扑克牌的每张牌用一个特定的整数来表示,它们之间的大小关系可以通过不同的玩法制定相应的规则。
那好,现在我们定义一副牌int Joker[54];
用随机函数来填充Joker。
算法为:(不是真实的程序语言,由于不知道你使用什么编程语言,这里只描述算法)
for(i = 0 to 53)
{
l1:
生成随机数:pai = rand(54); 随机生成一个0 -- 53的整数
在已产生的牌中查找是否存在pai(即在Joker[0] 到Joker[i - 1]中查找)
如果存在,goto l1;
否则Joker[i] = pai
}
这样我们就把整副牌给洗好了。
接下来,就可以发牌了。
发牌时,只要按顺序把牌“发”到每个人的“手”里就行了
例如:4个人玩牌,四个人的牌为player[4][14];
for(i = 0 to 53)
{
player[i % 4][i / 4] = Joker[i];
}
这样就完成了发牌程序。
当然,如果你想要发牌也用一维数组,那也简单,比如还是4个人玩,那么:
player0手上的第n张牌就是Joker[n 4 + 0]
player1手上的第n张牌就是Joker[n 4 + 1]
player2手上的第n张牌就是Joker[n 4 + 2]
player3手上的第n张牌就是Joker[n 4 + 3]
好了,洗牌和发牌都已经完成,剩下就是如何玩牌了,你没问,就不多说了。
上面的伪代码应该能看懂吧?如果有问题,就用消息联系好了。你自己用编程语言去实现,不是什么大问题的。
以上就是关于VBA洗牌法原理谁能文字阐释一下全部的内容,包括:VBA洗牌法原理谁能文字阐释一下、编写C语言程序,模拟将一副扑克牌54张随机分给4个人 (如何表达不同花色和大小,如何高效洗牌)、java编写扑克牌游戏里,洗牌时发牌时用到了随机分配的功能,请问在那个包中哪个类哪个方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)