这是我在大一第二学期(两年前)为了参加比赛,自学后写的一个Demo,拿出来和大家分享一下,代码为两年前的代码,未改动,优化以及各式可能很一般,请见谅。
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#define N 4//方阵边长
#define WIN 2048//游戏获胜目标
void output(int (*a)[N]){//输出4*4表格,
int i,j;
printf("\n");
printf("┏━━━━┳━━━━┳━━━━┳━━━━┓");//顶边框
printf("\n");
for(i=0;i<N;i++){printf("┃") ;
for(j=0;j<N;j++){
if(a[i][j]==0) printf(" ┃");//如果数值为零则输出空白
else printf("%4d┃",a[i][j]);
}
if(i!=3)
printf("\n┣━━━━╋━━━━╋━━━━╋━━━━┫\n");//层边框
else printf("\n┗━━━━┻━━━━┻━━━━┻━━━━┛\n");//底边框
}
}
int sj24(){//获取随机数2或4
int s[8]={2,2,2,2,2,2,2,4},i,j;//以概率7:1建立2和4的随机数种子
srand((unsigned)time(NULL));
i=(rand())%8;//以时间为种子得到0~7的随机数
return s[i];
}
int input(){//输入上下左右指令控制游戏
int m;
if(getch()==0xE0){ //对键入的命令进行识别
switch(getch()){//十位1表示水平移动2表示竖直移动,各位1表示向小坐标移动2表示向大坐标移动
case 72: return 21;break;//输入上
case 80: return 22;break;//输入下
case 75: return 11;break;//输入右
case 77: return 12;break;//输入左
default:{//若命令不符合要求,运用递归重新得到命令
printf("请输入正确的指令!(~ ̄(OO) ̄)ブ\n");
return input();
}
}
}
else {//若命令不符合要求,运用递归重新得到命令
printf("请输入正确的指令!(~ ̄(OO) ̄)ブ\n\n");
return input();
}
}
void move(int (*a)[N]){ //通过调用input函数得到正确的命令,根据命令移动数据
int x,i,j,k,s[N][N],t=0;
x=input();
for(i=0;i<N;i++){
for(j=0;j<N;j++) s[i][j]=a[i][j];//拷贝移动前方阵方便以后检查
}
if(x/10==1){//水平移动
if(x%10==1){//向小坐标移动
for(i=0;i<N;i++){for(k=0;k<3;k++){// 核心算法介绍
for(j=N-1;j>0;j--){ //第一步,先将一排数据重后往前一个个向前推(除去前面和中间的0)
if(a[i][j-1]==0) { //为确保移动完全经推理最多3次完成所有移动所有执行3次该算法
a[i][j-1]=a[i][j]; //第二步,将相邻两两相同的数相加赋值前者后者赋0
a[i][j]=0; // 第三部,重复第一步操作去除新产生的0,总操作完成
} //PS:所有方向算法原理相同
}
}
for(j=0;j<N-1;j++){
if(a[i][j]==a[i][j+1]) {
a[i][j]=a[i][j]+a[i][j+1];
a[i][j+1]=0;
}
}
for(k=0;k<3;k++){
for(j=N-1;j>0;j--){
if(a[i][j-1]==0) {
a[i][j-1]=a[i][j];
a[i][j]=0;
}
}
}
}
}
else{//向大坐标移动
for(i=0;i<N;i++){for(k=0;k<3;k++){
for(j=0;j<N-1;j++){
if(a[i][j+1]==0) {
a[i][j+1]=a[i][j];
a[i][j]=0;
}
}
}
for(j=N-1;j>0;j--){
if(a[i][j]==a[i][j-1]) {
a[i][j]=a[i][j]+a[i][j-1];
a[i][j-1]=0;
}
}
for(k=0;k<3;k++){
for(j=0;j<N-1;j++){
if(a[i][j+1]==0) {
a[i][j+1]=a[i][j];
a[i][j]=0;
}
}
}
}
}
}
else{//竖直移动
if(x%10==1){//向小坐标移动
for(i=0;i<N;i++){for(k=0;k<3;k++){
for(j=N-1;j>0;j--){
if(a[j-1][i]==0) {
a[j-1][i]=a[j][i];
a[j][i]=0;
}
}
}
for(j=0;j<N-1;j++){
if(a[j][i]==a[j+1][i]) {
a[j][i]=a[j][i]+a[j+1][i];
a[j+1][i]=0;
}
}
for(k=0;k<3;k++){
for(j=N-1;j>0;j--){
if(a[j-1][i]==0) {
a[j-1][i]=a[j][i];
a[j][i]=0;
}
}
}
}
}
else{//向大坐标移动
for(i=0;i<N;i++){for(k=0;k<3;k++){
for(j=0;j<N-1;j++){
if(a[j+1][i]==0) {
a[j+1][i]=a[j][i];
a[j][i]=0;
}
}
}
for(j=N-1;j>0;j--){
if(a[j][i]==a[j-1][i]) {
a[j][i]=a[j][i]+a[j-1][i];
a[j-1][i]=0;
}
}
for(k=0;k<3;k++){
for(j=0;j<N-1;j++){
if(a[j+1][i]==0) {
a[j+1][i]=a[j][i];
a[j][i]=0;
}
}
}
}
}
}
for(i=0;i<N;i++){//检查是否为有效移动
for(j=0;j<N;j++) {
if (s[i][j]!=a[i][j]) t=1;
}
}
if(t){
begin(a);
Sleep(60);//为让玩家知道移动后随机数出现位置,让其延迟出现
get(a);
begin(a);
}
else printf("选择其他方向试试(¬_¬)");
}
void get(int (*a)[N]){//在4*4表格中空板位置随机获得数字
int i,j;
srand((unsigned)time(NULL));
do{
i=(rand())%4;
j=(rand())%4;
} while(a[i][j]!=0);
a[i][j]=sj24();
}
void begin(int (*a)[N]){//清屏并打印开头
system("cls");
printf(" 小游戏2048\n\n ");
printf(" 键入上下左右控制\n");
output(a);
}
int test(int (*a)[N]){//判断是否游戏完成
int i,j,k=0,m=0,n=0;
printf("\n");
for(i=0;i<N;i++){
for(j=0;j<N;j++){
if(a[i][j]==0)m=1;//检查方阵中是否有0
if(a[i][j]==WIN)k=1; //检查方阵中是否有目标数字
}
}
if (k){//如果发现目标数字判定游戏获胜
printf("YOU WIN! \(^o^)/YES!");
return 0;
}
else{
if(!m){//如果方阵中无0且无相邻数字相等则判定游戏失败,反之游戏继续
for(i=0;i<N;i++){
for(j=0;j<N-1;j++)
if(a[i][j]==a[i][j+1]||a[j][i]==a[j+1][i]) n=1;
}
if(n) return 1;
else{
printf("GAME OVER!〒▽〒");
return 0;
}
}
else return 1;
}
}
void main(){
int a[N][N]={0};
get(a);get(a);begin(a);//起始时方阵有两个随机数
while(test(a)) move(a); //只有通过tset函数检查才能继续游戏
} //谢谢
原说明文档:
作品名:小游戏2048
使用语言:C语言
使用编译器:DEV-C++
游戏说明:《2048》是一款比较流行的数字游戏,最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块(2或4),相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048
程序设计思路:
在程序编写之前我只知道游戏的规则和对游戏把玩的经验。后来对游戏原理进行思考,大体的得到了程序编写的方向。
首先我需要一个4*4的表格来填放数字,可用二维数组来表达,用一个4*4的二维数组,初值设定为0。
开始在4*4的表格中随机出现两个2或4的随机数,为保证游戏难度正常出现2的概率应大于出现4的概率(P2:P4=7:1),然后键入一次方向键后进行相应移动、合并。完成移动后在表格中空白位置出现一个2或4的随机数。
游戏胜负判定:若数字“2048”出现则为获胜并输出“YOU WIM!”,若数字填满方格且每个数字无相邻相等(即不可移动)则为失败并输出“GAME OVER!”
核心算法(移动合并):第一步,先将需要操作的一行数据的非零数字向需移动方向靠齐(去0)。第二步,将相邻相等数字相加,靠近需移动的一个赋二者的和另一个赋0,若有连续三个数字相等,操作前两个。若前两个后两个均可合并,可同时操作。第三步,重复第一步操作,去除第二步新产生的0。
算法细节详见源文件代码及注释。
程序完成截图
: