c语言实现2048小游戏

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>

int best = 0 ;


// 定义2048游戏的结构体 
typedef struct { 
	int martix[16];			// 当前4*4矩阵的数字 
	int martixPrior[16];	// 上一步的4*4矩阵的数字 
	int emptyIndex[16];		// 空位置的索引值 
	int emptyCount;			// 空位置的数量 
	int score;				// 当前的分数 
	int step;				// 记录操作步数 
}Game;

int solve_best(int best){
	FILE *file;

    file = fopen("C:/Users/Redmi/Desktop/a.txt", "w"); // 以写入方式打开文件,如果文件不存在则创建
    if (file == NULL) {
        perror("Error opening file");
        return -1;
    }

    // 向文件中写入内容
    fprintf(file, "%d", best);


    fclose(file); // 关闭文件
}

int get_best(){
	FILE *file;

    // 打开文件以读取原有数字
    file = fopen("C:/Users/Redmi/Desktop/a.txt", "r");
    if (file == NULL) {
        perror("Error opening file for reading");
        return -1;
    }
	
	int num = 0 ;
	
    // 读取原有数字
    int originalNumber;
    if (fscanf(file, "%d", &num) != 1) {
        perror("Error reading original number from file");
        fclose(file);
        return -1;
    }
	
    fclose(file); // 关闭文件
    return num ;
}

// 生成[min, max]的随机整数
int RandomInt(int min, int max) {	
	srand((unsigned)time(NULL) + rand());	//以时间为随机种子
	return min + rand() % (max - min + 1);
}


// 结构体的初始化 
void gameInit(Game *game) {
	int i;
	
	game->score = 0;
	game->step = 0;
	game->emptyCount = 16;
	for(i = 0; i < 16; i++) { 
		game->martix[i] = 0;
		game->martixPrior[i] = 0;
		game->emptyIndex[i] = -1;
	}
}


// 空位检测
void emptyDetect(Game *game) {
	int i = 0, j = 0;
	
	game->emptyCount = 0;
	for(i = 0; i < 16; i++) { game->emptyIndex[i] = -1; }
	for(i = 0; i < 16; i++) {
		if (game->martix[i] == 0) {
			game->emptyIndex[j++] = i;
			game->emptyCount++;
		}
	}
}


// 在随机空位生成数字
void numberGenerate(Game *game) {
	int pos, numberIs4;
	
	numberIs4 = RandomInt(0, 3);	// 生成数字4的概率,这里为 1/4 
	pos = game->emptyIndex[RandomInt(0, game->emptyCount - 1)];
	
	if (numberIs4 == 0) { game->martix[pos] = 4; } else { game->martix[pos] = 2; }
} 


// 获取某行或某列
int *getLine(int *martix, int row, int col) {
	int i, *array;
	
	array = (int *)malloc(sizeof(int)*4);
	for (i = 0; i < 4; i++) {
		if (col != -1) { *(array+i) = *(martix + col+(i*4)); }
		if (row != -1) { *(array+i) = *(martix + row*4+i); }
	}
	
	return array;
} 


// 数字边缘对齐 
int *numberAlign(int *array, int reverse) {
	// reverse : 0: 向左对齐、向上对齐;  1: 向右对齐,向下对齐
	// 0 0 2 0 --> 2 0 0 0
	// 2 0 2 0 --> 2 2 0 0
	
	int i, j;
	int *newArray;
	
	newArray = (int *)malloc(sizeof(int)*4);
	for(j = 0; j < 4; j++) { *(newArray + j) = 0; }
	
	if (reverse == 0) {
		j = 0;
		for(i = 0; i < 4; i++) {
			if (*(array + i) != 0) { 
				*(newArray + j) = *(array + i);
				j++;
			}
		}
	}
	
	if (reverse == 1) {
		j = 3;
		for(i = 3; i >= 0; i--) {
			if (*(array + i) != 0) {
				*(newArray + j) = *(array + i);
				j--;
			}
		}
	}
	
	return newArray;
}


// 相邻数字相加
int *numberMerge(Game *game, int *array, int reverse) {
	int i, j, num1, num2;
	int *newArray;
	
	newArray = (int *)malloc(sizeof(int)*4);
	
	if (reverse == 0) {
		j = 0;
		for (i = 0; i < 4; i++) {
			num1 = *(array + i);
			num2 = 0;
			if (i != 3) { num2 = *(array + i + 1); } 
			
			if (num1 == num2 && num1 > 0 && num2 > 0) {
				*(newArray + j) = num1 + num2;
				*(array + i + 1) = 0;
				game->score += (num1 + num2); 
			} else {
				*(newArray + j) = *(array + i);
			}
			j++;
		}
	}
	
	if (reverse == 1) {
		j = 3;
		for (i = 3; i >= 0; i--) {
			num1 = *(array + i);
			num2 = 0;
			if (i != 0) { num2 = *(array + i - 1); }
			
			if (num1 == num2 && num1 > 0 && num2 > 0) {
				*(newArray + j) = num1 + num2;
				*(array + i - 1) = 0;
				game->score += (num1 + num2);
			} else {
				*(newArray + j) = *(array + i);
			}
			j--;
		}
	}
	
	return newArray;
}


