斗地主游戏的基本算法实现

wojiushi3344 2012-04-29 03:40:45
斗地主游戏的基本算法实现
by -wojiushi3344
QQ:513670524

转载请说明出处
源代码下载

PS:首先祝朋友们5,1节快乐!!之前在论坛中发了一个贴,附带上了自己写的斗地主小游戏,短短2天时间内就被下载超过200多次,所以今天决定写一下斗地主游戏的基本实现。 具体实现还得参见源代码。朋友们如果你有更好的建议可以到我博客留言讨论。谢谢!
博客地址:http://blog.csdn.net/wojiushi3344/article/details/7522245

发牌动画:

原理:没隔一段时间更新定时器,然后再更新图片到不同的位置实现地主发牌的动画。
具体实现:运用初中数学知识,2点确定一条直线(y=kx+b).



根据上图可以看出,P点和A,B,C三点连接成3条不同的直线。我们要实现发牌动画,首先需要要发出的牌从P点依次移动到A,B,C三点。然后再按着途中箭头的方向来更新点的坐标,这样依次执行下去,直到要发的牌剩3张时发牌动画截止。

定义3个vector,来存入我们已经发了的牌的坐标。

vector<card_coor> player_a;

vector<card_coor> player_b;

vector<card_coor> player_c;

具体的代码实现:

void CGame::calculateTwoPoint(float  x1,float  y1,float  x2,float  y2)//计算两点间的线段
{

m_k=(y1-y2)/(x1-x2);
m_b=y1-x1*m_k;
}

根据2点的坐标,来计算出K和b的值。

绘制使将X坐标用Y坐标来表示,这样的好处是,当我们更新Y坐标时X坐标也随之更新,从而达到我们想要实现的效果。

m_dcBuffer.TransparentBlt((m_coor_y-m_b)/m_k,m_coor_y,80,105,&m_dcImage,80*2,4*105,80,105,RGB(255,0,255));
最后我们只需要设置一个定时器,每隔一段时间来更新Y值就可以了。

当在更新的时候P点到达A,B,C任何一个点时,将牌的坐标存入相应的vector中,绘制的时候根据VECTOR的值来绘制3方的牌就可以了。

地主洗牌实现:
首先上一张图片


大家知道玩斗地主的时候有54张牌吗?如果知道,那很好,你可以进入下面的环节了。分析分牌思路。

首先我们可以定义一个拥有54张牌的一维数组。

int CardValueArray[54];

注意:详细理解下面的意思,这个对分牌很重要的。我们将54个元素用来代表不同的牌。

CardValueArray[0--------12]: 方块A---------方块K

CardValueArray[13--------25]: 梅花A---------梅花K

CardValueArray[26-------38-]: 红心A---------红心K

CardValueArray[39--------51]: 黑桃A---------黑桃K

CardValueArray【52】 小鬼 CardValueArray【53】大鬼

我想你现在应该明白我接下来该怎么做了吧!(嘿嘿)

我们将CardValueArray[54] 依次初始化为0------53.然后打乱数组的值,将数组分为4份。3份17张,1份3张(枪地主牌牌)。将3份17张牌,依次分发给3个不同的玩家。

这里难点就是给数组赋值。

这里有很多种方法。

第一种:

我们最直接能想到的一种,也是效率最低的方法。 也是我程序中采用的方法。(呵呵,比较笨吧!)

定义一个拥有54个元素的一维数组赋值为-1。然后随机生成0------54之间的数,然后判断生成的数是否在数组中已存在,不存在则存入数组,已存在则重新生成,直到54个数全部出现为止。

第二种:

可以这样,比如,定义一个拥有54个元素的一维数,依次赋值为1------53,然后随机两个0-53的数字,把这两个位置的数字互换 这样做比较多的次数之后,也是乱序的了,这个效率也不是特别高,但是比第一种要强。

第三种做法:

定义一个拥有54个元素的一维数,依次赋值为1------53, 随机54次,每次随机出一个数字,和第i个位置的数字交换,这样就比较不错了

 int  CardValueArray[54];
for(int i=0;i<54;i++)
{
CardValueArray[i]=i;
}
for (int i=0;i<54;i++)
{
swap( CardValueArray[i], CardValueArray[(rand()%54)]);
}

比如说,先随机出一个位置,和第一个数字交换,然后随机出一个位置,和第二个数字交换 打个比方,先随机出10,然后第十个数字,和第一个数字交换 然后随机出一个12,第12个数字,和第2个数字交换 然后随机一个数字和第三个交换.

第四种:

使用rand_shuffle随机化序列元素。

c++中提供了更好的解决方法,那就是random_shuffle()算法。不要着急,下面我就会告诉你如何用这种算法来产生不同类型的随机数。

产生指定范围内的随机元素集的最佳方法是创建一个顺序序列(也就是向量或者内置数组),在这个顺序序列中含有指定范围的所有值。例如,如何你需要产生54个0-54之间的数,那么就创建一个向量并用54个按升序排列的数填充向量:

#include <vector> using std::vector; 

int main()
{
vector<int> vi;
for (int i = 0; i < 10; i++)
{
vi.push_back(i); /*现在向量包含了54个 0-54 之间的整数并且按升序排列*/
}


填充完向量之后,用random_shuffle()算法打乱元素排列顺序。random_shuffle()定义在标准的头文件<algorithm.h>中。因为

所有的STL算法都是在名字空间std::中声明的,所以你要注意正确地声明数据类型。random_shuffle()有两个参数,第一个参数是指向序列首元素的迭代器,第二个参数则指向序列最后一个元素的下一个位置。下列代码段用random_shuffle()算法打乱了先前填充到向量中的元素:

#include <algorithm>

using std::random_shuffle;

random_shuffle(vi.begin(), vi.end()); /* 打乱元素 */


你可以选择以上4种中的任何一种方法来生成54个0--54之间的不重复数。

这样我们 通过以上的方法就将CardValueArray数组中的值赋值上了。现在我们只需要用数组中的值到大图中切对应的牌就行了。

从上图中我们可以用一个公式来表示每张牌在大图中的,X,Y坐标即:

y=CardValueArray[i]%13*每张牌的宽

y=CardValueArray[i]/13*每张牌的高

游戏AI思路

第一次编写AI智能,最开始真不知道该如何下手,在网上百度了一些资料,再根据自己的想法,通过进10天的重复编写,最后终于编写出了一套像样的AI智能,其中最难的就是拆牌方案和出牌规则的编写,拆牌的主要思路就是,先穷举出每张牌能组成的所有牌型,然后再根据手数最小原则来确定最后的拆牌。比如有344456778,每张牌都有组成单张的可能,4还有组成对子和3带的可能,7还有组成对子的可能,显而易见每张牌组成单张手数最多,然后如果4组成3带手数将是5,7组成对子手数也是5,最后把4组成对子,7组成单张手数将是3首,最后由手数最小原则得出最后的拆牌方案345678,44,7.出牌又分自家出牌和接牌2种,接牌又将分为2种接对手的牌和接敌人的牌,在自家出牌时先出张数叫多的牌型。在接牌的时候看是敌人出的还是对手出的,如果是敌人出的牌有大则打,如果是对手出的牌,看牌型如果是单张和对子能过则过,当对手的牌值大于K以上就直接过,其余的牌型直接PASS。

今天就先写到这里,以后有时间在写。
...全文
3826 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
cuit_NB 2014-06-13
  • 打赏
  • 举报
回复
最难的是在出牌规则和大小比较上吧,想了很久,不知道怎么下手,楼主怎么分析的?发牌洗牌这些都还好。
wojiushi3344 2012-05-06
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 的回复:]

引用 9 楼 的回复:
引用 8 楼 的回复:
引用 7 楼 的回复:
楼主能说明下怎么将数字与其对应的图片对应?

我以前也写过这类游戏,是关于麻将的,是课程设计的时候写的!

在我的上传的资料里有,打乱牌序我采用的是第二种方法,那时做的只是一个关于控制台的程序,用C写的

现在已经学完C++了,以后准备往游戏方面发展,目前还在学MFC,基本的图片的处理还是懂的,就是不晓得……
[/Quote]

没有编写过
LoveYouSelf 2012-05-06
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]
引用 8 楼 的回复:
引用 7 楼 的回复:
楼主能说明下怎么将数字与其对应的图片对应?

我以前也写过这类游戏,是关于麻将的,是课程设计的时候写的!

在我的上传的资料里有,打乱牌序我采用的是第二种方法,那时做的只是一个关于控制台的程序,用C写的

现在已经学完C++了,以后准备往游戏方面发展,目前还在学MFC,基本的图片的处理还是懂的,就是不晓得怎么将牌面与后面的数字对应! ……
[/Quote]

