关于麻将听牌的算法

dengkz1 2006-03-03 10:48:15
假设有:
二万,三万,四万,五万,六万,七万,八万

如果听牌的话有下列:
1,(二万,三万,四万)+(五万,六万,七万)+八万---->听八万

2,(二万,三万,四万)+(六万,七万,八万)+五万---->听五万

3,(三万,四万,五万)+(六万,七万,八万) +二万---->听二万

就要判断出上面的三组听牌可能,上面的牌都有一个对应值,分别是(2,3,4,5,6,7,8)

你能谈谈你的思路吗?????
...全文
1790 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
Greenberet 2006-06-27
  • 打赏
  • 举报
回复
看来麻将听/糊牌算法还真难倒不少人啊。。。

>>作为国粹的麻将,在互联网上相关的游戏编程资源如此之少,讨论的人不多,特别是与Delphi 相关的例子几乎没有,自己研究也不容易,现特建立一个QQ群专门来讨论麻将游戏的开发,如对此有兴趣的朋友请加群:6557246 (请注明:MJCSDN)

(如果您对街机:电子基盘,天开眼等有了解朋友更是欢迎)
cnwhonker 2006-04-12
  • 打赏
  • 举报
回复
偶不会打麻将:)
win2000pega 2006-04-07
  • 打赏
  • 举报
回复
每次列举一下所有的牌,然后看那张牌满足和牌的条件。就听那张牌。
类据的次数是:
1万-9万 9张
1桶-9桶 9张
1条-9条 9张
东-发 7张
afan789 2006-03-26
  • 打赏
  • 举报
回复
晕,
好吧,我来说一遍吧。。。。。

每一手可胡的麻将牌都是14张牌(把碰牌、杠牌都当作3张牌加进手中去),
可以看作(而且一定)是由五组牌组成的,
根据麻将规则,其中有且只有1组的对子(将牌),和其余共4组的顺子、刻子(碰牌或杠牌,)

先设定对子值是0,碰(杠)牌值是1,顺子是2
所以每手麻将牌的胡牌的数组 isHu:array[0..4] of integer;
例:isHu(2,1,1,1,0) 表示第一组是顺子,第二至四组是刻子(三张一样的牌),第五组是对子,
当isHu数组中只有一个0值(表示只有1组对子,其余四组是由顺子或刻子组成)时,这手麻将牌是可胡的.

我们现在要做的,把所有可能胡牌的组合(共1百多种可能)对这14张麻将牌进行处理,如果最后与条件符合的话,
说明一手麻将牌可胡,不符合的话当然就是胡不了啦.

首先把14张麻将牌转换成状如下列的数组。Tmp34Card:array[0..34] of integer;
Tmp34Card(0,0,0,0,0,0,1,1,1, // 一张七万,一张八万,一张九万
3,0,0,0,0,0,0,0,0, // 三张一同
0,0,0,0,3,0,0,0,0, // 三张五索
0,0,3,0,0,2,0); // 三张西风,两张发财
前面的三行分别代表万、同、索,最后一行代表字牌。该位置上的数字代表该种牌有几张

如果isHu[m]=2,则用顺子进行检测,首先顺序搜索到Tmp34Card[n]<>0的地方,然后

Dec(Tmp34Card[n],1);
Dec(Tmp34Card[n+1],1);
Dec(Tmp34Card[n+2],1);

注意:上面三个值不能小于零,什么原因自己想

如果isHu[m]=1,则用刻子进行检测,也是搜索到Tmp34Card[n]<>0的地方,然后

Dec(Tmp34Card,3); // 这个值也不能小于零

如果isHu[m]=0的话就Dec(Tmp34Card,2);

如果五组牌最后都能够成功匹配的话,胡牌成功,无法匹配的话则换另一种组合,全部组合都无法匹配的话,那就......

至于听什么牌的算法嘛,那就把34张麻将牌依次代入,看是否可胡,可胡的那几张牌就是要听的牌了.

BTW:
水平有限,看得懂就看,看不懂就算吧.哈哈..........................
Delphi1985 2006-03-23
  • 打赏
  • 举报
回复
代码看起来吃力
你把思路说上就行了撒
afan789 2006-03-23
  • 打赏
  • 举报
回复
上面那个ZiMo函数是我写的,因为表达能力有限,注释说得不太明白,见笑。
afan789 2006-03-23
  • 打赏
  • 举报
回复
VInput:array[0..135] of integer;

136张麻将牌分别对应1个号码,
对应关系是:

case MjNo of
1..4:CardName:='一筒';
5..8:CardName:='二筒';
9..12:CardName:='三筒';
13..16:CardName:='四筒';
17..20:CardName:='五筒';
21..24:CardName:='六筒';
25..28:CardName:='七筒';
29..32:CardName:='八筒';
33..36:CardName:='九筒';

