请教关于扑克的算法

请教关于扑克的算法,第1张

我代码已经写的有些眉目了,随机发牌已经写完,摆放算法在纸上画出来了应该没什么大问题,代码明天写,明天下班继续回来看看,应该能搞定。

到时候思考过程我都会写出来,代码部分会放到我的baidu空间,敬请留意。

回答者:风骚的可乐 - 千总 四级 12-13 01:40

----------------------------

问题描述:

打印3行,每行9张扑克,用户随机记录一张之后输入该扑克所在的行号(1-3)

程序打乱顺序两次,用户再输入所记录的扑克在新的矩阵中的行号,也是两次。

程序给出准确结果。

--------------------------------------------------------------

分析:

假设:54张扑克对应54个整数,随机抽取27个排成矩阵。

假设:第i次打乱之后的矩阵为M(i),用户第i次输入的行号为L(i)。这里i取1,2或3。

进行第一次打乱,我们将得到用户输入的两个数,L(1)和L(2)。此时,我们需要保证同时在M(1)中第L(1)行,且在M(2)中第L(2)行的元素足够

少,假如这时候满足条件的数组是A(1),其中含元素N(1)个。

那么我们再进行第2次打乱,用户输入L(3)。那么这时候,我们要保证,同时在M(3)中第L(3)行,且在数组A(1)中的元素,有且仅有1个,也就

是N(2)必须为1。

--------------------------------------------------------------

来看一个例子:

假设有如下的整数矩阵

[1] [2] [3]

[4] [5] [6]

[7] [8] [9]

假定我记录了8,那么L(1)=3,那么程序应该知道,用户记录的数字要么是7,要么8,要么9。这时候需要把这3个数放到不同的3行里,这样下

次用户输入行数就能确定两次的交集了。

看看这种移位:

[1] [5] [9]

[4] [8] [3]

[7] [2] [6]

如果拥护输入L(2)=2,程序将可以直接判定,第一次在{ 7,8,9 }中,且第2次在{ 4,8,3 }中的,必然是8这个数。

同理,我们也可以这样移位:

[1] [8] [6]

[4] [2] [9]

[7] [5] [3]

这样,用户的输入就应该是L(2)=1,判定方式同上类似。

可以得出结论,对于3*3的矩阵,可以通过2次判定得出结果。

下面我们把结论推广到27个数:

假定有如下的9*3矩阵

[T1] [T2] [T3]

[T4] [T5] [T6]

[T7] [T8] [T9]

其中,Ti(i=1~9)分别是3*1的矩阵,我们可以通过L(1)和L(2)确定i,因为Ti只有1行3个数,所以后面可以直接通过以上的“按列移位”方法来

确定具体是哪个数。

--------------------------------------------------------------

下面给出测试代码,其中有部分变量和注释是没有实际意义的,如果你仔细看过,相信很容易将他们挑出来删除掉。

代码说明:

(1) 为了方便,我没有将关键代码写成函数形式,如果写成函数形式的话会比较便于推广到n,而不仅仅局限于27个数。

(2) 为了方便,我没有写整数数组与扑克牌的转换代码,实际上这部分功能可以简单的通过数组对应来实现,请自行完成。

(3) 为了方便,代码中用到很多swap,实际上,应该使用自己编写的交换函数来实现这个功能,为了扩展方便,swap的参数已经被写成有规律

的形式

(4) 调试环境:VC6_SP6+WinXP,转载请注明出处:http://hi.baidu.com/crazycola,代码开放,抄袭可耻

#include <time.h>

#include <iostream>

#include <cstdlib>

#include <iomanip>

using namespace std

void printArr(const int* pArr)

{

for( int i=0i<3i++ )

{

for( int j=0j<9j++ )

cout <<setw(3) <<pArr[i*9+j] <<" "

cout <<endl// 抄袭可耻

}

}

void main()

