斗地主项目总结
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
斗地主项目总结
一,设计过程
1,由于我没有玩过斗地主,设计初期,没有一点思路。先写了一个界面,完成了洗牌,分牌,出牌功能。
牌值数组:i nt Pai[54] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,
7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,15};
在程序内部,操作的是1-15之间的牌值。之后在显示的时候才通过转换函数:
char paiChange (int n)将其转换为‘J’‘Q’之类的字符,并显示到屏幕上。
并通过一个保存三个玩家牌值数组名的指针数组实现三人轮流出牌:
int *WanJia[] = {JiaPai, YiPai, BingPai};//玩家名称数组
while(1)
{
…………………………………………..
// DoPai为出牌函数
if(DoPai (WanJia[i % 3], WanJiaPaiShu[i % 3], i % 3, &ComPai, nBool))
{
break;
}
nPaiAay[i % 3] = ComPai;
i++;
}这样就实现了三人轮流出牌。
然后,用一个临时数组保存玩家出的牌:
for (i = 0; ZhuoMian[i]; i++);//找到最后一个位置
ZhuoMian[i] = ary[nPaiIndex - 1];//从玩家牌值数组中拷贝
ZhuoMianCount ++;//临时数组长度加1
ary[nPaiIndex - 1] = 30;//把玩家牌值数组中相应的牌值赋为30
(*nCount) --;//把玩家牌值数组长度减1
…………………………………………..
关键:每次操作后,都要进行排序
2,增加了判定牌型的函数。
int ComparePai (int ZhuoMian[], int ZhuoMianCount, char **cPaiType);
完成单牌,对子,三张,顺子,双顺子,三顺子,三带一. . . . . .等的判定。
难点:牌之间的比较。
起初是直接用两个玩家的牌进行比较,后来发现这样很容易出错。重写了。
后来,我想到了为每个牌型规定一定比较数,这个数的结构是这样的:
例:三带一的比较数都是300开始的。‘8、8、8、4’的比较数是306.
最高位是权限位,后面的是用于比较大小的牌面值。在比较的时候,通过
//实现权限比对,10 ~ 10000之间的权限一样,10000以上的权限最高
//例如:103可以和106比较,但是禁止和504比较,10000以上的可以通吃
if ((nCompZM > *ComPai && nCompZM / 100 == *ComPai / 100 &&
nCompZM > 100)|| nCompZM / 10000 > *ComPai / 10000 ||
(*ComPai == 0 && nCompZM >100))
进行比较。
然后个玩家出牌后,都调用比较函数ComparePai进行比较,并且返回一个比较数,如果比上家大,就和上家的比较数进行交换,大不过,就保持不变。这样就实现了牌的比较。
3,增加了出完牌后,两家都不要的处理方式。
思路是:用一个三元素数组保存三个玩家出牌后,返回的比较数。如果三次都不变,就让第一个出牌的人,继续条件出牌(不用继续比较)。
具体实现:int nPaiAay[3] = {0};
nPaiAay[i % 3] = ComPai;
if (i >= j) //实现其余两家不要,本家继续随便出牌
{
for (j = i; j - i < 3; j++)
{
if (nPaiAay[j % 3] != nPaiAay[j % 3 +1] || nPaiAay[j % 3] == 10)
{
break;
}
}
if (j - i >= 3 && ComPai != 0 )
{
ComPai = 0;
}
}
4,增加了对输入错误和Pass等的判定功能。
难点:由于我用的是动态出牌,也就是输入牌值对应的下标后,相应的牌就会从数组中消失(其实不是消失,只是没赋值为30,数组长度减1)。
于是在输入错误之后,要把牌重新返回到玩家手中。
for (i = 0; ZhuoMian[i]; i++)
{
(*nCount) ++;//现把数组长度加一
ary[(*nCount) - 1] = ZhuoMian[i]; //把牌重新拷贝回去
}
以上:初期设计大体结束。
二,AI设计
1,牌面分析
由于原计划没有想过弄这个东西,后来时间比较充足就搞了。所以没有什么计划,想到一点写一点。结构也比较乱,代码比较长。
思路是:在机器人出牌之前,现把它手中的牌进行分析,把结果保存到一个结构体中,然后根据上家出牌返回的比较数,来选择其要出的牌。
首先写了一个用于保存牌面分析结果的结构体:
牌型大体分为,单牌,对子,三张,顺子,双顺子,炸弹,对王。
通过以上牌型的组合,可实现斗地主中所有的牌型。
typedef struct
{
DANPAI danpai[20];//单牌
DUIZI duizi[10];//对子
SANBUDAI sanbudai[7];//以下略。。。
ZHADAN zhadan[4];
WUSHUNZI wushunzi[5];
LIUSHUNZI liushunzi[6];
QISHUNZI qishunzi[7];
DUIW ANG duiwang[1];
SANDAIYI sandaiyi;
SANDAIER sandaier;
SIDAIER sidaier;
SANSHUANGSHUNZI sanshuangshunzi[3];
SISHUANGSHUNZI sishuangshunzi[2];
BASHUNZI bashunzi[2];
JIUSHUNZI jiushunzi[2];
}PAIXING;
然后开始写牌面分析函数
//AI判断对子
int AnalyseDUIZI (PAIXING *paixing, int PaiDemo[], int *PaiCount);
//AI判断顺子
int AnalyseSHUNZI (PAIXING *paixing, int PaiDemo[], int *PaiCount, int n);
//AI判断三张
int AnalyseSANZHANG (PAIXING *paixing, int PaiDemo[], int *PaiCount);
//AI判断炸弹
int AnalyseZHADAN (PAIXING *paixing, int PaiDemo[], int *PaiCount);
//AI判断单牌
int AnalyseDANPAI (PAIXING *paixing, int PaiDemo[], int *PaiCount);