37..40:CardName:='一索';
41..44:CardName:='二索';
45..48:CardName:='三索';
49..52:CardName:='四索';
53..56:CardName:='五索';
57..60:CardName:='六索';
61..64:CardName:='七索';
65..68:CardName:='八索';
69..72:CardName:='九索';

73..76:CardName:='一万';
77..80:CardName:='二万';
81..84:CardName:='三万';
85..88:CardName:='四万';
89..92:CardName:='五万';
93..96:CardName:='六万';
97..100:CardName:='七万';
101..104:CardName:='八万';
105..108:CardName:='九万';

109..112:CardName:='东风';
113..116:CardName:='南风';
117..120:CardName:='西风';
121..124:CardName:='北风';
125..128:CardName:='红中';
129..132:CardName:='发财';
133..136:CardName:='白板';
afan789 2006-03-23
  • 打赏
  • 举报
回复
上次题目没看清楚,这回看明白了,给你一个可用的


// [函数] 自摸检测(鸡胡)
function ZiMo(VInput:array of integer):bool;
var
TmpZimo:bool;
Test:array[0..4] of integer; // 胡牌组合检测参数
Tmp34Card:array[0..33] of integer; // 14张牌的位置数组
i,j,k,m,Sn,TestSuccess:integer; // Sn用来存首张牌的位置
// JiangNo是将牌的组数
// s:string;

begin

TmpZimo := false; // 赋予初值
j:=0;
MySort(VInput,14); // 排序

// 每一手可胡的麻将可拆分为五组牌,这五组牌分别由顺子,刻子和
// 有且唯一的将牌(即对子)组成,
// 所以每一手可胡的麻将牌理论上可能的胡牌组合=3的5次方=243种.
// 实际上胡牌的可能组合为112种(因为将牌的特殊原因)

// 设置循环方式,将112种胡牌组合依次代入,组合成功时退出.
// 先计算出本次循环要代入的胡牌组合代数

// ==把待检测的14张牌转换成位置数组

for i :=0 to 33 do // 初始化,置零值
Tmp34Card[i]:=0;

for i :=0 to 13 do // 将麻将牌号换算为位置
inc(Tmp34Card[(VInput[i]-1) div 4],1); //(本句已通过验证)

// ==转换完成
// 经过上循环,得出状如下列的数组
// Tmp34Card=(0,0,1,1,1,0,3,0,0, 1,2,2,1,0,2,0,0,0, ......)

// 十三么检测开始(鸡胡里没有十三么)

if (Tmp34Card[0]>0) and (Tmp34Card[8]>0) and (Tmp34Card[9]>0) and
(Tmp34Card[17]>0) and (Tmp34Card[18]>0) and (Tmp34Card[26]>0) and
(Tmp34Card[27]>0) and (Tmp34Card[28]>0) and (Tmp34Card[29]>0) and
(Tmp34Card[30]>0) and (Tmp34Card[31]>0) and (Tmp34Card[32]>0) and
(Tmp34Card[33]>0) and
(
(Tmp34Card[0]=2) or (Tmp34Card[8]=2) or (Tmp34Card[9]=2) or
(Tmp34Card[17]=2) or (Tmp34Card[18]=2) or (Tmp34Card[26]=2) or
(Tmp34Card[27]=2) or (Tmp34Card[28]=2) or (Tmp34Card[29]=2) or
(Tmp34Card[30]=2) or (Tmp34Card[31]=2) or (Tmp34Card[32]=2) or
(Tmp34Card[33]=2)
) then
begin
TmpZimo := true;
j:=243;
end;

// 十三么检测结束

while j<=242 do // 242次循环开始(3进制转换算法)
begin

m:=0;

// 将113/243种胡牌组合中取一种组合赋予给Test[i]

Test[0] := j div 81; // 第一组的组合形式(将,刻,顺)
if Test[0]=0 then inc(m,1); // 每发现一组将牌,则参数m+1;

Test[1]:= (j-(Test[0]*81)) div 27; // 第二组的组合形式
if Test[1]=0 then inc(m,1); // 每发现一组将牌,则参数m+1;

Test[2]:= (j-(Test[0]*81)-(Test[1]*27)) div 9; //第3组
if Test[2]=0 then inc(m,1); // 每发现一组将牌,则参数m+1;

Test[3]:= (j-(Test[0]*81)-(Test[1]*27)-(Test[2]*9)) div 3; //第4组
if Test[3]=0 then inc(m,1); // 每发现一组将牌,则参数m+1;

Test[4]:= j-(Test[0]*81)-(Test[1]*27)-(Test[2]*9)-(Test[3]*3); //第5组
if Test[4]=0 then inc(m,1); // 每发现一组将牌,则参数m+1;

// 上面段是从所有胡牌组合中取出一种可能组合并赋予Test[i]