// 数字移动
void numberMoving(Game *game, int direction) {
	
	int *line[4];
	int i, j;
	
	switch(direction) {
		case 1:
			for (i = 0; i < 4; i++) {
				line[0] = getLine(game->martix, i, -1);
				line[1] = numberAlign(line[0], 0);
				line[2] = numberMerge(game, line[1], 0);
				line[3] = numberAlign(line[2], 0);
				for (j = 0; j < 4; j++) { 
					game->martix[i*4+j] = *(line[3] + j);
					game->martixPrior[i*4+j] = *(line[0] + j);
				}
			}
			break;
		
		case 2:
			for(i = 0; i < 4; i++) {
				line[0] = getLine(game->martix, i, -1);
				line[1] = numberAlign(line[0], 1);
				line[2] = numberMerge(game, line[1], 1);
				line[3] = numberAlign(line[2], 1);
				for (j = 0; j < 4; j++) { 
					game->martix[i*4+j] = *(line[3] + j);
					game->martixPrior[i*4+j] = *(line[0] + j);
				}
			}
			break;
		
		case 3:
			for(i = 0; i < 4; i++) {
				line[0] = getLine(game->martix, -1, i);
				line[1] = numberAlign(line[0], 0);
				line[2] = numberMerge(game, line[1], 0);
				line[3] = numberAlign(line[2], 0);
				for (j = 0; j < 4; j++) { 
					game->martix[i+4*j] = *(line[3] + j);
					game->martixPrior[i+4*j] = *(line[0] + j);
				}
			}
			break;
		
		case 4:
			for(i = 0; i < 4; i++) {
				line[0] = getLine(game->martix, -1, i);
				line[1] = numberAlign(line[0], 1);
				line[2] = numberMerge(game, line[1], 1);
				line[3] = numberAlign(line[2], 1);
				for (j = 0; j < 4; j++) { 
					game->martix[i+4*j] = *(line[3] + j); 
					game->martixPrior[i+4*j] = *(line[0] + j);
				}
			}
			break;
	}
	
	for (j = 0; j < 4; j++) { free(line[j]); }

}


// 游戏结束判定
int gameOverDetect(Game *game) {
	// 当判定为输时返回 1 
	
	int i, j, row, col;
	
	if (game->emptyCount > 0) { return 0; }
	for (i = 0; i < 16; i++) {
		int numberBeside[4] = {0, 0, 0, 0};		// 相邻上下左右四个位置的数字
		
		row = i / 4;
		col = i % 4;
		if (row - 1 >= 0) { numberBeside[0] = game->martix[(row-1)*4+col]; }		// 获取上面的数字
		if (row + 1 < 4) { numberBeside[1] = game->martix[(row+1)*4+col]; }			// 获取下面的数字 
		if (col - 1 >= 0) { numberBeside[2] = game->martix[row*4+(col-1)]; }		// 获取左边的数字 
		if (col + 1 < 4) { numberBeside[3] = game->martix[row*4+(col+1)]; }			// 获取右边的数字 
		
		for(j = 0; j < 4; j++) {
			if (game->martix[i] == numberBeside[j]) { return 0; }
		}
	}
	
	return 1;
} 


// 键盘操作 
int keyboardPress() {
	// 返回值: 0: 无效操作; 1、2、3、4: 左右上下;

	int charAscii;
	
	charAscii = _getch();
	if (charAscii == 65 || charAscii == 97) { return 1; }		// A, 左
	if (charAscii == 68 || charAscii == 100) { return 2; }		// D, 右
	if (charAscii == 87 || charAscii == 119) { return 3; }		// W, 上
	if (charAscii == 83 || charAscii == 115) { return 4; }		// S, 下 
	
	return 0;
}


// 检查数字是否移动过
int checkNumberMove(Game *game) {
	// 返回值: 0: 数字没有移动过; 1: 数字移动过 
	int i;
	
	for(i = 0; i < 16; i++) {
		if (game->martix[i] != game->martixPrior[i]) { return 1; } 
	}
	return 0;
}


