最近在做一个炸弹斗地主的项目,需要搭建一个离线牌库,筛牌就成为了重点。其实别的部门有这块的功能代码,但是时间充裕,自己做做,效率不行的话,再想办法拿人家的代码吧。。。
与普通斗地主的出牌规则一致:
牌型 |
---|
火箭(双王) |
炸弹 |
四带2单 |
四带一对 |
四带两对 |
三带1 |
三带一对 |
单顺(5张及以上) |
双顺(3对及以上) |
三顺(2组及以上) |
飞机带翅膀(33344456,或者3334445566) |
对子 |
单牌 |
分析:
在各种牌型中,只有顺子和飞机与牌的点数有关,其他的与牌的点数均无关,也就是说,其他的牌只要每种牌的张数固定了,最少出牌手数就是固定的。
因此用DP数组存储每种情况的出牌次数,然后对顺子和飞机进行深搜即可。算法实际运行挺快的。代码下周整理好再放。
分割线-------------------------------------------------------------------
talk is cheap, show me the code
最近一直在忙,没来的及更新,手数搜索的代码测试过了,已经放到线上使用了,下面讲解下dp的思路以及主要代码:
1.dp状态的定义
一共有五种状态:
(1)当前手中的牌的数量
(2)炸弹的数量, 比如33334444,状态值就是2
(3)三张的数量,比如剩余手牌33367,状态值就是1
(4)对子的数量
(5)单牌的数量
状态有了,dp数组自然就定义出来了:
dp[17][25][25][25][25]: 稍微定义的大了一些,服务端,内存充足,哈哈哈,不影响,可以根据自己项目的需求修改。
2.dp数组的初始化
直接上代码,dp中的拆带牌规则,可以根据需求进行调整,比如现在的代码中是允许将一个炸弹当作两个对子的,也就是可以允许这种出牌: 3333 55 55
void InitAllDPArr()
{
for(int i = 0; i< 17; i ++)
{
InitDPArr(i + 1, m_dp[i]);// i + 1 代表手牌张数
}
}
void InitDPArr(int nDPIndex,int (&dp)[25][25][25][25])
{
dp[0][0][0][0] = 0; // base case
for(int i = 0; i <= nDPIndex; i ++) //四张
{
for(int j = 0; j <= nDPIndex; j ++) //三张
{
for(int k = 0; k <= nDPIndex; k ++) //对子
{
for(int l = 0;l <= nDPIndex; l ++) //单张