用c++做.docx
- 文档编号:24311459
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:15
- 大小:18.40KB
用c++做.docx
《用c++做.docx》由会员分享,可在线阅读,更多相关《用c++做.docx(15页珍藏版)》请在冰豆网上搜索。
用c++做
用c++做2048的一种方法
X.P.Y
本文绝对原创。
需要的知识:
c++
能够实现的功能:
手动或自动进行2048游戏。
AI算法:
一次计算有4个方向,预测三步需要64个状态,但是最后一步可以退回,所以需要开int[16][16],通过一次枚举方向来算评估分,并用评估分最大的方向作为下一次移动的方向。
遗憾的是,本算法到达2048概率并不高。
首先,如何实现一个2048界面。
准备函数:
voidgotoxy(intx,inty)函数:
(TC、BC自带该函数)
文件头:
#include
#include
函数代码:
voidgotoxy(intx,inty){
COORDc;c.X=x;c.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
int&at(int*pn,intx,inty=-1,boolreverse=false):
(实现这个函数的目的是让一维数组变为二维数组,其中pn是一维数组地址,x为行,y为列(如果是默认参数-1则返回一维数组),是否颠倒xy位置是为了以后写代码比较方便,在后面给出具体解释)
函数代码:
int&at(int*pn,intx,inty=-1,boolreverse=false){
returnreverse?
(~y?
pn[x*4+y]:
pn[x]):
(~y?
pn[y*4+x]:
pn[x]);
}
voidrandom_insert(int*pn)
(向棋盘内空白处插入一个数2或4,其中插入2的概率为90%)
文件头:
#include
函数代码:
voidrandom_insert(int*pn){
intdataCount=0;
for(inti=0;i<16;i++)
if(pn[i])
dataCount++;
if(dataCount==16)
return;
intindex=rand()%(16-dataCount);
intiScan=0;
while(pn[iScan]||index--)iScan++;
pn[iScan]=(rand()%10)?
2:
4;
}
解释:
dataCount:
统计棋盘内非零个数,如果非零数为16证明不能插入数了,返回。
如何随机插入呢?
首先取得空白数目:
16-dataCount,在0--空白数目-1之间取得一个随机数记为index,重新扫描棋盘,每次遇到空白时index自减1,当找到一个空白,并且index=0时,插入这个数。
voidinitialize(intn=3)
(初始化棋盘(棋盘为全局变量一维数组inttable[16]),其中的n代表初始化后棋盘内最初有几个数)
文件头:
#include
#include
函数代码:
voidinitialize(intn=3){
srand(time(0));
memset(table,0,16*sizeof(int));
Score=Max_number=0;
while(n--)random_insert(table);
}
解释:
memset(table,0,16*sizeof(int))将table地址往后16*sizeof(int)个字节赋值为0。
voidprint()
(打印棋盘。
不用清屏的原因是清屏会闪一下)
文件头:
#include
函数代码:
voidprint(){
gotoxy(0,0);
printf("2048-GameTabledesignedbyX.P.Y\nScore:
%d\n\n\n",Score);//x=1
for(inti=0;i<16;i++){
gotoxy((i%4+1)*5+1,(i/4+1)*2+1);
printf("%d",table[i]);
}
gotoxy(0,11);
}
boolisConinue(int*pn)
(每次操作会在一个while循环里进行,用本函数判断是否游戏结束。
直接放在while判断即可)
函数代码:
boolisConinue(int*pn=table){
intdataCount=0;
for(inti=0;i<16;i++)if(at(pn,i,-1,false))dataCount++;
returndataCount<16||cur_direction(table,0,true)||cur_direction(table,2,true);
}
boolcanMove(int*pn,intdirection)
(注:
这里的direction只有0、1两个值,分别代表横向、纵向。
本函数主要为了判断下一步是否可以横向走或纵向走。
)
函数代码:
boolcanMove(int*pn,intdirection){
for(inti=0,sum=0;i<4;i++){
for(intj=0;j<4;j++){
if(!
at(pn,i,j,direction==0))returntrue;
if(j&&at(pn,i,j,direction==0)==at(pn,i,j-1,direction==0))returntrue;
}
}
returnfalse;
}
接下来便是本程序的核心:
移动函数:
intcur_direction(int*pn,intdirect,boolvisual=false,int*callcount=NULL,int*squareCount=NULL,boolnoinsert=false)
(解释:
pn棋盘,这里之所以不用table是因为如果有ai预测下一步算法时,会另外开辟一段空间进行虚拟操作,此时的pn就不是table了。
参数解释:
direct:
0、向上移动
1、向下移动
2、向左移动
3、向右移动
visual:
是否为虚拟操作(操作只计算数据,不改变棋盘)
callcount:
特殊参数,如果存在该指针,一轮操作结束后指针指向的int将会被赋值为本次操作消除方块的个数。
squareCount:
特殊参数,如果存在该指针,一轮操作结束后指针指向的int将会被赋值为本次操作结束后方块的数据平整性(每个元素与同行、同列的临近元素呈2倍关系的程度)
noinsert:
如果值为真,则操作结束后不会自动插入随机方块。
)
函数代码:
intcur_direction(int*pn,intdirect,boolvisual=false,int*callcount=NULL,int*squareCount=NULL,boolnoinsert=false){
int_score=0,sum=0,square=0,flag=1;
boolisReverse=direct%2==0;
for(intiLine=0;iLine<4;iLine++){
vector
for(inti=(isReverse?
0:
3);i!
=(isReverse?
4:
-1);i+=(isReverse?
1:
-1)){
if(at(pn,iLine,i,direct>1))line.push_back(at(pn,iLine,i,direct>1));
flag=1;
while(flag){
flag=0;
for(intk=1;k if(line[k-1]==line[k]){ line[--k]*=2; _score+=line[k]; if(Max_number line.erase(line.begin()+k+1); flag++; } sum+=flag; } } if(! visual) for(inti=(isReverse? 0: 3);i! =(isReverse? 4: -1);i+=(isReverse? 1: -1)){ if(line.empty())at(pn,iLine,i,direct>1)=0; else{ at(pn,iLine,i,direct>1)=line[0]; line.erase(line.begin()); } } for(inti=1;i if(line[i-1]*2==line[i]||line[i-1]==2*line[i]) square+=line[i]-line[i-1]; } if(callcount)(*callcount)=sum; if(squareCount)(*squareCount)=abs(square); if((! visual)&&(! noinsert))random_insert(pn); return_score; } 解释: 大体思路: 本函数的返回值是本轮结束后得到的分数,函数采用vector可变数组来记录本次操作的一行或一列中非零个数,并在vector内完成相同方块消除操作,并在操作完成后重新赋值给原棋盘。 voidgameJudge() (游戏函数,完成人机交互) 函数代码: voidgameJudge(){ initialize(); while(isConinue()){ print(); switch(getch()){ case87: case119: case72: Score+=cur_direction(table,0);break; case83: case115: case80: Score+=cur_direction(table,1);break; case65: case97: case75: Score+=cur_direction(table,2);break; case68: case100: case77: Score+=cur_direction(table,3);break; } } } 到这里,已经完成了一个2048游戏的界面以及各种功能。 以下是ai自动游戏的算法,并不太成熟: voidai_judge(intnloop=1) (nloop: 玩几次) 函数代码: voidai_judge(intnloop=1){ while(nloop--){ initialize(); while(isConinue()){ Score+=cur_direction(table,ai_calculate()); print(); } } } ai算法的核心: intai_calculate() (该函数的返回值是理论上最好的下一步方向) 函数代码: intai_calculate(){ boolcanv=canMove(table,0),canh=canMove(table,1); if(! (canv&&canh))returncanv? 2: 0; intsum[4]={0},score[4]={0},square[4]={0},ai_table[16][16]; inttmp_sum,tmp_square,index=0,maxScore=-1,curScore=0; for(inti=0;i<4;i++){ for(intk=0;k<4;k++){ memcpy(ai_table[i*k],table,sizeof(int)*16); score[i]=cur_direction(ai_table[i*k],i,false,sum+i,square+i); score[i]+=0.8*cur_direction(ai_table[i*k],k,false,&tmp_sum,&tmp_square,true); sum[i]+=0.8*tmp_sum; square[i]+=0.8*tmp_square; for(intj=0;j<4;j++){ score[i]+=0.4*cur_direction(ai_table[i*k],j,true,&tmp_sum,&tmp_square,true); sum[i]+=0.4*tmp_sum; square[i]+=0.4*tmp_square; } curScore=2*score[i]+sum[i]; if(maxScore } } returnindex; } 解释: 本函数会对向下3步进行评估,并用评估分来作为下一步最优方向的依据。 由于下一步与下两步的得分是不确定的,因此不能有大于1的权值。 最终本程序的代码为: #include #include #include #include #include #include #include usingnamespacestd; inttable[16]={0},Score=0,Max_number=0; boolallprint=true; int&at(int*pn,intx,inty=-1,boolrev=false){ returnrev? (~y? pn[x*4+y]: pn[x]): (~y? pn[y*4+x]: pn[x]); } boolcanMove(int*pn,intdirection){ for(inti=0,sum=0;i<4;i++){ for(intj=0;j<4;j++){ if(! at(pn,i,j,direction==0))returntrue; if(j&&at(pn,i,j,direction==0)==at(pn,i,j-1,direction==0))returntrue; } } returnfalse; } voidgotoxy(intx,inty){ COORDc;c.X=x;c.Y=y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c); } voidrandom_insert(int*pn){ intdataCount=0; for(inti=0;i<16;i++) if(pn[i]) dataCount++; if(dataCount==16) return; intindex=rand()%(16-dataCount); intiScan=0; while(pn[iScan]||index--)iScan++; pn[iScan]=(rand()%10)? 2: 4; } intcur_direction(int*pn,intdirect,boolvisual=false,int*callcount=NULL,int*squareCount=NULL,boolnoinsert=false){ int_score=0,sum=0,square=0,flag=1; boolisReverse=direct%2==0; for(intiLine=0;iLine<4;iLine++){ vector for(inti=(isReverse? 0: 3);i! =(isReverse? 4: -1);i+=(isReverse? 1: -1)){ if(at(pn,iLine,i,direct>1))line.push_back(at(pn,iLine,i,direct>1)); flag=1; while(flag){ flag=0; for(intk=1;k if(line[k-1]==line[k]){ line[--k]*=2; _score+=line[k]; if(Max_number line.erase(line.begin()+k+1); flag++; } sum+=flag; } } if(! visual) for(inti=(isReverse? 0: 3);i! =(isReverse? 4: -1);i+=(isReverse? 1: -1)){ if(line.empty())at(pn,iLine,i,direct>1)=0; else{ at(pn,iLine,i,direct>1)=line[0]; line.erase(line.begin()); } } for(inti=1;i if(line[i-1]*2==line[i]||line[i-1]==2*line[i]) square+=line[i]-line[i-1]; } if(callcount)(*callcount)=sum; if(squareCount)(*squareCount)=abs(square); if((! visual)&&(! noinsert))random_insert(pn); return_score; } boolisConinue(int*pn=table){ intdataCount=0; for(inti=0;i<16;i++)if(at(pn,i,-1,false))dataCount++; returndataCount<16||cur_direction(table,0,true)||cur_direction(table,2,true); } voidprint(){ if(! allprint)return; gotoxy(0,0); printf("2048-GameTabledesignedbyX.P.Y\nScore: %d\n\n\n",Score);//x=1 for(inti=0;i<16;i++){ gotoxy((i%4+1)*5+1,(i/4+1)*2+1); printf("%d",table[i]); } gotoxy(0,11); } intai_calculate(){ boolcanv=canMove(table,0),canh=canMove(table,1); if(! (canv&&canh))returncanv? 2: 0; intsum[4]={0},score[4]={0},square[4]={0},ai_table[16][16]; inttmp_sum,tmp_square,index=0,maxScore=-1,curScore=0; for(inti=0;i<4;i++){ for(intk=0;k<4;k++){ memcpy(ai_table[i*k],table,sizeof(int)*16); score[i]=cur_direction(ai_table[i*k],i,false,sum+i,square+i); score[i]+=0.8*cur_direction(ai_table[i*k],k,false,&tmp_sum,&tmp_square,true); sum[i]+=0.8*tmp_sum; square[i]+=0.8*tmp_square; for(intj=0;j<4;j++){ score[i]+=0.4*cur_direction(ai_table[i*k],j,true,&tmp_sum,&tmp_square,true); sum[i]+=0.4*tmp_sum; square[i]+=0.4*tmp_square; } curScore=2*score[i]+sum[i]; if(maxScore } } returnindex; } voidinitialize(intn=3){ memset(table,0,16*sizeof(int)); Score=Max_number=0; while(n--)random_insert(table); } voidgameJudge(){ initialize(); while(isConinue()){ print(); switch(getch()){ case87: case119: case72: Score+=cur_direction(table,0);break; case83: case115: case80: Score+=cur_direction(table,1);break; case65: case97: case75: Score+=cur_direction(table,2);break; case68: case100: case77: Score+=cur_direction(table,3);break; } } } voidai_judge(intnloop=1){ while(nloop--){ initialize(); while(isConinue()){ Score+=cur_direction(table,ai_calculate()); print(); } if(allprint)printf("MaxNumber: %d\n",Max_number); } } intmain(){ srand(time(0)); gameJudge(); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- c+