标题:麻将胡牌算法
只看楼主
qunxingw
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:24
帖 子:1676
专家分:7295
注 册:2011-6-30
得分:0 
回复 20楼 azzbcc
谢谢你,看来看别人的东西更累,代价要高。

www.qunxingw.wang
2013-01-16 15:23
azzbcc
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江西财经大学
等 级:贵宾
威 望:81
帖 子:3293
专家分:12919
注 册:2012-11-4
得分:0 
在火车上无聊了,详细说下我的思路。

先标记暗刻牌,同时记录暗刻数m,在标记将牌,这里的标记,就是减去的意思。最后在剩下的牌里找连续牌,记为n,然后m+n=4就说明是胡牌了。

因为  3个相同 的个数与最后结果中的个数不一定相同,例如11123,虽然有3个1,但牌中没4,所以反而要做将牌。

假设有 j个这种  3个相同,就会产生 2^j种可能,再在对应的情况中找将牌,又有 很多情况了,所以才说是穷举。

这里再说下change函数作用,m值取值范围是 0 - 15,取其二进制位,1表示最后结果 这是一组暗刻,0表示这组 3个相同 是其他情况。比如 5 = 0101,就把找到的  3个相同 的第1 3组标记

代码中还有错误,记录将牌下标的temp2数组可能因为外循环累积,再前面加一个temp2[0] = 0就可以了。

下午到家后再研究研究版主的代码,嘿嘿:-)


[fly]存在即是合理[/fly]
2013-01-17 04:12
azzbcc
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江西财经大学
等 级:贵宾
威 望:81
帖 子:3293
专家分:12919
注 册:2012-11-4
得分:0 
手机码字真心伤不起啊!!!


[fly]存在即是合理[/fly]
2013-01-17 04:15
qunxingw
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:24
帖 子:1676
专家分:7295
注 册:2011-6-30
得分:0 
回复 22楼 azzbcc
首先感谢参与。我对你的程序弱弱的能理解一点,整体上应该是一个不错的思路,在不加tmep2[0]=0的情况下,测试胡牌的都可以找到。加后也有问题,
同时测试数据:    0 2 3 2 2 2 1 1 1 0
                  0 3 3 3 3 0 1 0 1 0

www.qunxingw.wang
2013-01-17 12:20
jk333
Rank: 2
来 自:XX
等 级:论坛游民
帖 子:41
专家分:29
注 册:2009-10-29
得分:0 
看个了大概,继续加强学习进度

有了目标,有了方向,每天就少睡点吧!
2013-01-17 20:37
azzbcc
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江西财经大学
等 级:贵宾
威 望:81
帖 子:3293
专家分:12919
注 册:2012-11-4
得分:0 
恩,是没想仔细,应该把temp2数组全部置 0的


[fly]存在即是合理[/fly]
2013-01-18 21:56
yaobao
Rank: 13Rank: 13Rank: 13Rank: 13
等 级:蒙面侠
威 望:4
帖 子:1854
专家分:4121
注 册:2012-10-25
得分:0 
呵呵   ,此贴很火啊

认认真真的学习,踏踏实实的走路:戒骄戒躁!!!
2013-01-18 23:07
qunxingw
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:24
帖 子:1676
专家分:7295
注 册:2011-6-30
得分:0 
回复 26楼 azzbcc
我有个老同学,他处理牌有你相同的方法 我也还没细看,一起粘在此吧。
程序代码:
#include<iostream> 
using namespace std;
int main()
{
int i,x,flat=1;
    int b[14]={1,2,3,4,4,4,5,5,5,5,6,7,8,9};// 牌无需排序。

    int a[10]={0};
    for(i=0; i<14; i++)
    {
        a[b[i]-1]++;    //统计每种牌的数量
    }
    int xi,a2[10];
    for (x=0; x<10; x++)  //循环找一对将牌
    {
        for(i=0;i<10;i++)
            a2[i]=a[i];
        if(a2[x]>=2 )//,除掉将牌
        {
          a2[x]-=2;
        }
        else continue;
        xi=0;
        flat=1;
        for(i=0; i<10; i++)                     //找出连续或相同的三个数
        {
            if(a2[i]>=3)
            {
                a2[i]-=3;
                xi+=3;
            }
            if((a2[i]>0)&&(i>=8))
            {
                flat=0;
                break;
            }
            if(a2[i]==2)
               {
                   if((a2[i+1]>1)&&(a2[i+2]>1))
                   {
                       a2[i]-=2;
                       a2[i+1]-=2;
                       a2[i+2]-=2;
                   }
                   else
                   {
                       flat=0;
                       break;
                   }
               }
            else if(a2[i]==1)
               {
                   if((a2[i+1]>0)&&(a2[i+2]>0))
                   {
                       a2[i]--;
                       a2[i+1]--;
                       a2[i+2]--;
                   }
                   else
                   {
                       flat=0;
                       break;
                   }
               }
        }
        if(flat==1)
                   break;
   }
          if(flat)  cout<<"恭喜您!已胡牌!"<<endl;
          else     cout<<"对不起!不能胡牌!"<<endl;

    return 0;

}