if m>1 then // 将牌不能超过一组,否则舍去此种组合,并重新循环
begin
inc(j,1);
continue;
end;

// ==把待检测的14张牌转换成位置数组

for i :=0 to 33 do // 初始化,全部置零值
Tmp34Card[i]:=0;

for i :=0 to 13 do // 将麻将牌号换算为位置
inc(Tmp34Card[(VInput[i]-1) div 4],1); //(本句已通过验证)

// ==转换完成
// 经过上循环,得出状如下列的数组
// Tmp34Card=(0,0,1,1,1,0,3,0,0, 1,2,2,1,0,2,0,0,0, ......)

{
s:='';
for n :=0 to 33 do
s:=s+' '+inttostr(Tmp34Card[n]);
ShowMessage(s);
}

Sn:=0; // 首张牌的位置号.置零
i:=0; // 胡牌组合的第几组

// 将113种胡牌组合中取一种组合代入待检牌
// 可胡性检测开始

while i<=4 do // 每一手可胡的麻将可拆分为五组牌
begin

k:=0; // 找到(剩下牌中)首张牌的位置
while k <= 33 do // 每一轮检测后都要在数组中减去已成功组合
begin // 的牌,所以要重新测定首张牌的位置
if Tmp34Card[k]<>0 then
begin
Sn:=k; // 检测到后打上标志
k:=34; // 首张牌的位置号 eg: 9是一索
end;
inc(k,1);
end;

// TestSuccess含义: 假设的组合是否与实际组合相符
TestSuccess:=0; // 检测参数

// 对子 2
if Test[i]=0 then // 待检参数为将牌(对子)=>进入此段检测
begin
if Tmp34Card[Sn]>1 then // 可以配成对子
begin
Dec(Tmp34Card[Sn],2); // 在检测序列中减去两张牌
TestSuccess:=1; // 本轮检测是否通过参数
end;
end;

// 刻子 3
if Test[i]=1 then // 待检参数为刻子=>进入此段检测
begin
if Tmp34Card[Sn]>2 then // 可以配成刻子
begin
Dec(Tmp34Card[Sn],3); // 在检测序列中减去三张牌
TestSuccess:=1; // 本轮检测是否通过参数
end;
end;

// 顺子 123
if Test[i]=2 then // 待检参数为顺子=>进入此段检测
begin
if (Tmp34Card[Sn+1]<>0) and (Tmp34Card[Sn+2]<>0) then // 可以配成顺子
begin
Dec(Tmp34Card[Sn],1); // 在检测序列中减去
Dec(Tmp34Card[Sn+1],1); // 在检测序列中减去
Dec(Tmp34Card[Sn+2],1); // 在检测序列中减去
TestSuccess:=1; // 本轮检测是否通过参数
end;
end;

// showmessage(inttostr(j)+' '+inttostr(Tmp34Card[Sn])+' '+
// inttostr(i)+' '+inttostr(sn)+' '+inttostr(TestSuccess));

if TestSuccess=0 then // 本轮无法组合,退出,换下一种组合
break;

if (i=4) and (TestSuccess=1) then // 如果第五组组合通过检测
begin
TmpZimo := true; // 则胡牌成功
break; // 退出
end;
// 在三种牌型检测完毕后开始第2/5组检测
inc(i,1); // 下一轮循环将检测 Test[i+1]

end; // 可胡性检测结束

if TmpZimo then break;

inc(j,1);

end; // 242次循环结束(3进制转换算法)

ZiMo := TmpZimo;

end;
yjs0100 2006-03-23
  • 打赏
  • 举报
回复
学学,帮你顶呀!!
数组 1W......9W
1T......9T
1B......9B
dong xi nan bei zhong fa bai
必须有一对完全一样的 2 5 8作长儿
一共13个牌,我觉得最好是把所有胡牌的14棵的可能都找出来,然后把手中的牌与之比较完全一只要完全一样就听牌,听这14个中没有的那几个!!
todouwang 2006-03-17
  • 打赏
  • 举报
回复
只要有2,3,4,或者3,4,5就可以听

需要的2,5,8也是有规律的
afan789 2006-03-07
  • 打赏
  • 举报
回复
楼主你好,我也在编一麻将游戏,希望互相沟通一下
QQ:91301
afan789 2006-03-07
  • 打赏
  • 举报
回复
穷举:
把一到九万都代入就知道胡什么了
chijingde 2006-03-06
  • 打赏
  • 举报
回复
你写的不就是思路么?

穷举...

找出所有的可能
Allblus 2006-03-05
  • 打赏
  • 举报
回复
这个我的思路
Allblus 2006-03-05
  • 打赏
  • 举报
回复
你要玩麻将去下一个就得了,干嘛自己写.就好象你需要针就不要拿铁棒来磨了:)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi GAME,图形处理/多媒体
社区管理员
  • GAME,图形处理/多媒体社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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