日麻听牌分析器
话说我不知道多久之前就放言要做一个日麻的自动听牌分析器,但是这个“企划”刚冲我脑海中诞生就被我关进小黑屋了,原因一个字——懒,但是最近想起来这个东西了,就实现了一下,原因也就只有一个字——闲!!
好吧,说起来以前为什么会产生这个想法呢,还得追溯到我以前玩“东方幻想麻将”的时候【所以我说这个想法被我关了多久的小黑屋了。。。】,里面有一个模式,是出牌面,然后让你回答这副牌听什么,其中最高难度的牌,不仅散序,而且有可能是没有听的,好想你要在10分钟内判断12副牌吧,好像。。。然后最后那个其实要全对真的很难,好吧,或许是我那个时候比较鶸,现在先玩也懒得装了。。。
而且当时刚做了那个自动扫雷机不久,所以想到的就是截获游戏的界面,然后判断出题目,在自动判断出听牌的东西,但是基于图像处理的题目分析,想想就很烦,虽然不是不能做,但是我觉得后面那个判断逻辑更加有“思维含金量”,所以我还是做一下后面那个判断内核吧~
某人说了,你这个东西如果不是用于打《东方幻想麻将》,实际鸟笼天风或者实麻的时候,基本都是派不上用场的,但是我说,其实如果我想做一个日麻的AI,这个不就成为了AI的最基础的一个模块了么?嗯,如果,我说了如果。。。【还是不要随便乱立什么奇怪的flag的好。。】
嘛,虽然想想这个东西技术含量和实用性确实不强,还不如学学学校某位棍力十足的大牛写那个舍牌分析器,可以判断出怎么打可以让接下来的进章面最广~
好吧,其实也就是几个小时的产物,所以界面什么的,就别在意啦~
其实以前CSDN上有人发布过一个版本,【我会告诉你我软件的那些麻将图片就是那个里面偷来的!??】,当时我记得哪里说了这个版本不能分析七对子和国士无双,嘛~也没办法,谁让这两个役在所有役里面是最奇葩的两个呢?
我自己在写的时候,也发现很难把这两个役归入到一般的通用算法里面去,最后,经过我的不懈努力,我终于把七对子给搞进去了,所以真的要判断国士无双,那么就另外判别吧,虽然也很简单的说。。。但是我的软件里面也不能判断国士无双,原因有两个,第一,我不想为国士无双这种魂淡役满专门写一段判断程序,而且要写也真的很简单啊不是么?其次,我听牌结果里面只放了9个牌的位置,因为,根本没有给国士无双13面听机会!!
嘛~随便说说实现思路就算水了这篇文章吧,另外几个核心的代码放在最后面。。
嘛,也没啥好说的,一个麻将牌的类,里面指示了每张牌的数字和类型,字牌也统一进去了
然后面子类,只是某几张牌是顺子,还是刻子,还是对子,还是不完整的顺子(就是顺子缺一张),或者是某张单独的牌
然后就是牌面类,包含若干个面子
然后就是一个迭代啦~在待分析的13张牌里面每次选取出一个面子来,可以是上面所说的五种中的任意一种,然后把这几张牌标记为不可用,然后继续迭代,知道足以判断听牌为止,再返回听牌的值。
标记结果我采用的是一个unsigned long int量就可以了,虽然位数很多,但是我只用其中的34位,每次一种牌面算出听的牌,就把对应的位置1,然后返回,每次迭代都和之前的结果做位或运算,这样就可以避免重复的了。。。
反正,大概如此。。。不明白的就自己yy脑部一下啦~【我才不会告诉你我是为了赶着去打天凤才随便写写的。。】
【完】
本文内容遵从CC版权协议,转载请注明出自http://www.kylen314.com
Majong_Card.h
#pragma once #define TYPE_UNKNOWN -1 #define WAN 1 #define TIAO 2 #define BING 3 #define DONG 4 #define NAN 5 #define XI 6 #define BEI 7 #define ZHONG 8 #define FA 9 #define BAI 10 class CMajong_Card { public: CMajong_Card(int num,int type):Num(num),Type(type){}; CMajong_Card(void); ~CMajong_Card(void); CMajong_Card & operator=(const CMajong_Card &t1){ Num = t1.Num; Type = t1.Type; return *this; } unsigned long int GetIdx(); int Num; int Type; };
Majong_Card.cpp
#include "StdAfx.h" #include "Majong_Card.h" CMajong_Card::CMajong_Card(void) { Type = TYPE_UNKNOWN; } CMajong_Card::~CMajong_Card(void) { } unsigned long int CMajong_Card::GetIdx() { if (WAN == Type) { return 0x01< <(Num-1); } else if(TIAO == Type) { return 0x01<<(Num-1+9); } else if(BING == Type) { return 0x01<<(Num-1+18); } else { return 0x01<<(Type-DONG+27); } return 0; }
Majong_Analyse.h
#pragma once #include "Majong_Card.h" #include "PaiMian.h" #define CARD_USED 1 #define CARD_UNUSED 0 class CMajong_Analyse { public: CMajong_Card pool[13]; CMajong_Card result[13]; CMajong_Analyse(void); ~CMajong_Analyse(void); void NewSort(); void Analyse(); void Zuhe(int Card_Used[],CPaiMian paimian,int num1,int num2,int num3,int mianzi_type); int FindCard(CMajong_Card _dst_card,int Card_Used[],int mask1,int mask2); int FindDudiao(int Card_Used[]); static unsigned long int TingPaiResult; };
Majong_Analyse.cpp
#include "StdAfx.h" #include "Majong_Analyse.h" unsigned long int CMajong_Analyse::TingPaiResult = 0; CMajong_Analyse::CMajong_Analyse(void) { } CMajong_Analyse::~CMajong_Analyse(void) { } /* 平和 | 斷么九 | 一盃口 | 役牌 三色同順 | 一氣通貫 | 混全帶么九 | 七對子 | 對對和 | 三暗刻 三色同刻 | 混老頭 | 小三元 | 混一色 | 純全帶么九 | 二杯口 清一色 國士無雙 | 四暗刻 | 大三元 | 小四喜 | 大四喜 | 字一色 | 綠一色 | 清老頭 | 九蓮寶燈 | 形听 */ void CMajong_Analyse::Analyse() { NewSort();//排序 //标记已经被用的牌 int Card_Used[13] = {CARD_UNUSED}; CPaiMian paimian; for(int i = 0;i < 13;i++) { Card_Used[i] = CARD_UNUSED; } TingPaiResult = 0;//初始化听牌结果 Zuhe(Card_Used,paimian,-1,-1,-1,-1);//第一次调用参数全部用-1 } //按类型排序 W->S->P->F->SY void CMajong_Analyse::NewSort() { CMajong_Card temp[13]; int idx = 0; for(int c_type = WAN;c_type < BAI;c_type++) { if(c_type < DONG) { for(int i = 1;i <= 9;i++) { for (int k = 0;k < 13;k++) { if(pool[k].Type == c_type && pool[k].Num == i) { temp[idx++] = pool[k]; } } } } else { for (int k = 0;k < 13;k++) { if(pool[k].Type == c_type) { temp[idx++] = pool[k]; } } } } for(int i = 0;i < 13;i++) { pool[i] = temp[i]; } } //递归组合面子 void CMajong_Analyse::Zuhe(int Card_Used[],CPaiMian paimian,int num1,int num2,int num3,int mianzi_type) { if(num1 >= 0 && num2 >= 0) { paimian.mianzi[paimian.Cur_Idx].Card[0] = pool[num1]; Card_Used[num1] = CARD_USED; paimian.mianzi[paimian.Cur_Idx].Card[1] = pool[num2]; Card_Used[num2] = CARD_USED; paimian.mianzi[paimian.Cur_Idx].type = mianzi_type; if (num3 >= 0) { paimian.mianzi[paimian.Cur_Idx].Card[2] = pool[num3]; Card_Used[num3] = CARD_USED; } paimian.Total_num += 2+(num3>=0); paimian.Cur_Idx++; int idx_dudiao = -1; if(paimian.Total_num == 12)//只剩一张牌 { idx_dudiao = FindDudiao(Card_Used); if(idx_dudiao != -1) { paimian.mianzi[paimian.Cur_Idx].Card[0] = pool[idx_dudiao]; Card_Used[idx_dudiao] = CARD_USED; paimian.mianzi[paimian.Cur_Idx].type = DUDIAO; paimian.Cur_Idx++; paimian.Total_num++; } } TingPaiResult |= paimian.Analyse(); if(paimian.Total_num == 13) { if(idx_dudiao != -1) Card_Used[idx_dudiao] = CARD_UNUSED; return; } } int Next_Card_id; int Next_Next_Card_id; for(int i = 0;i < 13;i++) { if(CARD_UNUSED == Card_Used[i]) { //顺子 Next_Card_id = FindCard(CMajong_Card(pool[i].Num+1,pool[i].Type),Card_Used,i,-1); Next_Next_Card_id = FindCard(CMajong_Card(pool[i].Num+2,pool[i].Type),Card_Used,i,Next_Card_id); if(Next_Card_id >= 0 && Next_Next_Card_id >= 0) { Zuhe( Card_Used, paimian, i, Next_Card_id, Next_Next_Card_id, SHUNZI); Card_Used[i] = CARD_UNUSED; Card_Used[Next_Card_id] = CARD_UNUSED; Card_Used[Next_Next_Card_id] = CARD_UNUSED; } //刻子 Next_Card_id = FindCard(CMajong_Card(pool[i].Num,pool[i].Type),Card_Used,i,-1); Next_Next_Card_id = FindCard(CMajong_Card(pool[i].Num,pool[i].Type),Card_Used,i,Next_Card_id); if(Next_Card_id >= 0 && Next_Next_Card_id >= 0) { Zuhe( Card_Used, paimian, i, Next_Card_id, Next_Next_Card_id, KEZI); Card_Used[i] = CARD_UNUSED; Card_Used[Next_Card_id] = CARD_UNUSED; Card_Used[Next_Next_Card_id] = CARD_UNUSED; } //雀头 Next_Card_id = FindCard(CMajong_Card(pool[i].Num,pool[i].Type),Card_Used,i,-1); if(Next_Card_id >= 0) { Zuhe( Card_Used, paimian, i, Next_Card_id, -1, QUETOU); Card_Used[i] = CARD_UNUSED; Card_Used[Next_Card_id] = CARD_UNUSED; } //顺子缺一张 Next_Card_id = FindCard(CMajong_Card(pool[i].Num+1,pool[i].Type),Card_Used,i,-1); Next_Next_Card_id = FindCard(CMajong_Card(pool[i].Num+2,pool[i].Type),Card_Used,i,Next_Card_id); if(Next_Card_id >= 0 && Next_Next_Card_id < 0) { Zuhe( Card_Used, paimian, i, Next_Card_id, -1, QUEZHANG); Card_Used[i] = CARD_UNUSED; Card_Used[Next_Card_id] = CARD_UNUSED; } else if(Next_Card_id < 0 && Next_Next_Card_id >= 0) { Zuhe( Card_Used, paimian, i, Next_Next_Card_id, -1, QUEZHANG); Card_Used[i] = CARD_UNUSED; Card_Used[Next_Next_Card_id] = CARD_UNUSED; } } } } //查找指定的CMajong_Card所在的位置 int CMajong_Analyse::FindCard( CMajong_Card dst_card,int Card_Used[],int mask1,int mask2) { int result = -1; for(int i = 0;i < 13;i++) { if(mask1 != i && mask2 != i && Card_Used[i] == CARD_UNUSED && pool[i].Num == dst_card.Num && pool[i].Type == dst_card.Type) return i; } return result; } //查找仅剩的一张还没被列入组合的牌 int CMajong_Analyse::FindDudiao( int Card_Used[] ) { for(int i = 0;i < 13;i++) { if(Card_Used[i] == CARD_UNUSED) { return i; } } return -1; }
PaiMian.h
#pragma once #include "MianZi.h" #include "PaiMian.h" class CPaiMian { public: CMianZi mianzi[7]; int Cur_Idx; int Total_num; unsigned long int Analyse(); int GetQuezhang(); int GetTypeNum(int MianziType); unsigned long int duipeng(); unsigned long int qiduizi(); unsigned long int dudiao(); unsigned long int changgui(); CPaiMian(void); ~CPaiMian(void); };
PaiMian.cpp
#include "StdAfx.h" #include "PaiMian.h" CPaiMian::CPaiMian(void) { Cur_Idx = 0; Total_num = 0; } CPaiMian::~CPaiMian(void) { } unsigned long int CPaiMian::Analyse() { unsigned long int result = 0; //组合牌数少于12,不可能呈听牌形式 if(Total_num < 12) return 0; int quezhang_num = GetTypeNum(QUEZHANG); //多于1个没完成的顺子,不可能听牌 if(quezhang_num > 1) return 0; int quetou_num = GetTypeNum(QUETOU); //3,4,5个对子,不可能听牌 if(quetou_num >=3 && quetou_num < 6) return 0; //不可能同时听独钓,双鹏,七对子,嵌章,偏听等情况 if((2 == quetou_num)+(6 == quetou_num)+(0 == quetou_num)+(1 == quezhang_num)>1) return 0; if(2 == quetou_num)//对对碰 result = duipeng(); else if(6 == quetou_num)//七对子 result = qiduizi(); else if(0 == quetou_num)//独钓 result = dudiao(); else if(1 == quezhang_num)//顺子不完整 result = changgui(); // CString str = ""; // for(int i = 0;i < Cur_Idx;i++) // { // if(mianzi[i].type == SHUNZI) // str.Format("%s顺子:",str); // else if(mianzi[i].type == KEZI) // str.Format("%s刻子:",str); // else if(mianzi[i].type == QUETOU) // str.Format("%s对子:",str); // else if(mianzi[i].type == QUEZHANG) // str.Format("%s缺章:",str); // else if(mianzi[i].type == DUDIAO) // str.Format("%s独钓:",str); // else // str.Format("%s未知:",str); // for(int j = 0;j < 3;j++) // { // if(mianzi[i].Card[j].Type != TYPE_UNKNOWN) // { // if(mianzi[i].Card[j].Type == WAN) // str.Format("%s %dW",str,mianzi[i].Card[j].Num); // else if(mianzi[i].Card[j].Type == TIAO) // { // str.Format("%s %dS",str,mianzi[i].Card[j].Num); // // }else if(mianzi[i].Card[j].Type == BING) // str.Format("%s %dP",str,mianzi[i].Card[j].Num); // else // str.Format("%s %d",str,mianzi[i].Card[j].Type-DONG); // } // } // str.Format("%s\n",str); // } // // str.Format("%s听牌:\n\n",str); // for(int i = 0;i < 34;i++) // { // if(result & 0x01<<i) // { // if(i < 9) // str.Format("%s %dW",str,i+1); // else if(i < 18) // { // str.Format("%s %dS",str,i+1-9); // }else if(i < 27) // str.Format("%s %dP",str,i+1-18); // else // str.Format("%s %d",str,i+1-27); // } // } // AfxMessageBox(str); return result; } int CPaiMian::GetTypeNum( int MianziType ) { int counter = 0; for(int i = 0;i < Cur_Idx;i++) { if(mianzi[i].type == MianziType) { counter++; } } return counter; } unsigned long int CPaiMian::duipeng() { unsigned long int result = 0x00; for(int i = 0;i < Cur_Idx;i++) { if(mianzi[i].type == QUETOU) result |= mianzi[i].Card[0].GetIdx(); } return result; } unsigned long int CPaiMian::qiduizi() { unsigned long int result = 0x00; for(int i = 0;i < Cur_Idx;i++) { if(mianzi[i].type == DUDIAO) result |= mianzi[i].Card[0].GetIdx(); } return result; } unsigned long int CPaiMian::dudiao() { unsigned long int result = 0x00; for(int i = 0;i < Cur_Idx;i++) { if(mianzi[i].type == DUDIAO) result |= mianzi[i].Card[0].GetIdx(); } return result; } //顺子缺一张 unsigned long int CPaiMian::changgui() { unsigned long int result = 0x00; for(int i = 0;i < Cur_Idx;i++) { if(mianzi[i].type == QUEZHANG) { if (2 == mianzi[i].Card[1].Num-mianzi[i].Card[0].Num) { result |= CMajong_Card(mianzi[i].Card[0].Num+1,mianzi[i].Card[0].Type).GetIdx(); return result; } else if(1 == mianzi[i].Card[0].Num) { result |= CMajong_Card(3,mianzi[i].Card[0].Type).GetIdx(); return result; } else if(8 == mianzi[i].Card[0].Num) { result |= CMajong_Card(7,mianzi[i].Card[0].Type).GetIdx(); return result; } else { result |= CMajong_Card(mianzi[i].Card[0].Num-1,mianzi[i].Card[0].Type).GetIdx(); result |= CMajong_Card(mianzi[i].Card[1].Num+1,mianzi[i].Card[0].Type).GetIdx(); return result; } } } return result; }
MianZi.h
#pragma once #include "Majong_Card.h" #define SHUNZI 1 #define KEZI 2 #define QUETOU 3 #define QUEZHANG 4 #define DUDIAO 5 class CMianZi { public: CMajong_Card Card[3]; int type; CMianZi(void); ~CMianZi(void); };
MianZi.cpp
#include "StdAfx.h" #include "MianZi.h" CMianZi::CMianZi(void) { for(int i = 0;i < 3;i++) { Card[i].Type = TYPE_UNKNOWN; } } CMianZi::~CMianZi(void) { }
MajongDlg.h
// MajongDlg.h : 头文件 // #pragma once #include "Majong_Analyse.h" const int Table_IDC[34] = { IDC_PIC1,IDC_PIC2,IDC_PIC3,IDC_PIC4,IDC_PIC5,IDC_PIC6,IDC_PIC7, IDC_PIC8,IDC_PIC9,IDC_PIC10,IDC_PIC11,IDC_PIC12,IDC_PIC13,IDC_PIC14, IDC_PIC15,IDC_PIC16,IDC_PIC17,IDC_PIC18,IDC_PIC19,IDC_PIC20,IDC_PIC21, IDC_PIC22,IDC_PIC23,IDC_PIC24,IDC_PIC25,IDC_PIC26,IDC_PIC27,IDC_PIC28, IDC_PIC29,IDC_PIC30,IDC_PIC31,IDC_PIC32,IDC_PIC33,IDC_PIC34 }; const int MajongPool_IDC[13] = { IDC_PIC35,IDC_PIC36,IDC_PIC37,IDC_PIC38,IDC_PIC39,IDC_PIC40,IDC_PIC41, IDC_PIC42,IDC_PIC43,IDC_PIC44,IDC_PIC45,IDC_PIC46,IDC_PIC47 }; const int MajongResult_IDC[13] = { IDC_PIC48,IDC_PIC49,IDC_PIC50,IDC_PIC51,IDC_PIC52,IDC_PIC53,IDC_PIC54,IDC_PIC55,IDC_PIC56 }; // CMajongDlg 对话框 class CMajongDlg : public CDialog { // 构造 public: CMajongDlg(CWnd* pParent = NULL); // 标准构造函数 void DrawJPG(int nID,char* pic_path ); void ShowTable(); void ShowCardPool(); void SetResult(); void ShowResult(); CMajong_Card pool[13]; CMajong_Card tp_result[9]; // 对话框数据 enum { IDD = IDD_MAJONG_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnStnClickedTablePic(UINT uID); afx_msg void OnStnClickedPoolPic(UINT uID); afx_msg void OnBnClickedBeginAnalyse(); afx_msg void OnBnClickedClearall(); };
MajongDlg.cpp
// MajongDlg.cpp : 实现文件 // #include "stdafx.h" #include "Majong.h" #include "MajongDlg.h" #include <afx.h> #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CMajongDlg 对话框 CMajongDlg::CMajongDlg(CWnd* pParent /*=NULL*/) : CDialog(CMajongDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMajongDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMajongDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_CONTROL_RANGE(STN_CLICKED,IDC_PIC1,IDC_PIC34,OnStnClickedTablePic) ON_CONTROL_RANGE(STN_CLICKED,IDC_PIC35,IDC_PIC47,OnStnClickedPoolPic) ON_BN_CLICKED(IDC_BEGIN_ANALYSE, &CMajongDlg::OnBnClickedBeginAnalyse) ON_BN_CLICKED(IDC_ClEARALL, &CMajongDlg::OnBnClickedClearall) END_MESSAGE_MAP() // CMajongDlg 消息处理程序 BOOL CMajongDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 for(int i = 0;i < 34;i++) { GetDlgItem(Table_IDC[i])->ModifyStyle(0,SS_NOTIFY); } for(int i = 0;i < 13;i++) { GetDlgItem(MajongPool_IDC[i])->ModifyStyle(0,SS_NOTIFY); } for(int i = 0;i < 13;i++) { pool[i].Type = TYPE_UNKNOWN; pool[i].Num = TYPE_UNKNOWN; } return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMajongDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMajongDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } /*CDC* pDC = GetDC(); CDC MemDC; CRect rect; GetWindowRect(&rect); int nWidth = rect.Width(); int nHeight = rect.Height(); CBitmap MemBitmap; MemDC.CreateCompatibleDC(NULL); MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); ShowTable(&MemDC); ShowCardPool(&MemDC); pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); MemBitmap.DeleteObject(); MemDC.DeleteDC();*/ ShowTable(); ShowCardPool(); ShowResult(); int idx = -1; for(int i = 0;i < 13;i++) { if (pool[i].Type == TYPE_UNKNOWN) { idx = i; break; } } CButton* Analyse_Button = (CButton*)GetDlgItem(IDC_BEGIN_ANALYSE); Analyse_Button->EnableWindow(-1==idx); } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMajongDlg::OnQueryDragIcon() { return static_cast<hcursor>(m_hIcon); } void CMajongDlg::DrawJPG(int nID,char* pic_path ) { if (!pic_path) return; CDC *pDC = this->GetDC(); CRect rect; //CDC memDC; GetDlgItem(nID)->GetWindowRect(&rect); GetDlgItem(nID)->GetParent()->ScreenToClient(rect); //memDC.CreateCompatibleDC(NULL); CoInitialize(NULL); // COM 初始化 CFile file; // 读入文件内容 file.Open(pic_path,CFile::modeRead | CFile::shareDenyNone); //获取长度 DWORD dwSize = DWORD(file.GetLength()); //给图片分配全局内存 HGLOBAL hMem = GlobalAlloc( GMEM_MOVEABLE, dwSize ); //锁定内存 LPVOID lpBuf = GlobalLock( hMem ); //读取图片到全局内存当中 file.Read( lpBuf, dwSize ); //关闭文件 file.Close(); //解锁内存 GlobalUnlock( hMem ); //IStream接口指针,用来保存图片流 IStream* pStream = NULL; //图片对象 IPicture* pPicture = NULL; //由HGLOBAL得到IStream,参数TRUE表示释放IStream的同时,释放内存 HRESULT hr; //用全局内存初使化IStream接口指针 hr = CreateStreamOnHGlobal( hMem, TRUE, &pStream );//ASSERT ( SUCCEEDED(hr) ); //得到IPicture COM接口对象 hr = OleLoadPicture( pStream, dwSize, TRUE, IID_IPicture, ( LPVOID * )&pPicture ); //ASSERT(hr==S_OK); long nWidth,nHeight; //MM_HIMETRIC 模式 单位是0.01毫米 pPicture->get_Width( &nWidth ); pPicture->get_Height( &nHeight ); ////////原大显示////// CSize sz( nWidth, nHeight ); //转换MM_HIMETRIC到MM_TEXT像素单位 pDC->HIMETRICtoDP( &sz ); //控件大小变成图片大小 //GetDlgItem(IDC_PIC1)->MoveWindow(rect.left,rect.top,sz.cx,sz.cy); //左上角那个点对齐 //pPicture->Render(pDC->m_hDC,rect.left,rect.top,sz.cx,sz.cy, // 0,nHeight,nWidth,-nHeight,NULL); //图片缩放至空间大小 pPicture->Render(pDC->m_hDC,rect.left,rect.top,rect.Width(),rect.Height(), 0,nHeight,nWidth,-nHeight,NULL); if (pPicture) pPicture->Release(); if (pStream) pStream->Release(); //pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY); //this->ReleaseDC(pDC); //memDC.DeleteDC(); CoUninitialize(); } void CMajongDlg::ShowTable() { char* path = new char[1024]; for(int i = 0;i < 34;i++) { if (i < 9) { sprintf(path,"./image/m%d.JPG",i+1); DrawJPG(Table_IDC[i],path); } else if(i < 18) { sprintf(path,"./image/t%d.JPG",i+1-9); DrawJPG(Table_IDC[i],path); } else if(i < 27) { sprintf(path,"./image/w%d.JPG",i+1-18); DrawJPG(Table_IDC[i],path); } else if(i < 31) { sprintf(path,"./image/zf%d.JPG",i+1-27); DrawJPG(Table_IDC[i],path); } else { sprintf(path,"./image/zj%d.JPG",i+1-31); DrawJPG(Table_IDC[i],path); } } } void CMajongDlg::OnStnClickedTablePic(UINT uID) { //找到牌池中未知的那个位置 int idx = -1; for(int i = 0;i < 13;i++) { if (pool[i].Type == TYPE_UNKNOWN) { idx = i; break; } } if(idx == -1) return; //条子 if(uID >= Table_IDC[0] && uID < Table_IDC[9]) { pool[idx].Num = uID - Table_IDC[0]+1; pool[idx].Type = TIAO; } else if(uID >= Table_IDC[9] && uID < Table_IDC[18]) { pool[idx].Num = uID - Table_IDC[9]+1; pool[idx].Type = BING; } else if(uID >= Table_IDC[18] && uID < Table_IDC[27]) { pool[idx].Num = uID - Table_IDC[18]+1; pool[idx].Type = WAN; } else { pool[idx].Type = DONG + uID - Table_IDC[27]; pool[idx].Num = 0; } //Invalidate(TRUE); CRect rect; GetDlgItem(MajongPool_IDC[idx])->GetWindowRect(&rect); GetDlgItem(MajongPool_IDC[idx])->GetParent()->ScreenToClient(rect); InvalidateRect(&rect); } void CMajongDlg::ShowCardPool() { char* path = new char[1024]; for(int i = 0;i < 13;i++) { if (pool[i].Type == TYPE_UNKNOWN) continue; else switch (pool[i].Type) { case TIAO: sprintf(path,"./image/m%d.JPG",pool[i].Num); break; case BING: sprintf(path,"./image/t%d.JPG",pool[i].Num); break; case WAN: sprintf(path,"./image/w%d.JPG",pool[i].Num); break; case DONG: case NAN: case XI: case BEI: sprintf(path,"./image/zf%d.JPG",pool[i].Type - DONG + 1); break; case ZHONG: case FA: case BAI: sprintf(path,"./image/zj%d.JPG",pool[i].Type - ZHONG + 1); break; default: return; } DrawJPG(MajongPool_IDC[i],path); } } void CMajongDlg::OnBnClickedBeginAnalyse() { // TODO: 在此添加控件通知处理程序代码 CMajong_Analyse Analyse; for(int i = 0;i < 13;i++) { Analyse.pool[i] = pool[i]; } Analyse.Analyse(); SetResult(); Invalidate(TRUE); } void CMajongDlg::OnStnClickedPoolPic( UINT uID ) { pool[uID-IDC_PIC35].Type = TYPE_UNKNOWN; CRect rect; GetDlgItem(MajongPool_IDC[uID-IDC_PIC35])->GetWindowRect(&rect); GetDlgItem(MajongPool_IDC[uID-IDC_PIC35])->GetParent()->ScreenToClient(rect); InvalidateRect(&rect); } void CMajongDlg::ShowResult() { char* path = new char[1024]; for(int i = 0;i < 9;i++) { if (tp_result[i].Type == TYPE_UNKNOWN) continue; else switch (tp_result[i].Type) { case TIAO: sprintf(path,"./image/m%d.JPG",tp_result[i].Num); break; case BING: sprintf(path,"./image/t%d.JPG",tp_result[i].Num); break; case WAN: sprintf(path,"./image/w%d.JPG",tp_result[i].Num); break; case DONG: case NAN: case XI: case BEI: sprintf(path,"./image/zf%d.JPG",tp_result[i].Type - DONG + 1); break; case ZHONG: case FA: case BAI: sprintf(path,"./image/zj%d.JPG",tp_result[i].Type - ZHONG + 1); break; default: return; } DrawJPG(MajongResult_IDC[i],path); } } void CMajongDlg::SetResult() { for(int i = 0;i < 9;i++) { tp_result[i].Type = TYPE_UNKNOWN; } int cc = 0; for(int i = 0;i < 34;i++) { if(CMajong_Analyse::TingPaiResult & 0x01<<i) { if(i < 9) { tp_result[cc].Num = i+1; tp_result[cc].Type = WAN; } else if(i < 18) { tp_result[cc].Num = i+1-9; tp_result[cc].Type = TIAO; } else if(i < 27) { tp_result[cc].Num = i+1-18; tp_result[cc].Type = BING; } else { tp_result[cc].Num = 0; tp_result[cc].Type = i-27+DONG; } cc++; } } } void CMajongDlg::OnBnClickedClearall() { // TODO: 在此添加控件通知处理程序代码 for(int i = 0;i < 9;i++) { tp_result[i].Type = TYPE_UNKNOWN; } for(int i = 0;i < 13;i++) { pool[i].Type = TYPE_UNKNOWN; } Invalidate(TRUE); }