作者在 2019-01-21 18:26:50 发布以下内容
#include <conio.h> //为了读取方向键
#include <windows.h>//控制dos界面(获取控制台上坐标位置、设置字体颜色)
#include <math.h> //pow函数
#include <stdio.h> //标准输入输出函数库(printf、scanf)
/*******函 数 声 明*******/
void gotoxy(int x, int y); //获取屏幕光标位置
int color(int c); //设置文字颜色
int TextColors(int i); //根据数字修改颜色
void drawTheGameBox(); //绘制游戏界面
int *add(int item[]); //合并数字
int ifMove(int item[]); //判断是否能够移动数字,返回1能动,0不能动
void Gameplay(); //开始游戏
void Replay(); //重新游戏
int if2n(int x); //判断x是否是2的n次方
int ifup(); //判断是否能够上移 可以上移(格子中的两个数相加是2的n次方),则返回1 不能移动,则返回0
int ifdown(); //判断是否能够下移 可以下移(格子中的两个数相加是2的n次方),则返回1 不能移动,则返回0
int ifleft(); //判断是否能够左移 可以左移(格子中的两个数相加是2的n次方),则返回1 不能移动,则返回0
int ifright(); //判断是否能够右移 可以右移(格子中的两个数相加是2的n次方),则返回1 不能移动,则返回0
int BOXmax(); //返回棋盘最大数
int Gamefaile(); //判断是否失败
int Gamewin(); //判断是否胜利
int keyboardControl(int key); //键盘控制移动
void close(); //关闭游戏
void title(); //绘制标题(2048字符画)
void choice(); //选择框
void Rabbit(); //绘制字符画
void regulation(); //游戏规则介绍
void explation(); //按键说明
/*******定 义 全 局 变 量*******/
int step=0; //已执行步数
int score=0; //存储游戏分数
long int Time; //游戏运行时间
int BOX[4][4]={0,0,0,0, //游戏中的16个格子
0,0,0,0,
0,0,0,0,
0,0,0,0};
HANDLE hOut; //控制台句柄
/**
* 获取屏幕光标位置
*/
void gotoxy(int x, int y)
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
/**
* 文字颜色函数 此函数的局限性:1、只能Windows系统下使用 2、不能改变背景颜色
*/
int color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //更改文字颜色
return 0;
}
/**
* 根据数字修改颜色
*/
int TextColors(int number)
{
switch (number) //格子中出现的2和2的次方显示为不同颜色
{ //数字1~15代表不同的文字颜色,超过15表示文字背景色
case 2:
return color(12);
break;
case 4:
return color(11);
break;
case 8:
return color(10);
break;
case 16:
return color(14);
break;
case 32:
return color(6);
break;
case 64:
return color(5);
break;
case 128:
return color(4);
break;
case 256:
return color(3);
break;
case 512:
return color(2);
break;
case 1024:
return color(9);
break;
case 2048:
return color(7);
break;
}
return 0;
}
/**
* 绘制游戏界面 4*4的网格
*/
void drawTheGameBox()
{
int i,j,k;
gotoxy(16,1); //屏幕坐标位置
color(11); //淡浅绿色
printf("游戏分数: %ld",score);
color(13); //粉色
gotoxy(42,1); //屏幕坐标位置
printf("执行步数: %d\n",step);
color(14); //黄色
for(j = 2;j <= 22;j += 5) //打印棋盘边框
{
gotoxy(15,j);
for(k = 1;k<42;k++)
{
printf("-");
}
printf("\n");
}
for (i = 3;i < 7;i ++)
{
gotoxy(15,i);
printf("| | | | | ");
}
for (i = 8;i<12;i++)
{
gotoxy(15,i);
printf("| | | | | ");
}
for (i = 13;i<17;i++)
{
gotoxy(15,i);
printf("| | | | | ");
}
for (i = 18;i<22;i++)
{
gotoxy(15,i);
printf("| | | | | ");
}
gotoxy(44,23);
color(10); //绿色
printf("已用时:%d s",time(NULL) - Time); //输出游戏运行时间
}
/**
* 合并数字
*/
int* add(int item[])
{
int i = 0, j = 0;
int tep[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 < 4; i ++)
{
// if(tep[0] == 0) break; //如果格子里没有数字,返回
if(tep[i] == tep[i + 1]) //如果两个数字相同,则合并
{
tep[i] *= 2; //一个格子中的数字翻倍,另一个为空
tep[i + 1] = 0;
score=score+tep[i]; //加分,加的分数为消除的数字*2
}
}
j = 0;
for(i = 0; i < 4; i ++)
{
if(tep[i] != 0)
{
tmp[j ++] = tep[i];
}
}
return (int *)(&tmp); //tmp为指针的引用,*&指针本身可变
}
/**
* 判断能否移动数字,返回1能动,0不能动
*/
int ifMove(int item[])
{
int i = 0;
for(i = 0; i < 3; i ++)
{
if(item[i] != 0 && item[i] == item[i + 1]) //如果两个相邻两位上数字相同,能移动,返回1
{
return 1;
}
if(item[i] == 0 && item[i + 1] != 0) //如果两个相邻两位上,一个是空格子,一个上有数字,也能移动,返回1
{
return 1;
}
}
return 0; //不能合并,返回0
}
/**
* 判断x是否是2的n次方,是2的n次方,返回1,否则返回0
*/
int if2n(int x)
{
int flag = 0;
int n;
int N = 1;
for(n = 1;n <= 11;n++) //2的11次方是2048,游戏目标是达到2048
{
if(x == pow(2,n)) //计算2的n次方
{
flag = 1;
if(n>N)
N = n;
return flag;
}
}
return flag;
}
/**
* 判断是否能够上移 可以上移,则返回1 不能移动,则返回0
*/
int ifup()
{
int i,j;
int flag = 0; //定义标志变量,只有0或1
for(j = 0;j < 4;j ++)
for(i = 0;i < 3;i ++)
{
if((if2n(BOX[i][j] + BOX[i+1][j]) == 1) && BOX[i+1][j]) //如果上下两个格子相加是2的n次方,并且下面的格子中有数
{
flag = 1; //可以上移
}
}
return flag; //返回1表示可以上移,返回0表示不能上移
}
/**
* 判断是否能够下移 可以下移,则返回1 不能移动,则返回0
*/
int ifdown()
{
int i,j;
int flag = 0;
for(j = 0;j < 4;j ++)
for(i = 3;i > 0;i --)
{
if((if2n(BOX[i][j] + BOX[i-1][j]) == 1) && BOX[i-1][j]) //如果上下两个格子相加是2的n次方,并且上面的格子中有数
{
flag = 1; //可以下移
}
}
return flag; //返回1表示可以下移,返回0表示不能下移
}
/**
* 判断是否能够左移 可以左移,则返回1 不能移动,则返回0
*/
int ifleft()
{
int i,j;
int flag = 0;
for(i = 0;i < 4;i ++)
for(j = 0;j < 3;j ++)
{
if((if2n(BOX[i][j] + BOX[i][j+1]) == 1) && BOX[i][j+1]) //如果左右两个格子相加是2的n次方,并且右面的格子中有数
{
flag = 1; //可以左移
}
}
return flag; //返回1表示可以左移,返回0表示不能左移
}
/**
* 判断是否能够右移 可以右移,则返回1 不能移动,则返回0
*/
int ifright()
{
int i,j;
int flag = 0;
for(i = 0;i < 4;i ++)
for(j = 3;j > 0;j --)
{
if((if2n(BOX[i][j] + BOX[i][j-1]) == 1) && BOX[i][j-1]) //如果左右两个格子相加是2的n次方,并且左面的格子中有数
{
flag = 1; //可以下右移
}
}
return flag; //返回1表示可以右移,返回0表示不能右移
}
/**
* 返回棋盘最大数
*/
int BOXmax()
{
int max = BOX[0][0]; //初始化BOX数组
int i,j;
for(i = 0;i < 4;i ++) //遍历整个数组
{
for(j = 0;j < 4;j ++)
{
if(BOX[i][j] > max) //如果数组中有数值大于max的值
{
max = BOX[i][j]; //将数组中的值赋值给max,这样找出数组中的最大数
}
}
}
return max; //返回max的值。也就是当前棋盘中的最大值
}
/**
* 判断是否失败 加一个输出棋盘最大数
*/
int Gamefaile()
{
int flag = 0;
int max;
if(ifup() + ifdown() + ifleft() + ifright() == 0) //当上下左右都不能移动的时候,游戏失败
// if(ifMove(BOX))
{
system("cls");
gotoxy(34,3);
color(14);
printf("合并出的最大数是:");
gotoxy(52,3);
color(11);
max = BOXmax();
printf("%d",max);
gotoxy(19,6);
color(4); //暗红色
printf(" ■■■■■ ■ ■ ■■ \n"); //输出end字符画
gotoxy(19,7);
printf(" ■ ■■ ■ ■ ■ \n");
gotoxy(19,8);
printf(" ■ ■ ■ ■ ■ ■ \n");
gotoxy(19,9);
printf(" ■ ■ ■ ■ ■ ■ \n");
gotoxy(19,10);
printf(" ■■■■ ■ ■ ■ ■ ■ \n");
gotoxy(19,11);
printf(" ■ ■ ■ ■ ■ ■ \n");
gotoxy(19,12);
printf(" ■ ■ ■ ■ ■ ■ \n");
gotoxy(19,13);
printf(" ■ ■ ■ ■ ■ ■ \n");
gotoxy(19,14);
printf(" ■■■■■ ■ ■■ ■■ \n");
gotoxy(34,17);
color(13);
printf("无法移动,游戏失败!"); //提示文字
flag = 1;
}
return flag; //flag的值正常是0,返回1则表示游戏失败
}
/**
* 判断是否胜利
*/
int Gamewin()
{
int flag = 0;
if(BOXmax() == 2048) //如果棋盘中的最大值为2048,达到目标,则游戏胜利
{
system("cls");
gotoxy(1,6);
color(2); //暗绿色
printf(" ■ ■ ■ ■■■■■ ■ ■ \n"); //输出胜利win的字符画
gotoxy(1,7);
printf(" ■ ■■ ■ ■ ■ ■ ■ \n");
gotoxy(1,8);
printf(" ■ ■ ■ ■ ■ ■ ■ ■ \n");
gotoxy(1,9);
printf(" ■ ■ ■ ■ ■ ■ ■ ■ \n");
gotoxy(1,10);
printf(" ■ ■ ■ ■ ■ ■ ■ ■ \n");
gotoxy(1,11);
printf(" ■ ■ ■ ■ ■ ■ ■ ■ \n");
gotoxy(1,12);
printf(" ■ ■ ■ ■ ■ ■ ■ ■ \n");
gotoxy(1,13);
printf(" ■■ ■■ ■ ■ ■ ■ \n");
gotoxy(1,14);
printf(" ■ ■ ■■■■■ ■ ■ \n");
gotoxy(35,17);
color(13);
printf("胜利啦,你真棒!!!");
flag = 1;
}
return flag; //flag的值正常是0,返回1则表示游戏胜利
}
/**
* 键盘控制移动
*/
int keyboardControl(int key) {
int i = 0, j = 0;
int *p;
int tp[4] = {0, 0, 0, 0};
switch(key) //LEFT = 75, UP = 72, RIGHT = 77, DOWN = 80;
{
case 72: // up
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 = add(tp); //获得合并之后的数值
if(!ifMove(tp)) //判断是否可以移动,可以移动,则新出现一个数字;不能移动但按键了,也不会出现新数字
//if(ifup())
{
j++; //向上移动
}
BOX[0][i] = p[0]; //把处理好的中间变量移回来
BOX[1][i] = p[1];
BOX[2][i] = p[2];
BOX[3][i] = p[3];
}
return j != 4; //当j不超过4的时候,可以执行up操作
case 80: // 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 = add(tp);
if(!ifMove(tp))
{
j++;
}
BOX[3][i] = p[0];
BOX[2][i] = p[1];
BOX[1][i] = p[2];
BOX[0][i] = p[3];
}
return j != 4;
case 75: // 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 = add(tp);
if(!ifMove(tp))
{
j++;
};
BOX[i][0] = p[0];
BOX[i][1] = p[1];
BOX[i][2] = p[2];
BOX[i][3] = p[3];
}
return j != 4;
case 77: // 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 = add(tp);
if(!ifMove(tp))
// if(ifright() == 1)
{
j++;
}
BOX[i][3] = p[0];
BOX[i][2] = p[1];
BOX[i][1] = p[2];
BOX[i][0] = p[3];
}
return j != 4;
case 27: //按ESC
gotoxy(20,23);
color(12);
printf("确定退出游戏么? (y/n)");
char c = getch(); //获得键盘输入
if(c == 'y' ||c == 'Y') //如果输入的是大写或者小写的y
{
exit(0); //退出游戏
}
if(c == 'n'||c == 'N') //如果输入的是大写或者小写的n
{
gotoxy(20,23);
printf(" "); //继续游戏
}
break;
default: return 0;
}
}
/**
* 开始游戏
*/
void Gameplay()
{
system("cls"); //清屏
int i = 0, j = 0;
Time = time(NULL); //取当前时间为开始时间
drawTheGameBox(); //绘制游戏界面
int a,b; //BOX[][]数组的横纵坐标
srand(time(NULL)); //设置随机数种子,初始化随机数
do
{
a = rand()%4; //获得4*4棋盘中的随机位置
b = rand()%4;
}while(BOX[a][b]!=0); //一直到棋盘中没有空格
if(rand() % 4 == 0) //2或4随机出现在空格处(最开始出现在棋盘上的2或4)
{
BOX[a][b] = 4;
}
else
{
BOX[a][b] = 2;
}
for(i = 0; i < 4; i ++) //遍历整个网格
{
for(j = 0; j < 4; j ++)
{
if(BOX[i][j] == 0) //如果网格中有空位,就继续下去
{
continue;
}
// gotoxy(17 + j * 8 + 3 + (j * 2), i * 4 + (i + 5)); //设置棋子显示位置
gotoxy(15 + j * 10 + 5, 2 + i * 5 + 3); //设置棋子显示位置
int c = BOX[i][j]; //获得棋盘上BOX[i][j]上的数字
TextColors(c); //设置棋子的颜色,不同数字显示不同颜色
printf("%d", c); //打印棋子
}
}
while(1) {
while (kbhit()) //kbhit()检查当前是否有键盘输入,有返回1,否则返回0
{
if(!keyboardControl(getch())) //如果按下的按键不是在keyboardControl()方法中定义的,会没有反应,一直到按下定义的按键为止
{
continue;
}
drawTheGameBox(); //绘制棋盘
for(i = 0; i < 4; i ++) //循环整个4*4的棋盘
{
for(j = 0; j < 4; j ++)
{
if(BOX[i][j] == 0) //如果棋盘中有空位,则可一直进行按键
{
continue;
}
gotoxy(15 + j * 10 + 5, 2 + i * 5 + 3);//合并后的数出现的位置
int c = BOX[i][j];
TextColors(c);
printf("%d", c);
}
}
do{
a = rand()%4;
b = rand()%4; //获得随机位置
}while(BOX[a][b]!=0);
if(rand() % 4 == 0) //2或4随机出现在空格处(进行方向操作合并之后,在空白处出现)
{
BOX[a][b] = 4; //随机位置上设置为4
} else {
BOX[a][b] = 2; //随机位置上设置为2
}
step++; //进行计步
// gotoxy(17 + b * 8 + 3 + (b * 2), a * 4 + (a + 5));//合并后的数出现的位置
gotoxy(15 + b * 10 + 5, 2 + a * 5 + 3); //随机出现的2或4
int c = BOX[a][b];
TextColors(c);
printf("%d", c);
}
if(Gamefaile()+Gamewin() != 0) //只要Gamefaile()或者Gamewin()任意一个函数返回1,也就是成功或是失败都会出现下面的内容
{
int n;
gotoxy(20,20);
color(12);
printf("我要重新玩一局-------1");
gotoxy(45,20);
printf("不玩了,退出吧-------2\n");
gotoxy(43,21);
color(11);
scanf("%d", &n);
switch (n)
{
case 1:
Replay(); //重新游戏函数
break;
case 2:
close(); //关闭游戏函数
break;
}
}
}
}
/**
* 重新游戏
*/
void Replay()
{
system("cls"); //清屏
score = 0,step = 0; //分数、步数归零
memset(BOX,0,16*sizeof(int)); //初始化BOX数组
Gameplay(); //开始游戏
}
/**
* 主函数。程序入口
*/
int main() {
// system("cls"); //清屏
title(); //打印标题
Rabbit(); //打印字符画
choice(); //菜单选项
}
/**
* 设置标题
*/
void title()
{
color(11); //浅淡绿色
gotoxy(19,2);
printf("■■■ ■■■■ ■ ■ ■■■■"); //输出2048字符画
gotoxy(19,3);
printf(" ■ ■ ■ ■ ■ ■ ■");
gotoxy(19,4);
printf("■■■ ■ ■ ■ ■ ■■■■");
gotoxy(19,5);
printf("■ ■ ■ ■■■■ ■ ■");
gotoxy(19,6);
printf("■■■ ■■■■ ■ ■■■■");
}
/**
* 菜单选项
*/
void choice()
{
int n;
int i,j = 1;
gotoxy(32,8);
color(13);
printf("挑 战 2 0 4 8");
color(14); //黄色边框
for (i = 9; i <= 20; i++) //输出上下边框===
{
for (j = 15; j <= 60; j++) //输出左右边框||
{
gotoxy(j, i);
if (i == 9 || i == 20) printf("=");
else if (j == 15 || j == 59) printf("||");
}
}
color(12);
gotoxy(25, 12);
printf("1.开始游戏");
gotoxy(40, 12);
printf("2.游戏规则");
gotoxy(25, 16);
printf("3.按键说明");
gotoxy(40, 16);
printf("4.退出");
gotoxy(21,22);
color(5);
printf("请选择[1 2 3 4]:[ ]\b\b");
scanf("%d", &n); //输入选项
switch (n)
{
case 1:
Gameplay(); //游戏开始函数
break;
case 2:
regulation(); //游戏规则函数
break;
case 3:
explation(); //按键说明函数
break;
case 4:
close(); //关闭游戏函数
break;
}
}
/**
* 绘制小花
*/
void Rabbit()
{
// gotoxy(66,12);
// color(12);
// printf("(_)");
//
// gotoxy(64,13);
// color(12);
// printf("(_)");
//
// gotoxy(67,13);
// color(6);
// printf("@");
//
// gotoxy(68,13);
// color(12);
// printf("(_)");
//
// gotoxy(66,14);
// color(12);
// printf("(_)");
//
// gotoxy(70,14);
// color(6);
// printf("\\"); //注意、\为转义字符。想要输入\,必须在前面需要转义
//
// gotoxy(70,15);
// color(6);
// printf("`|/");
//
// gotoxy(70,16);
// color(6);
// printf("\\|");
//
// gotoxy(71,17);
// color(6);
// printf("| /");
//
// gotoxy(67,18);
// color(10);
// printf("\\\\\\\\");
//
// gotoxy(71,18);
// color(6);
// printf("|");
//
// gotoxy(73,18);
// color(10);
// printf("//");
//
// gotoxy(67,19);
// color(10);
// printf("^^^^^^^^");
color(3);
gotoxy(64,10);
printf("┏-┓ ┏-┓");
gotoxy(64,11);
printf("┃ ┃ ┃ ┃");
gotoxy(64,12);
printf("┃ ┃ ┃ ┃");
gotoxy(63,13);
printf("_┃");
gotoxy(74,13);
printf("┃_");
gotoxy(62,14);
printf("┃");
gotoxy(76,14);
printf("┃");
gotoxy(62,15);
printf("┃ ┃");
gotoxy(62,16);
printf("┃");
gotoxy(76,16);
printf("┃");
gotoxy(62,17);
printf("┃ ┃");
gotoxy(62,18);
printf("┗━┳━━┳━┛");
gotoxy(64,19);
printf("┏┫ ┣┓");
gotoxy(62,20);
printf("—┺┻━┻┻┹—");
color(5);
gotoxy(67,13);
printf("`~ '~`");
color(4);
gotoxy(67,14);
printf("○ ○");
color(13);
gotoxy(65,15);
printf("〃");
gotoxy(74,15);
printf("〃");
color(12);
gotoxy(69,17);
printf("┻");
}
/**
* 退出
*/
void close()
{
exit(0);
}
/**
* 游戏规则介绍
*/
void regulation()
{
int i,j = 1;
system("cls");
color(13);
gotoxy(34,3);
printf("游戏规则");
color(2);
for (i = 6; i <= 18; i++) //输出上下边框===
{
for (j = 15; j <= 70; j++) //输出左右边框||
{
gotoxy(j, i);
if (i == 6 || i == 18) printf("=");
else if (j == 15 || j == 69) printf("||");
}
}
color(3);
gotoxy(18,7);
printf("tip1: 玩家可以通过↑ ↓ ← →方向键来移动方块");
color(10);
gotoxy(18,9);
printf("tip2: 按ESC退出游戏");
color(14);
gotoxy(18,11);
printf("tip3: 玩家选择的方向上,若有相同的数字则合并");
color(11);
gotoxy(18,13);
printf("tip4: 每移动一步,空位随机出现一个2或4");
color(4);
gotoxy(18,15);
printf("tip5: 棋盘被数字填满,无法进行有效移动,游戏失败");
color(5);
gotoxy(18,17);
printf("tip6: 棋盘上出现2048,游戏胜利");
getch(); //按任意键返回主界面
system("cls");
main();
}
/**
* 按键说明
*/
void explation()
{
gotoxy(20,22);
color(13);
printf("①、↑、↓、←、→方向键进行游戏操作!");
gotoxy(20, 24);
printf("②、ESC键退出游戏");
// color(8);
getch(); //按任意键返回主界面
system("cls");
main();
}