// 游戏开始时随机生成2个数字 
void gameStart(Game *game) {
	int i;
	gameInit(game);
	emptyDetect(game);
	numberGenerate(game);
	emptyDetect(game);
	numberGenerate(game);
	emptyDetect(game);
}


// 绘制画面
void drawGame(Game *game) {
	int row;

	system("cls");
	printf("\n      GAME : 2 0 4 8 BEST : %d    \n",best);
	printf("\n按键说明:  W:上  A:左  S:下  D:右\n\n");
	for(row = 0; row < 4; row++) {
		if (row == 0) { printf("---------------------------------\n"); }
		printf("|\t|\t|\t|\t|\n");
		if (game->martix[row*4] != 0) { printf("|%7d", game->martix[row*4]); } else { printf("|\t"); }
		if (game->martix[row*4+1] != 0) { printf("|%7d", game->martix[row*4+1]); } else { printf("|\t"); }
		if (game->martix[row*4+2] != 0) { printf("|%7d", game->martix[row*4+2]); } else { printf("|\t"); }
		if (game->martix[row*4+3] != 0) { printf("|%7d|\n", game->martix[row*4+3]); } else { printf("|\t|\n"); }
		printf("|\t|\t|\t|\t|\n");
		printf("---------------------------------\n");
	}
	printf("步数: %d\n分数: %d\n\n", game->step, game->score);
} 


// 主程序 
int main() {
	Game *gamePtr;
	int key;
	best = get_best() ;
	gamePtr = (Game *)malloc(sizeof(Game));
	gameInit(gamePtr);
	gameStart(gamePtr);
	drawGame(gamePtr);

	while(gameOverDetect(gamePtr) != 1) {
		key = keyboardPress();
		
		// 移动数字后生成数字 
		if (key != 0) {
			numberMoving(gamePtr, key);
			if (checkNumberMove(gamePtr) != 0) {
				emptyDetect(gamePtr);
				numberGenerate(gamePtr);
				emptyDetect(gamePtr);
				gamePtr->step += 1;
				drawGame(gamePtr); 
			}
		}
	}
	printf("%d\n",gamePtr->score);
	if(gamePtr->score > best){
		solve_best(best) ;
	}
	printf("\n游 戏 结 束 !\n"); 
	return 0;
}

效果 : 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/520982.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.6(信息差)

&#x1f30d; 山西500千伏及以上输电线路工程首次采用无人机AI自主验收 &#x1f30b; 中国与泰国将开展国际月球科研站等航天合作 ✨ 网页版微软 PowerPoint 新特性&#xff1a;可直接修剪视频 &#x1f34e; 特斯拉开始在德国超级工厂生产出口到印度的右舵车 1.马斯克&…

Qt 使用QPropertyAnimation动画效果的图片浏览器

文章目录 效果图功能点代码解析图片切换显示与动画效果图片缩放 总结 效果图 功能点 加载指定路径下的所有图片并显示滑动滑动条查看指定图片&#xff0c;也滚轮切换图片滑动条缩略图加入动画效果图片可以进行缩放移动查看 代码解析 整体来说相对&#xff0c;显示图片的是一…

4.1 JavaScript的使用

JavaScript有两种使用方式&#xff1a;一是在HTML文档中直接添加代码&#xff1b;二是将JavaScript脚本代码写到外部的JavaScript文件中&#xff0c;再在HTML文档中引用该文件的路径地址。 这两种使用方式的效果完全相同&#xff0c;可以根据使用率和代码量选择相应的开发方式。…

【Qt】:常用控件(一:概述和QWidget核心属性)

常用控件 一.概述二.QWidget核心属性1.enabled&#xff08;是否可用&#xff09;2.geometry&#xff08;设置坐标&#xff09;3.WindTitle&#xff08;窗口标题&#xff09;4.windowIcon1.绝对路径2.qrc机制 5.windowOpacity&#xff08;透明度&#xff09; 一.概述 Widget是Q…

Spring源码解析-容器基本实现

spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…

SpringCloud学习(9)-GateWay网关-自定义拦截器

GateWay Filter详细配置说明 gateway Filter官网:Spring Cloud Gateway 作用&#xff1a; 请求鉴权异常处理记录接口调用时长统计 过滤器类别 全局默认过滤器&#xff1a;官网&#xff1a;Spring Cloud Gateway&#xff0c;出厂默认已有的&#xff0c;直接用&#xff0c;作…

【详细讲解0基础如何进入IT行业】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

Deep Image Prior

自监督的开创性工作 从简单分布到复杂分布的映射&#xff0c;本质上是将重建限制到某一流形&#xff0c;在流形上通过观测图像的数据保真项作为监督。 称之为先验也是很准确&#xff0c;流形就是先验。 这个扰动也很关键&#xff0c;本质上一个平滑正则项。直观理解是各种扰动…

