仲 恺 农 业 工 程 学 院
课 程 设 计 报 告
课程名称: 数据结构
院(系):计算机科学与工程
专 业:计算机科学与技术
班 级: 计算机102班
学 号:
姓 名:
指导老师:
目 录
题目
(一) 需求和规格说明:问题描述,即题目要解决的问题是什么
(二) 算法设计(包括程序流程图,如函数功能、入口及出口参数说明,函数调用关系描述等)
(三) 详细设计(源程序清单,要包括足够的注释)
(四) 调试分析(包括调试数据与调试结果)
(五) 课程设计总结(包括程序中遇到的问题及解决方案,以及课程设计收获)
题目
斗地主游戏(简单版)
(一) 需求和规格说明:问题描述,即题目要解决的问题是什么
系统基本要求:
具备基本的界面形式及操作功能
具备基本的AI能力
解决问题:
(1) 以MFC作为程序框架
(2) 图片以位图的形式出现,并进行基本的界面操作
(3) 以链表及广义表等形式(C++封装好的),进行数据的操作
(4) 设计了简单的AI函数,用以对游戏的进行,判断等
(二) 算法设计(包括程序流程图,如函数功能、入口及出口参数说明,函数调用关系描述等)
(三) 详细设计(源程序清单,要包括足够的注释)
斗地主游戏(简单版)源程序(部分)如下:
注:由于具体框架为程序自主产生,在这里不再出现,只列出View类函数,程序中绿色程序代码为实验中出错的部分或者验证部分
// 试验品View.cpp : C试验品View 类的实现
//
#include "stdafx.h"
#include "试验品.h"
#include "试验品Doc.h"
#include "试验品View.h"
#include"algorithm"
#include"Ctime"
#include"vector"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// C试验品View
IMPLEMENT_DYNCREATE(C试验品View, CView)
BEGIN_MESSAGE_MAP(C试验品View, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_WM_CREATE()
ON_BN_CLICKED(IDB_BUTTON1,OnButton1Clicked)
ON_BN_CLICKED(IDB_BUTTON2,OnButton2Clicked)
END_MESSAGE_MAP()
// C试验品View 构造/析构
C试验品View::C试验品View()
: m_point(0)
, width(0)
, height(0)
, x_machine(0)
, current_player(0)
{
// TODO: 在此处添加构造代码
for(int j=0;j<20;j++)
{
m_key[j]=j+1;
}
for(int i=3;i<16;i++)
{
for(int j=0;j<4;j++)
vec.push_back(i);
}
vec.push_back(53);
vec.push_back(54);
srand(time(0));
random_shuffle(vec.begin(),vec.end());
vec1.assign(vec.begin(),vec.begin()+17);
vec2.assign(vec.begin()+17,vec.begin()+34);
vec_game.assign(vec.begin()+34,vec.end());
std::sort(vec1.begin(),vec1.end());
std::sort(vec2.begin(),vec2.end());
std::sort(vec_game.begin(),vec_game.end());
v1=vec1;
v2=vec2;
v_game=vec_game;
}
C试验品View::~C试验品View()
{
}
BOOL C试验品View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
//左键点击
void C试验品View::OnLButtonDown(UINT nFlags,CPoint point) {
m_point=point;
InvalidateRect(FALSE);//传递窗口重绘的消息该OnDraw()
CView::OnLButtonDown(nFlags,point);
}
// C试验品View 绘制
void C试验品View::OnDraw(CDC* pDC)
{
C试验品Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CRect rcWksMng;
this->GetWindowRect(rcWksMng);
height=rcWksMng.bottom-rcWksMng.top;//得到当前窗口大小,当时为什么位图大小无法改变
width=rcWksMng.right-rcWksMng.left;
CDC MemDC;
MemDC.CreateCompatibleDC(NULL);
MemDC.SelectObject(pDoc->m_Beijing);
pDC->StretchBlt(0,0,width,height,&MemDC,0,0,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
//按照第一二参数为原点坐标,第三四为变化后的宽高,第四为文件句柄指针,后面是原来的
//在OnDraw中可以直接用pDC,但是在其他呢??
MemDC.SelectObject(pDoc->m_Bitmap);
int width0=width/25;
int height0=height/25;
pDC->SetStretchBltMode(COLORONCOLOR);//防止失色
for(int i=0;i
{
pDC->StretchBlt(width0,height-7*height0-i*height0,3*width0,3*height0,&MemDC,0,0,
pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
for(int i=0;i
{
pDC->StretchBlt(width-4*width0,height-7*height0-i*height0,3*width0,3*height0,&MemDC,0,0,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
int t=0,i=0,j=0,k=0;;
std::vector B_m;
//CBitmap 数组为什么无法相互赋值,而list,vector类型的确需要指针呢
for(std::vector::reverse_iterator riter=vec_game.rbegin();riter!=vec_game.rend();riter++)
{//游戏方牌组所对应的CBitmap值
if(*riter<16)
{
if(t==*riter)
++i;
else
i=0;
j=*riter-3+i*13;
}
else
{
j=*riter-1;
}
B_m.push_back((pDoc->m)+j);
t=*riter;
}
int p=JudgeRect(m_point);
if(p!=-1)//点击桌面的牌牌时,促使弹起
{
for(i=0;i
{
MemDC.SelectObject(*(B_m[i]));
if(m_np[i]!=1)//不要写==0,因为原来m_np[i]没有赋值为随意不为零的数
pDC->StretchBlt(2*width0+i*width0,height-3*height0,3*width0,3*height0,&MemDC,0,0
,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
else
pDC->StretchBlt(2*width0+i*width0,height-4*height0,3*width0,3*height0,&MemDC,0,0
,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
}
else
{
for(i=0;i
{
MemDC.SelectObject(*(B_m[i]));
pDC->StretchBlt(2*width0+i*width0,height-3*height0,3*width0,3*height0,&MemDC,0,0
,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
if(i!=B_m.size()-1)
{
CRectr(2*width0+i*width0,height-3*height0,2*width0+(i+1)*width0
,height-3*height0+pDoc->m_nHeight);
rect[i]=r;
}
else
{
CRectr(2*width0+i*width0,height-3*height0,2*width0+i*width0+pDoc->m_nWidth
,height-3*height0+pDoc->m_nHeight);
rect[i]=r;
}
}
for(i=0;i<20;i++)
{
m_np[i]=0;
}
}
//表示出所出的牌到桌面上
t=0,i=0,j=0,k=0;;
std::vector BB_m;
//CBitmap 数组为什么无法相互赋值,而list,vector类型的确需要指针呢
for(std::vector::reverse_iterator riter=vec_chu.rbegin();riter!=vec_chu.rend();riter++)
{//游戏方所出得牌组所对应的CBitmap值
if(*riter<16)
{
if(t==*riter)
++i;
else
i=0;
j=*riter-3+i*13;
}
else
{
j=*riter-1;
}
BB_m.push_back((pDoc->m)+j);
t=*riter;
}
for(i=0;i
{
MemDC.SelectObject(*(BB_m[i]));
pDC->StretchBlt(5*width0+i*width0,height-7*height0,3*width0,3*height0,&MemDC
,0,0,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
if(x_machine!=0)
//之所以把current_player=1或者后的操作写在外面,是因为,当鼠标点击到飞按钮区域时图片依然存在
{
std::multimap mp_machine,pm_machine,mmpp,ppmm;
std::multimap::size_type st;
std::multimap::iterator iter_machine;
if(current_player==1)
{
transition(mp_machine,pm_machine,vec1);
vcc.clear();//需要消去原来的元素,避免元素叠加
machine(vec1,mp_machine,pm_machine);
}
else
{
transition(mp_machine,pm_machine,vec2);
vcc.clear();
machine(vec2,mp_machine,pm_machine);
}
transition(mmpp,ppmm,vcc);
judge_game(mmpp,ppmm,vcc);
x_machine=0;
}
if(current_player==1)//当一比二先下时的情况,包含接下来得二所要下的形式
{
std::vector B_m1;
//CBitmap 数组为什么无法相互赋值,而list,vector类型的确需要指针呢
i=3;
for(std::vector::reverse_iterator riter=vcc.rbegin();riter!=vcc.rend();riter++)
{//游戏方牌组所对应的CBitmap值
if(*riter<16)
{
if(t==*riter)
--i;
else
i=3;
j=*riter-3+i*13;
}
else
{
j=*riter-1;
}
B_m1.push_back((pDoc->m)+j);
t=*riter;
}
for(i=0;i
{
MemDC.SelectObject(*(B_m1[i]));
pDC->StretchBlt(5*width0+i*width0,height-11*height0,3*width0,3*height0,&MemDC
,0,0,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
//以下是,机器一后,判断机器二是否有下,如果有则进行处理,可以加入更多的只能
std::map c;
c=Brand_size.begin()->first;
int x=c.begin()->first;
int y=c.begin()->second;
int z=Brand_size.begin()->second;
int xx=0;
std::multimap mmm,ppp;
transition(mmm,ppp,vec2);
xx=continuation(mmm,z,y,x);//表示机器二是否有牌
if(xx==0)
current_player=1;//当二下次无法找到牌时,就在桌面上保持一的存在
else
current_player=2;
if(xx!=0)
{
if((x==1&&vec2.size()<3)||(x==2&&vec2.size()<5)||(x==1&&z<14&&vec2.size()>2)
||(x==2&&z<12&&vec2.size()>4))
{
std::multimap mp_machine,pm_machine,mmpp,ppmm;
std::multimap::size_type st;
std::multimap::iterator iter_machine;
transition(mp_machine,pm_machine,vec2);
vcc.clear();
machine(vec2,mp_machine,pm_machine);
//功能是除去vec2中的元素到vcc中作为图片载入的依据
transition(mmpp,ppmm,vcc);
judge_game(mmpp,ppmm,vcc);//改变Brand_size的数值,保持与当时下牌方一致
}
}
}
if(current_player==2)//二下牌后的图片显示
{
std::vector B_m1;
//CBitmap 数组为什么无法相互赋值,而list,vector类型的确需要指针呢
i=3;
//因为时间缘故,且不知道怎么判断花色,所以就直接的玩家下的牌就从前面顺序在m[]中找出CBitmap而两个机器就直接从后面算起,所以i=3;
for(std::vector::reverse_iterator riter=vcc.rbegin();riter!=vcc.rend();riter++)
{//游戏方牌组所对应的CBitmap值
if(*riter<16)
{
if(t==*riter)
--i;
else
i=3;
j=*riter-3+i*13;
}
else
{
j=*riter-1;
}
B_m1.push_back((pDoc->m)+j);
t=*riter;
}
for(i=0;i
{
MemDC.SelectObject(*(B_m1[i]));
pDC->StretchBlt(5*width0+i*width0,height-15*height0,3*width0,3*height0,&MemDC
,0,0,pDoc->m_nWidth,pDoc->m_nHeight,SRCCOPY);
}
current_player=2;
//使得机器二能够在桌面上保持显示,直到二没有牌下,也作为玩家不要时,下牌者的判断依据
}
// TODO: 在此处为本机数据添加绘制代码
}
// C试验品View 打印
BOOL C试验品View::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void C试验品View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void C试验品View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清除过程
}
// C试验品View 诊断
#ifdef _DEBUG
void C试验品View::AssertValid() const
{
CView::AssertValid();
}
void C试验品View::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
C试验品Doc* C试验品View::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(C试验品Doc)));
return (C试验品Doc*)m_pDocument;
}
#endif //_DEBUG
// 判断点是否在矩形里面,返回对应矩形号
int C试验品View::JudgeRect(CPoint point)
{
if(point.xrect[19].right||point.y
||point.y>rect[0].bottom)
{
for(int i=0;i<20;i++)
//需要这个否则点击随意后其他虽然弹入,但是当点其他时,还是会重新弹出,同时,不进行赋值的话,第一次点击不会弹出因为第一次时,下面的if语句会直接先赋值,即点击后还是按照原来的图片形式
m_np[i]=0;
return -1;
}
for(int i=0;i
{
if(point.x>rect[i].left&&point.xrect[i].
top&&point.y
{
if(m_np[i])
m_np[i]=0;
else
m_np[i]=1;
return i;
}
}
return -1;
}
int C试验品View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
int w=width/25;
int h=height/25;
// m_Button1.Create(_T("出牌"),WS_CHILD | BS_PUSHBUTTON | WS_BORDER,//vs2005本身问题,需要把char[] 转换为LPCTSTR类型
m_Button1.Create(_T("出牌"),WS_CHILD|BS_PUSHBUTTON|WS_VISIBLE|WS_BORDER,
CRect(400,20,480,60),this,IDB_BUTTON1);
m_Button2.Create(_T("不出"),WS_CHILD | BS_PUSHBUTTON |WS_VISIBLE | WS_BORDER,
CRect(500,20,580,60),this,IDB_BUTTON2);
return 0;
}
void C试验品View::OnButton1Clicked()
{
int i,x1,y1,z1;
int t=0;
std::vector vec;//CString s;s.Format
std::vector::reverse_iterator riter=vec_game.rbegin();
std::map c1;
if(current_player==1||current_player==2)
{
c1=Brand_size.begin()->first;
x1=c1.begin()->first;
y1=c1.begin()->second;
z1=Brand_size.begin()->second;
}
std::multimap mp,pm;
for(i=0;i<20;i++)
{
if(m_np[i]==1)
{
vec.push_back(*(riter+i));
t=1;
}
}
if(t==0)
MessageBox(_T("请选择输出的牌"));
else
{
std::sort(vec.begin(),vec.end());
transition(mp,pm,vec);
judge_game(mp,pm,vec);
std::map c;
c=Brand_size.begin()->first;
int x=c.begin()->first;
int y=c.begin()->second;
int z=Brand_size.begin()->second;
if(current_player==1||current_player==2)
{
if((x1!=x)||(y1!=y)||(!(z1
{
MessageBox(_T("请重新选择输出的牌"));
std::map t;
t.insert(std::map::value_type(x1,y1));
Brand_size.clear();
Brand_size.insert(std::map,int>::value_type(t,z1));
x=0;
y=0;
z=0;
InvalidateRect(FALSE);
}
}
if(x!=0&&y!=0&&z!=0)
{
i=vec_game.size()-1;
vec_chu.clear();
for(std::vector::iterator iter=vec_game.begin();iter!=vec_game.end();i--)
{//减去游戏者所下的牌
if(m_np[i]==1)
{
vec_chu.push_back(*iter);
iter=vec_game.erase(iter);
}
else
iter++;
}
std::multimap mmm,ppp,mmm1,ppp1;
transition(mmm,ppp,vec1);
x_machine=continuation(mmm,z,y,x);//表示机器一是否有牌
if(x_machine==0)//如果一有下,则调用一下地情况
{
transition(mmm1,ppp1,vec1);
x_machine=continuation(mmm1,z,y,x);//表示机器二是否有牌
if(x_machine==0)//否则,调用二下的情况,可以加入一些智能
current_player=0;
else
current_player=2;
}
else
current_player=1;//表示机器出牌
// x_machine=1;
InvalidateRect(FALSE);//传递窗口重绘的消息该OnDraw()
}
// CString str;
// str.Format(_T("%d,%d,%d",x,y,z));想用这个调式看结果但是谁让对了,但是输出不对,到底该怎么用呢
// MessageBox(str);
}
}
void C试验品View::OnButton2Clicked()
{
std::vector::iterator ir;
std::map t;
int d,k;
if(current_player==1)
{
ir=vec1.begin();
d=*ir;
k=std::count(vec1.begin(),vec1.end(),d);
if(k==1)
{
vcc.clear();
vcc.push_back(d);
vec1.erase(ir);
t.insert(std::map::value_type(k,1));
Brand_size.clear();
Brand_size.insert(std::map,int>::value_type(t,d));
}
if(k>=2)
{
vcc.clear();
vcc.push_back(d);
vcc.push_back(d);
ir=vec1.erase(ir);
vec1.erase(ir);
t.insert(std::map::value_type(2,1));
Brand_size.clear();
Brand_size.insert(std::map,int>::value_type(t,d));
}
}
if(current_player==2)
{
ir=vec2.begin();
d=*ir;
k=std::count(vec2.begin(),vec2.end(),d);
if(k==1)
{
vcc.clear();
vcc.push_back(d);
vec2.erase(ir,ir+1);
t.insert(std::map::value_type(k,1));
Brand_size.clear();
Brand_size.insert(std::map,int>::value_type(t,d));
}
if(k>=2)
{
vcc.clear();
vcc.push_back(d);
vcc.push_back(d);
ir=vec2.erase(ir,ir+2);
// vec2.erase(ir);
t.insert(std::map::value_type(2,1));
Brand_size.clear();
Brand_size.insert(std::map,int>::value_type(t,d));
}
}
}
// 得到连续的牌号(与order的区别在于,order只是判断所给的数据是不是符合,而这个函数则是找遍关联器直到找到或者都找完为止)
int C试验品View::continuation(std::multimap mmp, int d, int k, int wc)
{//得到连续的牌号(与order的区别在于,order只是判断所给的数据是不是符合,而这个函数则是找遍关联器直到找到或者都找完为止)
int n=1,i;//n是用来记录iter运行到哪个数,用在判断剩下的数够不够再进行一次循环判断
std::multimap::iterator iter=mmp.begin();
std::multimap m;
int j=0;
int initial_number=0;
for(i=0;i
{
if(iter->first>d)
break;
n++;
iter++;//当iter->first
}
if(i==mmp.size())//找不到跳出
return 0;
while(1)
{
if((mmp.size()-n+1/*加一是因为每次都是在上次不能连续点开始的,所以剩下的数必须加上原来的一个点*/)
break;
initial_number=iter->first;//作为开始点
// if(initial_number>10)//当开始点大于时会出现,但是(即对应的)是不能出现的
// return 0;
m.clear();//每次都要把存储判断数组清零
for(j=iter->first;jfirst+k;j++)
{
m.insert(std::multimap::value_type(j,j));
}//组建判断数组,iter无法加k,只能重载自加运算符
int cnt=0;
std::multimap::iterator it=m.begin();
while(/*(++iter)!=m.end()&&*/mmp.find(it->first)/*得到对应键*/!=mmp.end())//判断数据是否连续
{/*得到iter++,每次都指向下一个,必须在前面,因为it不符合时,必须跳过,但是iter必须是下一个*/
iter++;
// if(iter==m.end())//为什么无法这样呢,无法用m.end()与之相等
// break;
if(wc>mmp.find(it->first)->second)//有这个判断,可以得到连续的双或者三
{
iter++;//本意是指向下一个(因为原来有加,但是后来下面又减了,所以要加,
n++;//指向下一个
break;
}
++cnt;
++it;
n++;//每次都指向下一个
if(cnt==k)//记录,是否连续的关键
return initial_number;
}
iter--;//加上这个是因为,当出现不符合。find()时,iter还是会加一,也就是在不连续点的下一个点,所以需要返回到不连续点处
}
return 0;
}
// //删去下一次出牌方下的牌,与continuation()连用,分别是判断(上面只是判断连续的方面),取牌initial_number/*开始的牌号*/,continuation_number/*连续量*/,suit_patterns/*是双是单还是三,四的*/
void C试验品View::Choose_Brand(std::vector & vc,std::vector & c,int initial_number/*开始的牌号*/,int continuation_number/*连续量*/,int suit_patterns/*是双是单还是三,四的*/)
{
//删去下一次出牌方下的牌,与continuation()连用,分别是判断(上面只是判断连续的方面),取牌
int d=initial_number,i;
for(i=0;i
{
std::vector::iterator iter=std::find(vc.begin(),vc.end(),initial_number++);
for(int j=0;j
{
c.push_back(*iter);
iter=vc.erase(iter);
}
}
}
// 拆分关联器,得到需要的部分用于操作,注意这里输入的要是以牌数为键值的pm因为只有以牌数为键值的在后面才是牌数最多的牌号
std::multimap C试验品View::split(std::multimap pmm, int k)
{
std::multimap::iterator iter=pmm.begin();
for(int i=0;i
iter++;
// iter=iter+1; multimap的迭代器不能使用加减号,只能自增自减
// iter=iter+k-1;
std::multimap m;
do
{
m.insert(std::multimap::value_type(iter->second,iter->first));
//输出时是按照牌号为键值的,所以需要倒过来
iter++;
}while(iter!=pmm.end());
return m;
}
// //判断不重复后的牌组,是否连续
int C试验品View::order(std::multimap mmp)
{
int i;
std::multimap m;
std::multimap::iterator iter=mmp.begin();
for(i=iter->first;ifirst+mmp.size();i++)
{
m.insert(std::multimap::value_type(i,i));
}
int cnt=0;
std::multimap::iterator it=m.begin();
while(mmp.find(it->first)/*得到对应键*/!=mmp.end())//判断数据是否连续
{
++cnt;
++it;
if(cnt==mmp.size())
return iter->first;
}
return 0;
}
// 得到所出牌的multimap形式,需要multimap,因为在pm中键值需要重复,输入后,自动按键值排序
void C试验品View::transition(std::multimap & mp,std::multimap & pm,std::vector & vec)
{
int i;
for(std::vector::iterator iter=vec.begin();iter!=vec.end();iter+=i/*跳到下一个与该数不相等的数的迭代器上*/)
{
i=count(vec.begin(),vec.end(),*iter);//count不是容器等专有函数,而是泛型函数,返回的是对应数目
mp.insert(std::multimap::value_type(*iter,i));//第一个数是牌,第二是数目
pm.insert(std::multimap::value_type(i,*iter));//与上面相反,两个相反是为了得到数目(下面)为基的排序与牌号(上面的)为基的排序
}//得到牌号及对应数目(此时,不会有牌号相同的情况
}
// 判断点击输出的值是否正确,获得当前所下的牌型,用Brand_size存储
void C试验品View::judge_game(std::multimap mp, std::multimap pm,std::vector vec)//炸弹无法判断
{
std::multimap m1;
std::vector::size_type vec_s=vec.size();
int j;
std::multimap::reverse_iterator riter=pm.rbegin();
//反向迭代器,得到后起第一个,即键值最大的,此时关联器是pm,为最大的牌数值对应的迭代器
int wc=riter->first;//得到最大的牌数(同一种牌号)
j=pm.count(wc);//得到了最大数目的次数(同一数目多少种牌号)
int n=mp.size();//得到不重复牌数目
// cout<
if(Brand_size.begin()!=Brand_size.end())
Brand_size.erase(Brand_size.begin());
int magnitude=0;
//表示牌的大小,其中,-》,2-》,注意,内在的不会出现,2(只有界面才是)内在的用,15表示
switch(wc)//判断牌型
{
case 1:
if(n<5)
{
if(n==1)
magnitude=mp.begin()->first;//单只牌
if(n==2)
{
if((mp.begin())->first==53&&(mp.rbegin())->first==54)//两张大王时
{
magnitude=-1;//避过Brand_size的赋值行为
std::map t;
t.insert(std::map::value_type(100,100));
Brand_size.insert(std::map,int>::value_type(t,100));
}
}
}
else
magnitude=order(mp);//单顺时的情况
if(n!=2&&magnitude!=0)//当牌型符合规则
{
std::map t;
t.insert(std::map::value_type(1,n));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
else//不合规则
{
std::map t;
t.insert(std::map::value_type(0,0));
Brand_size.insert(std::map,int>::value_type(t,0));
//Brand_size三个参数分别代表着,最多数目量,有多少不同牌(只有最大为单时第二个参数才代表这个)(这两个用来判断牌型),最后一个为大小(一般结合第二个数判断)
}
//其中不符合规则的牌型为三0,最大为三100(鬼炸)
break;
case 2:
if(j==1&&n==1)//一双对的情况
{
magnitude=mp.begin()->first;//这里面的赋值可以考虑用函数,或类
std::map t;
t.insert(std::map::value_type(2,1));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(j>2&&n==j/*都是对的情况*/&&(magnitude=order(mp))!=0)
//此时已经判断了n==j,所以不用拆分mp直接可以判断是否连续
{
std::map t;
t.insert(std::map::value_type(2,j));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(magnitude==0)
{
std::map t;
t.insert(std::map::value_type(0,0));
Brand_size.insert(std::map,int>::value_type(t,0));
}
break;
case 3:
m1=split(pm,n-j);//拆分关联器用以判断连续
if(n==j&&(magnitude=order(mp))!=0)//单独三条或连续三条的情况
{
std::map t;
t.insert(std::map::value_type(3,j));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(n<=2*j/*"<="的情况与case4的相同*/&&(magnitude=order(m1))!=0)
//三带的情况,此时,因为要判断连续的情况,又有单的情况,所以需要拆分
{
if(pm.count(1)==j||(vec_s-3*j)==j)//三带一,含连续带
{
std::map t;
int d=j*10+1;
t.insert(std::map::value_type(3,d));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(pm.count(2)==j)//三带二,含连续带
{
std::map t;
int d=j*10+2;
t.insert(std::map::value_type(3,d));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
}
if(magnitude==0)
{
std::map t;
t.insert(std::map::value_type(0,0));
Brand_size.insert(std::map,int>::value_type(t,0));
}
break;
case 4:
m1=split(pm,n-j);
//拆分出部分是因为在使用order()函数时,无法单独判断最多数目的牌号间是否顺序,需要拆分出来
if(n==1)//炸弹的情况
{
magnitude=mp.begin()->first;
std::map t;
t.insert(std::map::value_type(4,4));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(n<=3*j/*用"<="是因为也可能出现四带二个单时,单之间可能相同的情况*/&&(magnitude=order(m1))!=0)
{
if(pm.count(1)==2*j||(vec_s-4*j)==2*j/*即剩下牌的数目刚好是张的牌号的牌数(不重复,即除以)的两倍,即四带二个单,第二种情况是因为可能出现单的中有相同的牌*/)
{
std::map t;
int d=j*10+1;//乘以+1,是为了区分四带二个双的情况
t.insert(std::map::value_type(4,d));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if(pm.count(2)==2*j)//四带二个双
{
std::map t;
int d=j*10+2;
t.insert(std::map::value_type(4,d));
Brand_size.insert(std::map,int>::value_type(t,magnitude));
}
if((vec_s-4*j)!=2*j)
//这种情况是因为前面把magnitude已经赋值,但是剩余的牌又不符合规则,需要重新把magnitude赋
magnitude=0;
}
if(magnitude==0)
{
std::map t;
t.insert(std::map::value_type(0,0));
Brand_size.insert(std::map,int>::value_type(t,0));
}
break;
default:
break;
}
}
// 在对应的牌组里面找出该下的牌
int C试验品View::machine(std::vector &vec,std::multimap mp,std::multimap pm)
{
std::map m_b=Brand_size.begin()->first;
int m_n=Brand_size.begin()->second;
int o_n=m_b.begin()->first;
int t_n=m_b.begin()->second;
int d,b=0,k,l,q,r;
switch(o_n)
{
case 1:
if(t_n==1)
{
d=continuation(mp,m_n,1,1);
b=seek_max(mp,d,1);
}
else
{
b=continuation(mp,m_n,t_n,1);
}
if(b==0)
break;
Choose_Brand(vec,vcc,b,t_n,1);
break;
case 2:
if(t_n==1)
{
d=continuation(mp,m_n,1,2);
b=seek_max(mp,d,2);
}
else
{
b=continuation(mp,m_n,t_n,2);
}
if(b==0)
break;
Choose_Brand(vec,vcc,b,t_n,2);
break;
case 3:
if(t_n<10)
{
d=continuation(mp,m_n,t_n,3);
b=d;
if(b==0)
break;
Choose_Brand(vec,vcc,b,t_n,3);
}
else
{
if((t_n%10)==1)
{
if((t_n-10)==1)
{
d=continuation(mp,m_n,1,3);
b=d;
int k=pm.find(1)->second;
if(k==0)
{
k=pm.find(2)->second;
}
if(b==0)
break;
Choose_Brand(vec,vcc,b,t_n,3);
Choose_Brand(vec,vcc,k,1,1);
}
if((t_n-20)==1)
{
d=continuation(mp,m_n,2,3);
b=d;
if(b==0)
break;
k=pm.find(1)->second;
if(k==0)
{
k=pm.find(2)->second;
}
Choose_Brand(vec,vcc,k,1,1);
int l=pm.find(1)->second;
if(l==0)
{
l=pm.find(2)->second;
}
Choose_Brand(vec,vcc,l,1,1);
Choose_Brand(vec,vcc,b,t_n,3);
}
if((t_n-30)==1)
{
d=continuation(mp,m_n,3,3);
b=d;
if(b==0)
break;
k=pm.find(1)->second;
if(k==0)
{
k=pm.find(2)->second;
}
Choose_Brand(vec,vcc,k,1,1);
l=pm.find(1)->second;
if(l==0)
{
l=pm.find(2)->second;
}
Choose_Brand(vec,vcc,l,1,1);
int q=pm.find(1)->second;
if(q==0)
{
q=pm.find(2)->second;
}
Choose_Brand(vec,vcc,q,1,1);
Choose_Brand(vec,vcc,b,t_n,3);
}
if((t_n-40)==1)
{
d=continuation(mp,m_n,3,3);
b=d;
if(b==0)
break;
k=pm.find(1)->second;
if(k==0)
{
k=pm.find(2)->second;
}
Choose_Brand(vec,vcc,k,1,1);
l=pm.find(1)->second;
if(l==0)
{
l=pm.find(2)->second;
}
Choose_Brand(vec,vcc,l,1,1);
q=pm.find(1)->second;
if(q==0)
{
q=pm.find(2)->second;
}
Choose_Brand(vec,vcc,q,1,1);
int r=pm.find(1)->second;
if(r==0)
{
r=pm.find(2)->second;
}
Choose_Brand(vec,vcc,r,1,1);
Choose_Brand(vec,vcc,b,t_n,3);
}
}
else
{
if((t_n-10)==2)
{
d=continuation(mp,m_n,1,3);
b=d;
if(b==0)
break;
k=pm.find(2)->second;
if(k==0)
{
k=pm.find(3)->second;
}
Choose_Brand(vec,vcc,b,t_n,3);
Choose_Brand(vec,vcc,k,1,2);
}
if((t_n-20)==2)
{
d=continuation(mp,m_n,2,3);
b=d;
if(b==0)
break;
k=pm.find(2)->second;
if(k==0)
{
k=pm.find(2)->second;
}
Choose_Brand(vec,vcc,k,1,2);
l=pm.find(2)->second;
if(l==0)
{
l=pm.find(3)->second;
}
Choose_Brand(vec,vcc,l,1,2);
Choose_Brand(vec,vcc,b,t_n,3);
}
if((t_n-30)==2)
{
d=continuation(mp,m_n,3,3);
b=d;
if(b==0)
break;
k=pm.find(2)->second;
if(k==0)
{
k=pm.find(3)->second;
}
Choose_Brand(vec,vcc,k,1,2);
l=pm.find(2)->second;
if(l==0)
{
l=pm.find(3)->second;
}
Choose_Brand(vec,vcc,l,1,2);
q=pm.find(2)->second;
if(q==0)
{
q=pm.find(3)->second;
}
Choose_Brand(vec,vcc,q,1,2);
Choose_Brand(vec,vcc,b,t_n,3);
}
if((t_n-40)==2)
{
d=continuation(mp,m_n,3,3);
b=d;
if(b==0)
break;
k=pm.find(2)->second;
if(k==0)
{
k=pm.find(3)->second;
}
Choose_Brand(vec,vcc,k,1,2);
l=pm.find(2)->second;
if(l==0)
{
l=pm.find(3)->second;
}
Choose_Brand(vec,vcc,l,1,2);
q=pm.find(2)->second;
if(q==0)
{
q=pm.find(3)->second;
}
Choose_Brand(vec,vcc,q,1,2);
r=pm.find(2)->second;
if(r==0)
{
r=pm.find(3)->second;
}
Choose_Brand(vec,vcc,r,1,2);
Choose_Brand(vec,vcc,b,t_n,3);
}
}
}
break;
case 4:
b=0;
break;
}
if(b==0&&o_n!=4)
{
std::multimap::iterator iter_1,iter_2,iter_3;;
iter_1=pm.find(4);
iter_2=mp.find(53);
iter_3=mp.find(54);
if(iter_1!=pm.end())
{
Choose_Brand(vec,vcc,iter_1->second,1,4);
}
else if(iter_2!=mp.end()&&iter_3!=mp.end())
{
Choose_Brand(vec,vcc,53,1,1);
Choose_Brand(vec,vcc,54,1,1);
}
else
{
五. 课程设计总结(包括程序中遇到的问题及解决方案,以及课程设计收获)
总结:
1. 问题:选择什么语言
解决: C++ MFC
2. 问题: MFC的结构是怎样的
解决:孙鑫的视频教程和相关书籍
3. 问题:具体AI是怎么样的,所想的是否不足
解决:网上查询
4. 问题:具体游戏框架怎么样
解决:分类思考,分成AI和 图片显示(由于视野所限,只有这些)
5. 问题:怎么在窗口中显示图片
解决:网上查询和书籍查询(得到StretchBlt函数)
6. 问题:图片的动态效果(即弹起,出牌等等)
解决:添加参数(在确定按钮中进行改变),用来判断是否进行改变,切换到另外的图片显示上
7. 问题:怎么判断是否出牌
解决:添加两个按钮,进行相关操作
8. 问题:怎么判断哪个牌需要弹起
解决:分割出一定区域,以矩形作为区域大小,同时,添加鼠标点击的响应函数,判断出所点击区域说在矩形区域,从而得到所对应的牌
9. 问题:如何显示机器玩家的出牌
解决:添加相关参数用来判断哪方出牌
问题:(由于时间的原因无法解决的问题)
1. 当玩家这一方出牌时,有时候不知道为什么出现系统错误,至今无法解决
2. 图片的分辨率问题,即在桌面上显示不好,同时,本来想要固定显示的窗口大小的,问题仍然无法解决
3. 怎么让所出的牌旋转45度(网上有相关的资料,可惜不懂)
4. 机器放的智能无法达到预期效果,好像(尚未调式)无法出三张以上,同时,AI方面不足,需要时间
5. 窗口的样式需要改变,由于时间和知识不牢固,无法解决
收获:
1. 了解了MFC得编程形式
2. 明白了做游戏的辛苦,大致明白游戏到底是怎么出现的
3. 学会了MFC的图片显示
4. 学会了坚持(本来由于时间和各方面压力的问题,无法完成的)
5. 巩固了C++的相关知识,但是还有很多不足,思想形式无法从C语言上转变过来
数据结构课程实验报告专业指导老师班级姓名学号完成日期一实验目的1掌握线性表的顺序存储结构和链式存储结构2熟练掌握顺序表和链表基本算…
数据结构与算法课程设计报告姓名林小琼学号0907022118班级09网络工程设计时间20xx11020xx114审阅教师目录一课程…
软件111班18号赵庆珍数据结构课程设计任务书学期12131班级软件111一设计目的数据结构是一门实践性较强的软件基础课程为了学好…
仲恺农业工程学院课程设计报告课程名称:数据结构院(系):计算机科学与工程专业:计算机科学与技术班级:计算机102班学号:姓名:指导…
目录一概述1二系统分析1三概要设计2四详细设计441赫夫曼树的建立4411选择选择parent为0且权值最小的两个根结点的算法54…
《数据结构》课程设计报告题目:班级:计算机系1001班姓名:学号:4236指导教师:日期:20##年7月3日一、课程设计目标二、概…
数据结构课程设计报告学生姓名学号班级地信10901长江大学20XX.6目录1.需求分析......................…
软件111班18号赵庆珍数据结构课程设计任务书学期12131班级软件111一设计目的数据结构是一门实践性较强的软件基础课程为了学好…
课程设计报告课程名称数据结构课题名称迷宫问题姓名吴明华学号20xx16020xx9院系计算机学院通信与信息工程系专业班级通信112…
数据结构与算法课程设计报告姓名林小琼学号0907022118班级09网络工程设计时间20xx11020xx114审阅教师目录一课程…
四川大学操作系统课程设计报告学院专业年级组编号组成员软件学院第X组乔心轲姓名0743111340学号张雯姓名XXXXXXXX学号康…