{

int line = 0

srand( (unsigned)time( NULL ) )

int *iArr = new int[27]

int tag = 0

for( int i1=0i1<27i1++ )

{

char cola_temp1 = 'x'// when you just copy this without going through

iArr[i1]=1+rand()%54// you'll be dammed

if( i1==0 ) continue

do {

tag = 0

for( int j=0j<i1j++ )

if( iArr[j] == iArr[i1] )

{

iArr[i1]=1+rand()%54

tag = 1

}

} while( tag==1 )

// cout <<iArr[i1] <<endl

}

printArr(iArr)

char cola_temp2 = 't'

cin >>line// first

int *iArr2 = new int[9]

for( int i3=0i3<9i3++ )

iArr2[i3] = iArr[(line-1)*9+i3]// aha, it's sunny outside

swap(iArr[ 0*9+ 3],iArr[ 1*9+ 3])swap(iArr[ 0*9+ 4],iArr[ 1*9+ 4])swap(iArr[ 0*9+ 5],iArr[ 1*9+ 5])

swap(iArr[ 0*9+ 3],iArr[ 2*9+ 3])swap(iArr[ 0*9+ 4],iArr[ 2*9+ 4])swap(iArr[ 0*9+ 5],iArr[ 2*9+ 5])

swap(iArr[ 0*9+ 6],iArr[ 2*9+ 6])swap(iArr[ 0*9+ 7],iArr[ 2*9+ 7])swap(iArr[ 0*9+ 8],iArr[ 2*9+ 8])

swap(iArr[ 0*9+ 6],iArr[ 1*9+ 6])swap(iArr[ 0*9+ 7],iArr[ 1*9+ 7])swap(iArr[ 0*9+ 8],iArr[ 1*9+ 8])

printArr(iArr)

cin >>line//second

int smallMatrixFoot = -1

int *iArr3 = new int[3]

char cola_temp3 = '5'// 抄袭可耻

for( int i4=0,k=0i4<9i4++ )

for( int j=0j<9j++ )

if( iArr2[j]==iArr[(line-1)*9+i4] )

{

if( k==0 ) smallMatrixFoot = (line-1)*9+i4// save for future use

// smallMatrixFoot % 9 = col_num, and ( smallMatrixFoot - col_num

) / 9 = row_num

iArr3[k++] = iArr2[j]

}

// -- start: for test only

/*for( int dbg01=0dbg01<3dbg01++ )

cout <<iArr3[dbg01] <<" "

cout<<endl*/

// --end: for test only

int col_num = smallMatrixFoot % 9

swap(iArr[ 0*9+col_num+1],iArr[ 1*9+col_num+1])swap(iArr[ 0*9+col_num+1],iArr[ 2*9+col_num+1])

swap(iArr[ 0*9+col_num+2],iArr[ 2*9+col_num+2])swap(iArr[ 0*9+col_num+2],iArr[ 1*9+col_num+2])

printArr(iArr)

char cola_temp = '0'

cin >>line//third

int bingo = -1

for( int i5=0i5<3i5++ )

if( iArr3[i5]==iArr[(line-1)*9+col_num+i5] )

bingo = iArr3[i5]// i'm not so happy

// -- start: for test only

/*else

cout <<iArr3[i5] <<"!=" <<iArr[line*9+col_num+i5] <<endl*/

// --end: for test only

cout <<endl <<"wow, you've remembered " <<bingo <<" !" <<endl

delete [] iArr3iArr3 = NULL

delete [] iArr2iArr2 = NULL

delete [] iArriArr = NULL// 抄袭可耻

}

大家好,我是前端西瓜哥。

最近在试图做一个在线斗地主的游戏,为此需要实现一个洗牌算法,最后是给它实现了。一起来看看我是怎么将它实现的吧。

思路其实也不复杂,就两步:

我们先从顶层的算法出发,将上面的两个流程抽为两个子函数。

下面我们先看看 getCards 子算法。该算法的作用是返回一个完整扑克牌数组。

我们用字符串来表示一张牌。

对于牌的大小:

至于扑克牌花色,我们用 0 到 3 表示。也可以用它们英文的首字母来表示:S、H、C、D,都可以。

然后对它们做组合,就能表示一张特定的卡牌:

这里还缺两张比较特殊的大小王。因为他们花色的概念,所以要做特殊处理,随意找两个字符来表示。

大小王的英文为 Joker,可以考虑 J(Joker)或 K(王),但它们都被占用了。最后我就随意找两个连续字母 M 和 N 来表示了。你看这个两个字母是不是很像小丑的帽子,其实还挺像的。

这里返回的是完整的一副扑克牌数组。