Redis从入门到精通(四)Redis实战(一)短信登录

文章目录 前言第4章 Redis实战4.1 短信登录4.1.1 基于session实现短信登录4.1.1.1 短信登录逻辑梳理4.1.1.2 创建测试项目4.1.1.3 实现发送短信验证码功能4.1.1.4 实现用户登录功能4.1.1.5 实现登录拦截功能4.1.1.6 session共享问题 4.1.2 基于Redis实现短信登录4.1.2.1 Key-Va…

MATLAB - 用命令行设计 MPC 控制器

系列文章目录 前言 本例演示如何通过命令行创建和测试模型预测控制器。 一、定义工厂模型 本示例使用《使用 MPC Designer 设计控制器》中描述的工厂模型。创建工厂的状态空间模型&#xff0c;并设置一些可选的模型属性&#xff0c;如输入、状态和输出变量的名称和单位。 % co…

(阿里云万网)-域名注册购买实名流程

1&#xff0c;进入阿里云网万官网 输入网址 https://wanwang.aliyun.com/?spm5176.161059.J_3207526240.33.581fa505OGhzsW 注册域名 &#xff0c;域名推荐com&#xff08;国际顶级域名&#xff09; &#xff0c;cn&#xff08;国内顶级域名&#xff09;。其中cn价钱比com便…

状态机高阶讲解-16

2534 01:44:41,942 --> 01:44:44,140 那我们&#xff0c;你看这里 2535 01:44:45,170 --> 01:44:46,452 你看这里改之后 2536 01:44:46,452 --> 01:44:48,833 它代码就做新的调整了嘛 2537 01:44:48,833 --> 01:44:49,200 对吧 2538 01:44:50,150 --> 01:44…

smbms:超市订单管理系统(项目分析)

smbms&#xff1a;超市订单管理系统&#xff08;项目分析&#xff09; 文章目录 smbms&#xff1a;超市订单管理系统&#xff08;项目分析&#xff09;前言一、项目介绍&#xff1a;二、项目来源&#xff1a;三、架构图&#xff1a;&#xff08;流程图&#xff09;四、使用了什…

【论文阅读】CompletionFormer:深度完成与卷积和视觉变压器

【论文阅读】CompletionFormer:深度完成与卷积和视觉变压器 文章目录 【论文阅读】CompletionFormer:深度完成与卷积和视觉变压器一、介绍二、联系工作深度完成Vision Transformer 三、方法四、实验结果 CompletionFormer: Depth Completion with Convolutions and Vision Tran…

腾讯云添加域名后不生效

问题原因 添加域名后不生效可能是因为没有加CDN域名解析 解决步骤

手动实现Tomcat底层机制+自己设计Servlet

文章目录 1.Tomcat整体架构分析自己理解 2.第一阶段1.实现功能2.代码1.TomcatV1.java 3.调试阶段1.阻塞在readLine导致无法返回结果 4.结果演示 3.第二阶段1.实现功能2.代码1.RequestHander.java2.TomcatV2.java 3.调试阶段1.发现每次按回车会接受到两次请求 4.结果演示 4.第三…

【Python使用】嘿马头条完整开发md笔记第4篇:数据库,1 方案选择【附代码文档】

嘿马头条项目从到完整开发笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;课程简介&#xff0c;ToutiaoWeb虚拟机使用说明1 产品介绍,2 原型图与UI图,3 技术架构,4 开发,1 需求,2 注意事项。数据库&#xff0c;理解ORM1 简介,2 安装,3 数据库连接…

C++要点细细梳理(下)(内存分配、异常处理、template和文件读写)

4. 类动态内存分配 4.1 C语言动态内存分配&#xff1a;malloc和free 4.2 C动态内存分配&#xff1a;new和delete 思考&#xff1a;定义一个对象和定义一个普通变量有何区别? 普通变量:分配足够空间即可存放数据对象:除了需要空间&#xff0c;还要构造/析构 类比&#xff1a;…

关于 VScode, 点击文件右键或者在文件夹中没有 【 在vscode中打开选项】 解决办法

关于 VScode, 点击文件右键或者在文件夹中没有 【 在vscode中打开选项】 解决办法 段子手-168 2024-4-6 1、在任意位置创建一个文本文件。如&#xff1a;a.txt 2、复制以下代码到 a.txt 文本文件中。 &#xff08;注&#xff1a; 以 ; 开头的 , 是备注信息 , 不需要做任何修…

代码随想录第19天

654. 最大二叉树 已解答 中等 相关标签 相关企业 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀…