用c++做.docx
《用c++做.docx》由会员分享,可在线阅读,更多相关《用c++做.docx(15页珍藏版)》请在冰点文库上搜索。
![用c++做.docx](https://file1.bingdoc.com/fileroot1/2023-5/26/63d89362-598f-4223-852f-4dfe43b811ea/63d89362-598f-4223-852f-4dfe43b811ea1.gif)
用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++){
vectorline;
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;kif(line[k-1]==line[k]){
line[--k]*=2;
_score+=line[k];
if(Max_numberline.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;iif(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++){
vectorline;
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;kif(line[k-1]==line[k]){
line[--k]*=2;
_score+=line[k];
if(Max_numberline.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;iif(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;
}