www.qunxingw.wang
2013-01-18 23:17
azzbcc
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:江西财经大学
等 级:贵宾
威 望:81
帖 子:3293
专家分:12919
注 册:2012-11-4
得分:0 
回复 28楼 qunxingw
把修订版放这。
程序代码:
#include <math.h>
#include <stdio.h>
#include <string.h>

#define Copy(a, b) memcpy((void *)a, (void *)b, 40)

void initarray(int *a, int len, int *b, int mode)
{   //找到 b中不小于 mode的数,将其下标存入 a,a[0]是其个数
    memset(a, 0, len);

    for (int i = 1;i < 10;++i)
    {
        a[0] += b[i] >= mode;
        if (a[0] && !a[a[0]])
            a[a[0]] = i;
    }
}
int change(int *a, int flag[], int m)
{
    int n = 0;

    if (m & 1)    a[flag[1]] -= 3, ++n;
    if (m & 2)    a[flag[2]] -= 3, ++n;
    if (m & 4)    a[flag[3]] -= 3, ++n;
    if (m & 8)    a[flag[4]] -= 3, ++n;

    return n;
}
int find(int *a)
{
    for (int i = 1;i < 7;++i)
        if (a[i] && a[i+1] && a[i+2])
        {
            --a[i];--a[i+1];--a[i+2];
            return 1;
        }
   
    return 0;
}
int main()
{
    int i, j, m, n, flag = 0;
//  int a[10] = {0, 2, 1, 2, 2, 1, 2, 0, 2, 2};
//  int a[10] = {0, 2, 1, 2, 2, 1, 3, 0, 0, 3};
//  int a[10] = {0, 3, 0, 2, 2, 2, 2, 0, 0, 3};
//  int a[10] = {0, 2, 3, 2, 2, 2, 1, 1, 1, 0};
    int a[10] = {0, 3, 3, 3, 3, 0, 1, 0, 1, 0};
    int b[10], c[10], temp1[5], temp2[11];

    initarray(temp1, sizeof(temp1), a, 3);

    for (i = (int)pow(2, temp1[0]);i;--i)
    {
        Copy(b, a);
        m = change(b, temp1, i-1);
   
        initarray(temp2, sizeof(temp2), b, 2);
   
        for (j = temp2[0];j;--j)
        {
            Copy(c, b);c[temp2[j]] -= 2;
       
            n = 0;while (find(c))    ++n;
       
            if (4 == m+n){flag = 1;break;}
        }
   
        if (flag)    break;
    }
    if (flag)    puts("YES!");
    else         puts("NO!");

    return 0;
}
楼主的代码是还没改好吧,b数组没用到。想了一下应该是可以的,要加两个限定条件,有可能的将牌数 和 某处已被标记过,然后一次次把 b复制到 a就行。

至于楼上的代码,其实就是这个思路的实现,这样会有一个问题 1 2 2 3 3 3 4 4 5 这种,也就是说连续必须优先处理,,楼上代码就是这样做的。嗯,目前

对找 3个时 这个条件
程序代码:
if((a2[i]>0)&&(i>=8))
{
    flat=0;
    break;
}
表示疑惑,尚需努力啊!


[ 本帖最后由 azzbcc 于 2013-1-19 17:04 编辑 ]


[fly]存在即是合理[/fly]
2013-01-19 16:59
qunxingw
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:24
帖 子:1676
专家分:7295
注 册:2011-6-30
得分:0 
谢谢你的关注。19楼b数组大部分时候都用不上,从以前数据测试可以看出来。不过每次判断不胡牌时必竞修改了a数组的值。有时总是在最后选将时会出现错误。所以一不做二不休的,在后面如果不胡时,重新通过b还原a数组,以便选择下对将。

www.qunxingw.wang
2013-01-19 18:55



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-396597-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.507244 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved