C语言控制台版2048小游戏
效果不好,见谅,没事就写了一个!!!
/**
*@authorRouth
*@main.c
*@date2014,4,26
*/
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<windows.h>
//consolewidth
#defineCONSOLE_WIDTH80
#defineBOX_WIDTH10
intBOX[4][4]={
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}};
//theconsoleoutputhandle
HANDLEc_handle;
voidsetCursorPosition(shortx,shorty){
staticCOORDc;
c.X=x;
c.Y=y;
SetConsoleCursorPosition(c_handle,c);
}
voiddrawTheGameBox(){
printf("%15s■■■■■■■■■■■■■■■■■■■■■\n","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■■■■■■■■■■■■■■■■■■■■■\n","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■■■■■■■■■■■■■■■■■■■■■\n","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■■■■■■■■■■■■■■■■■■■■■\n","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■%8s■%8s■%8s■%8s■\n","","","","","");
printf("%15s■■■■■■■■■■■■■■■■■■■■■\n","");
}
/**
*getarandomposition:R
*thex:0xff&(R>>4)
*they:0x0f&R
*/
intrandom(){
inti=0,j=0,_index=0,rrr=0;
intrand_arr[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
srand((unsigned)time(NULL));
//rand()
for(i=0;i<4;i++){
for(j=0;j<4;j++){
if(BOX[i][j]==0){
rand_arr[_index++]=(0xff&i<<4)|(0xf&j);
}
}
}
if(_index==0){
return-1;
}
returnrand_arr[rand()%_index];
}
/**thecleanarray.**/
int*alogs(intitem[]){
inti=0,j=0;
inttep[4]={0,0,0,0},tmp[4]={0,0,0,0};
for(i=0;i<4;i++){
if(item[i]!=0){
tep[j++]=item[i];
}
}
for(i=0;i<3;i++){
if(tep[0]==0)break;
if(tep[i]==tep[i+1]){
tep[i]*=2;
tep[i+1]=0;
}
}
j=0;
for(i=0;i<4;i++){
if(tep[i]!=0){
tmp[j++]=tep[i];
}
}
return(int*)(&tmp);
}
/**BOXcanmove.*/
intvalidate(intitem[]){
inti=0;
for(i=0;i<3;i++){
if(item[i]!=0&&item[i]==item[i+1])return1;
if(item[i]==0&&item[i+1]!=0)return1;
}
return0;
}
intkeydownControlx(intkey){
inti=0,j=0;
int*p;
inttp[4]={0,0,0,0};
switch(key){
case72://up
j=0;
for(i=0;i<4;i++){
tp[0]=BOX[0][i];
tp[1]=BOX[1][i];
tp[2]=BOX[2][i];
tp[3]=BOX[3][i];
p=alogs(tp);
if(!validate(tp))j++;
BOX[0][i]=p[0];
BOX[1][i]=p[1];
BOX[2][i]=p[2];
BOX[3][i]=p[3];
}
returnj!=4;
case80://down
j=0;
for(i=0;i<4;i++){
tp[0]=BOX[3][i];
tp[1]=BOX[2][i];
tp[2]=BOX[1][i];
tp[3]=BOX[0][i];
p=alogs(tp);
if(!validate(tp))j++;
BOX[3][i]=p[0];
BOX[2][i]=p[1];
BOX[1][i]=p[2];
BOX[0][i]=p[3];
}
returnj!=4;
case75://left
j=0;
for(i=0;i<4;i++){
tp[0]=BOX[i][0];
tp[1]=BOX[i][1];
tp[2]=BOX[i][2];
tp[3]=BOX[i][3];
p=alogs(tp);
if(!validate(tp))j++;
BOX[i][0]=p[0];
BOX[i][1]=p[1];
BOX[i][2]=p[2];
BOX[i][3]=p[3];
}
returnj!=4;
case77://right
j=0;
for(i=0;i<4;i++){
tp[0]=BOX[i][3];
tp[1]=BOX[i][2];
tp[2]=BOX[i][1];
tp[3]=BOX[i][0];
p=alogs(tp);
if(!validate(tp))j++;
BOX[i][3]=p[0];
BOX[i][2]=p[1];
BOX[i][1]=p[2];
BOX[i][0]=p[3];
}
returnj!=4;
default:return0;
}
return0;
}
intmain(){
inti=0,j=0,r=0;
/**setthecursor,visibleorinvisible.*/
CONSOLE_CURSOR_INFOcci={1,0};
/**gettheconsoleoutputhandle.*/
c_handle=GetStdHandle(STD_OUTPUT_HANDLE);
//hidethecursor.
SetConsoleCursorInfo(c_handle,&cci);
//
SetConsoleTextAttribute(c_handle,0x3);
//system("color30");
drawTheGameBox();
r=random();
if(rand()%2==0){
BOX[0xff&(r>>4)][0xf&r]=2;
}else{
BOX[0xff&(r>>4)][0xf&r]=4;
}
for(i=0;i<4;i++){
for(j=0;j<4;j++){
if(BOX[i][j]==0)continue;
setCursorPosition(17+j*8+2+(j*2),i*4+(i+2));
//SetConsoleTextAttribute(c_handle,BOX[i][j]);
printf("%d",BOX[i][j]);
}
}
//begin
while(1){
Sleep(100);
//keydown.
while(_kbhit())
{
//thekeydownfun.
if(!keydownControlx(_getch()))continue;
//cleartheconsoleandredraw.
system("cls");
SetConsoleTextAttribute(c_handle,0x3);
drawTheGameBox();
for(i=0;i<4;i++){
for(j=0;j<4;j++){
if(BOX[i][j]==0)continue;
setCursorPosition(17+j*8+2+(j*2),i*4+(i+2));
//SetConsoleTextAttribute(c_handle,BOX[i][j]);
printf("%d",BOX[i][j]);
}
}
r=random();
if(r==-1){//gameover
//SetConsoleTextAttribute(c_handle,0xff0000);
setCursorPosition(27,10);
printf("GAMEORVER!!!!!!!");
}
if(rand()%2==0){
BOX[0xff&(r>>4)][0xf&r]=2;
}else{
BOX[0xff&(r>>4)][0xf&r]=4;
}
Sleep(100);
setCursorPosition(17+(0xf&r)*8+2+((0xf&r)*2),(0xff&(r>>4))*4+((0xff&(r>>4))+2));
//SetConsoleTextAttribute(c_handle,BOX[0xff&(r>>4)][0xf&r]);
printf("%d",BOX[0xff&(r>>4)][0xf&r]);
}
}
return0;
}
附上另外一个小伙伴的代码
/*
*Copyright(C)JudgeYoung
*E-mail:yjjtc@126.com
*Version:1.0
*/
#include<stdio.h>
#include<time.h>/*包含设定随机数种子所需要的time()函数*/
#include<conio.h>/*包含Windows平台上完成输入字符不带回显和回车确认的getch()函数*/
#include<windows.h>/*包含Windows平台上完成设定输出光标位置达到清屏功能的函数*/
voidstart_game();/*开始游戏*/
voidreset_game();/*重置游戏*/
/*往左右上下四个方向移动*/
voidmove_left();
voidmove_right();
voidmove_up();
voidmove_down();
voidrefresh_show();/*刷新界面显示*/
voidadd_rand_num();/*生成随机数,本程序中仅生成2或4,概率之比设为2:1*/
voidcheck_game_over();/*检测是否输掉游戏,设定游戏结束标志*/
intget_null_count();/*获取游戏面板上空位置数量*/
intboard[4][4];/*游戏数字面板,抽象为二维数组*/
intscore;/*游戏的分*/
intbest;/*游戏最高分*/
intif_need_add_num;/*是否需要生成随机数标志,1表示需要,0表示不需要*/
intif_game_over;/*是否游戏结束标志,1表示游戏结束,0表示正常*/
/*main函数函数定义*/
intmain()
{
start_game();
}
/*开始游戏函数定义*/
voidstart_game()
{
reset_game();
charcmd;
while(1)
{
cmd=getch();/*接收标准输入流字符命令*/
if(if_game_over)/*判断是否需已经输掉游戏*/
{
if(cmd=='y'||cmd=='Y')/*重玩游戏*/
{
reset_game();
continue;
}
elseif(cmd=='n'||cmd=='N')/*退出*/
{
return;
}
else
{
continue;
}
}
if_need_add_num=0;/*先设定不默认需要生成随机数,需要时再设定为1*/
switch(cmd)/*命令解析,w,s,a,d字符代表上下左右命令*/
{
case'a':
case'A':
case75:
move_left();
break;
case's':
case'S':
case80:
move_down();
break;
case'w':
case'W':
case72:
move_up();
break;
case'd':
case'D':
case77:
move_right();
break;
}
score>best?best=score:1;/*打破得分纪录*/
if(if_need_add_num)/*默认为需要生成随机数时也同时需要刷新显示,反之亦然*/
{
add_rand_num();
refresh_show();
}
}
}
/*重置游戏函数定义*/
voidreset_game()
{
score=0;
if_need_add_num=1;
if_game_over=0;
/*了解到游戏初始化时出现的两个数一定会有个2,所以先随机生成一个2,其他均为0*/
intn=rand()%16;
for(inti=0;i<4;i++)
{
for(intj=0;j<4;j++)
{
board[i][j]=(n--==0?2:0);
}
}
/*前面已经生成了一个2,这里再生成一个随机的2或者4,且设定生成2的概率是4的两倍*/
add_rand_num();
/*在这里刷新界面并显示的时候,界面上已经默认出现了两个数字,其他的都为空(值为0)*/
system("cls");
refresh_show();
}
/*生成随机数函数定义*/
voidadd_rand_num()
{
srand(time(0));
intn=rand()%get_null_count();/*确定在何处空位置生成随机数*/
for(inti=0;i<4;i++)
{
for(intj=0;j<4;j++)
{
if(board[i][j]==0&&n--==0)/*定位待生成的位置*/
{
board[i][j]=(rand()%3?2:4);/*确定生成何值,设定生成2的概率是4的概率的两倍*/
return;
}
}
}
}
/*获取空位置数量函数定义*/
intget_null_count()
{
intn=0;
for(inti=0;i<4;i++)
{
for(intj=0;j<4;j++)
{
board[i][j]==0?n++:1;
}
}
returnn;
}
/*检查游戏是否结束函数定义*/
voidcheck_game_over()
{
for(inti=0;i<4;i++)
{
for(intj=0;j<3;j++)
{
/*横向和纵向比较挨着的两个元素是否相等,若有相等则游戏不结束*/
if(board[i][j]==board[i][j+1]||board[j][i]==board[j+1][i])
{
if_game_over=0;
return;
}
}
}
if_game_over=1;
}
/*
*如下四个函数,实现上下左右移动时数字面板的变化算法
*左和右移动的本质一样,区别仅仅是列项的遍历方向相反
*上和下移动的本质一样,区别仅仅是行项的遍历方向相反
*左和上移动的本质也一样,区别仅仅是遍历时行和列互换
*/
/*左移函数定义*/
voidmove_left()
{
/*变量i用来遍历行项的下标,并且在移动时所有行相互独立,互不影响*/
for(inti=0;i<4;i++)
{
/*变量j为列下标,变量k为待比较(合并)项的下标,循环进入时k<j*/
for(intj=1,k=0;j<4;j++)
{
if(board[i][j]>0)/*找出k后面第一个不为空的项,下标为j,之后分三种情况*/
{
if(board[i][k]==board[i][j])/*情况1:k项和j项相等,此时合并方块并计分*/
{
score+=board[i][k++]<<=1;
board[i][j]=0;
if_need_add_num=1;/*需要生成随机数和刷新界面*/
}
elseif(board[i][k]==0)/*情况2:k项为空,则把j项赋值给k项,相当于j方块移动到k方块*/
{
board[i][k]=board[i][j];
board[i][j]=0;
if_need_add_num=1;
}
else/*情况3:k项不为空,且和j项不相等,此时把j项赋值给k+1项,相当于移动到k+1的位置*/
{
board[i][++k]=board[i][j];
if(j!=k)/*判断j项和k项是否原先就挨在一起,若不是则把j项赋值为空(值为0)*/
{
board[i][j]=0;
if_need_add_num=1;
}
}
}
}
}
}
/*右移函数定义*/
voidmove_right()
{
/*仿照左移操作,区别仅仅是j和k都反向遍历*/
for(inti=0;i<4;i++)
{
for(intj=2,k=3;j>=0;j--)
{
if(board[i][j]>0)
{
if(board[i][k]==board[i][j])
{
score+=board[i][k--]<<=1;
board[i][j]=0;
if_need_add_num=1;
}
elseif(board[i][k]==0)
{
board[i][k]=board[i][j];
board[i][j]=0;
if_need_add_num=1;
}
else
{
board[i][--k]=board[i][j];
if(j!=k)
{
board[i][j]=0;
if_need_add_num=1;
}
}
}
}
}
}
/*上移函数定义*/
voidmove_up()
{
/*仿照左移操作,区别仅仅是行列互换后遍历*/
for(inti=0;i<4;i++)
{
for(intj=1,k=0;j<4;j++)
{
if(board[j][i]>0)
{
if(board[k][i]==board[j][i])
{
score+=board[k++][i]<<=1;
board[j][i]=0;
if_need_add_num=1;
}
elseif(board[k][i]==0)
{
board[k][i]=board[j][i];
board[j][i]=0;
if_need_add_num=1;
}
else
{
board[++k][i]=board[j][i];
if(j!=k)
{
board[j][i]=0;
if_need_add_num=1;
}
}
}
}
}
}
/*下移函数定义*/
voidmove_down()
{
/*仿照左移操作,区别仅仅是行列互换后遍历,且j和k都反向遍历*/
for(inti=0;i<4;i++)
{
for(intj=2,k=3;j>=0;j--)
{
if(board[j][i]>0)
{
if(board[k][i]==board[j][i])
{
score+=board[k--][i]<<=1;
board[j][i]=0;
if_need_add_num=1;
}
elseif(board[k][i]==0)
{
board[k][i]=board[j][i];
board[j][i]=0;
if_need_add_num=1;
}
else
{
board[--k][i]=board[j][i];
if(j!=k)
{
board[j][i]=0;
if_need_add_num=1;
}
}
}
}
}
}
/*刷新界面函数定义*/
voidrefresh_show()
{
/*重设光标输出位置方式清屏可以减少闪烁,system("cls")为备用清屏命令,均为Windows平台相关*/
COORDpos={0,0};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
printf("\n\n\n\n");
printf("GAME:2048SCORE:%06dBEST:%06d\n",score,best);
printf("--------------------------------------------------\n\n");
/*绘制表格和数字*/
printf("┌──┬──┬──┬──┐\n");
for(inti=0;i<4;i++)
{
printf("│");
for(intj=0;j<4;j++)
{
if(board[i][j]!=0)
{
if(board[i][j]<10)
{
printf("%d│",board[i][j]);
}
elseif(board[i][j]<100)
{
printf("%d│",board[i][j]);
}
elseif(board[i][j]<1000)
{
printf("%d│",board[i][j]);
}
elseif(board[i][j]<10000)
{
printf("%4d│",board[i][j]);
}
else
{
intn=board[i][j];
for(intk=1;k<20;k++)
{
n>>=1;
if(n==1)
{
printf("2^%02d│",k);/*超过四位的数字用2的幂形式表示,如2^13形式*/
break;
}
}
}
}
elseprintf("│");
}
if(i<3)
{
printf("\n├──┼──┼──┼──┤\n");
}
else
{
printf("\n└──┴──┴──┴──┘\n");
}
}
printf("\n");
printf("--------------------------------------------------\n");
printf("W↑A←→D↓S");
if(get_null_count()==0)
{
check_game_over();
if(if_game_over)/*判断是否输掉游戏*/
{
printf("\rGAMEOVER!TRYTHEGAMEAGAIN?[Y/N]");
}
}
}
以上所述就是本文的全部内容了,希望大家能够喜欢。