楼主强大! 顺便问下楼主有没有过编写格斗游戏的经验,里面的人物的动作又是怎么出来的!
tinatianNick 2012-05-01
  • 打赏
  • 举报
回复
写得很不错,现在正在写斗地主游戏。太感谢了。。
wojiushi3344 2012-04-30
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]
真的“不知道怎么玩”,鼠标点击,什么动作都没有。
有个单人的“拖拉机“,是不是你的目的?
[/Quote]
呵呵,就是实现玩家和2家电脑玩的一个地主小游戏。
schlafenhamster 2012-04-30
  • 打赏
  • 举报
回复
真的“不知道怎么玩”,鼠标点击,什么动作都没有。
有个单人的“拖拉机“,是不是你的目的?
schlafenhamster 2012-04-30
  • 打赏
  • 举报
回复
运行后,内存有泄漏:
Detected memory leaks!
Dumping objects ->
{110} normal block at 0x00377550, 112 bytes long.
。。。
schlafenhamster 2012-04-30
  • 打赏
  • 举报
回复
vc6上:
ErgodicCard(i,j,k,f,h);
warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
如何除去???
wojiushi3344 2012-04-30
  • 打赏
  • 举报
回复
呵呵,没有IN 就没有OUT ,笑一个。
schlafenhamster 2012-04-30
  • 打赏
  • 举报
回复
我从来不玩这些的,没有in就没有out。
只是考虑到可以学点什么,才下载。
wojiushi3344 2012-04-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
引用 7 楼 的回复:
楼主能说明下怎么将数字与其对应的图片对应?

我以前也写过这类游戏,是关于麻将的,是课程设计的时候写的!

在我的上传的资料里有,打乱牌序我采用的是第二种方法,那时做的只是一个关于控制台的程序,用C写的

现在已经学完C++了,以后准备往游戏方面发展,目前还在学MFC,基本的图片的处理还是懂的,就是不晓得怎么将牌面与后面的数字对应! (有点想法,但不敢去实现)……
[/Quote]

不好意思错了,不是红心K,是方块K。
wojiushi3344 2012-04-29
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
楼主能说明下怎么将数字与其对应的图片对应?

我以前也写过这类游戏,是关于麻将的,是课程设计的时候写的!

在我的上传的资料里有,打乱牌序我采用的是第二种方法,那时做的只是一个关于控制台的程序,用C写的

现在已经学完C++了,以后准备往游戏方面发展,目前还在学MFC,基本的图片的处理还是懂的,就是不晓得怎么将牌面与后面的数字对应! (有点想法,但不敢去实现),希望听听楼主的做法!
[/Quote]
我们假设你游戏的牌在一张大图中,我们就举上面斗地主的例子嘛。有一章大图,里面包含很多的小图,很容易发现每张小图都是有规律的。我们以一张牌为单位那么这张大图就可以用13*5来表示。假设我们数组第一个值为12.12对应的X坐标是不是就是12%13*每张牌的宽。y坐标是不是就是12/13*每张牌的高。那么对应的牌就是红心K。坐标有了你绘制的时候到大图里面去切小图就能绘制红心K了。不知这下你明白没有。
LoveYouSelf 2012-04-29
  • 打赏
  • 举报
回复
楼主能说明下怎么将数字与其对应的图片对应?

我以前也写过这类游戏,是关于麻将的,是课程设计的时候写的!

在我的上传的资料里有,打乱牌序我采用的是第二种方法,那时做的只是一个关于控制台的程序,用C写的

现在已经学完C++了,以后准备往游戏方面发展,目前还在学MFC,基本的图片的处理还是懂的,就是不晓得怎么将牌面与后面的数字对应! (有点想法,但不敢去实现),希望听听楼主的做法!
chenbaohai1990 2012-04-29
  • 打赏
  • 举报
回复
咋没有菜单与登入界面
wojiushi3344 2012-04-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
不知道怎么玩?
[/Quote]
嘿嘿,地主斗也不知道怎么玩呀。你也太OUT了吧!
schlafenhamster 2012-04-29
  • 打赏
  • 举报
回复
不知道怎么玩?
wojiushi3344 2012-04-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
支持2副牌吗? 一副牌玩得人少
[/Quote]
不支持也。。呵呵 这是一年前写的程序了。
Kaile 2012-04-29
  • 打赏
  • 举报
回复
支持2副牌吗? 一副牌玩得人少
schlafenhamster 2012-04-29
  • 打赏
  • 举报
回复
下载了,学习。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