我用了闭包,主要是为了做缓存,因为我们每次调用这个函数的返回值其实都是一样的,缓存一下能够用空间换时间,降低时间复杂度。

这里需要注意的是,我们需要返回缓存数组的拷贝,而不是直接返回缓存数组。如果你直接返回缓存数组,返回的其实是对缓存数组的引用,因为它们指向同一个内存对象。

如果你想返回两副牌,你可以在 return 前将数组自拷贝一下再放到数组尾部。

shuffle 方法是一个通用的洗牌算法,它会将传入的数组随机打乱。实现如下;

核心逻辑为:从后往前遍历,i 递减。从 0 ~ i 的索引范围内随机找一个元素,和 arr[i] 交换。

在 i 的动态变化过程中,i 右侧为打乱的元素区间,当 i 递减到 0,整个数组就洗完了。

这种实现是一种原地算法,空间复杂度为 O(1),时间复杂度为 O(n)。

两个子函数实现完了,我们来看看执行 getShuffledCards 函数的输出结果:

西瓜哥我很满意。

这里我们再扩展一下,实现一下将乱序的牌排好序的算法。

假设我们在玩斗地主,我们把牌洗好了,先留下给地主的 3 张牌,然后每人发 17 张牌,但都是乱序的。

玩家问:“你 TMD 能不能给我把牌排好序?日内瓦!退钱!”

玩家貌似很愤怒(无感情),我们赶紧来实现上面将卡牌数组排序的 sortCards 方法。

首先明确平时我们平时打牌时的排序规则。

实现思路就是用 JS 自带的 Math.sort() 方法进行排序,难点是怎么对比两个字符串。

我们 无法用字典序 ,因为 A 比 K 大,大小王 M 和 N 又比较特殊。我使用的方案就是 计算出它们的等价的数值,通过它们来比较 。实现如下:

我们把牌大小作为更高的位( parseInt(num) * 10 )。

对于花色,则要采取负收益的做法 ,因为我是用 1 来表示黑桃,3 来表示方块,排序要求从大到小,且黑桃要最左,所以需要对它取反,来保证黑桃的值要比方块的要大。

有些非数字字符,我们需要依照它们的大小,给它们提供对应的数字。然后是大小王,需要最特殊处理,直接返回非常大的比其他牌要大的等价数。

真正地给扑克牌洗牌,然后将它们发给玩家,再帮他们拍好牌,你们学会了吗?

我们看到,实现扑克牌洗牌的算法其实并没有想象中的那么简单,当然也不难。因为我们可以使用工程化的思维,将一个大问题不断地拆分,拆分成合适大小的子问题。一个个将子问题解决,大问题自然也就被解决了。

积分规则算法如下:

1、牌面大小顺序:A>K>Q>J>10>9>8>7>6>5>4>3>2。

2、牌型大小顺序:一条龙>同花顺>四条>葫芦>同花>顺子>三条>两对>对子>散牌(乌龙)。

3、赢一墩:同一墩,大于其他某个玩家,自己加1注(头墩加1注,中墩加2注,底墩加3注)。

4、输一墩:同一墩,小于其他某个玩家,自己减1注(头墩减1注,中墩减2注,底墩减3注)。

5、强碰(打和):同一墩,与其他玩家大小一样,自己加0注。

游戏规则:

四人中一人为庄家,(也可以四人对比,) 庄家把除去大小王的一副牌牌分成四份,每份十三张。开牌前,各闲家向庄家下注。

各人把十三张牌排成三段(道),称头(道)、二道及尾(道)。头有三张,二道及尾各五张。头道必须小于二道,二道必须小于尾道,否则称为“相公”。凡“相公”者全赔。

头段因为只有三张牌,因此不算顺、花。只可能是不成花式(称无头),一对或三条。各人排好牌后,打开牌跟庄家比较大小。头跟头比,二道跟二道比,尾跟尾比。

比较时,先比牌型。牌型相同时,比点数。部分玩法的规则,比点数时由最大点数的牌比起,相同时比第二大的牌,如此类推。倘若完全相同,比最大点数牌的花色。

部分玩法的规则订成对庄家稍为有利:只比点数最大的一只牌。倘若相同,一律由庄家胜。任何一方遇上以下的组合通吃,称为“报到”。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12164358.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存