• 2048游戏


    声明:本程序绝大部分属于原创,交互部分参考了博客园 Judge Young的原创文章 游戏2048源代码 - C语言控制台界面版,
    作者Judge Young的算法思想非常值得参考,感谢作者的分享
    附上文章链接:https://www.cnblogs.com/judgeyoung/p/3760515.html

    算法总体思想:(请结合思维导图观看,移动合并算法篇幅较大,部分放到函数注释)

    1. 游戏主体抽象:将游戏数字面板抽象为一个二维数组,0代表空格。
    2. 移动合并算法:把每一行/列同等对待,只研究一行/列的移动和合并算法,通过遍历来实现所有行/列的移动合并算法。
    3. 游戏结束条件:分为三种情况,主动退出、游戏失败和游戏胜利。
    4. 随机数生成:寻找出空格,平均概率生成2 / 4。
    5. 界面显示:利用清屏再打印,达到界面刷新效果。
    6. 计分系统:游戏结束时,将所有格子中数字相加得到最终分数。
    7. 矩阵翻转:为了减少代码量与复用函数,提高练习效果,这里牺牲了部分效率。
    8. 备注:移动合并算法也可以通过矩阵翻转90度达到更好的函数复用效果,但效率更低。
    9. 再备注:函数声明处有一个撤回功能,可以利用old_squares做出来,但由于作者嫌麻烦所以没有做。
    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <time.h>
    
    #define N	4				//矩阵大小为N * N
    #define Max 2048			//胜利条件 
    
    int squares[N][N];			//游戏矩阵
    int sum;					//游戏积分
    int old_squares[N][N];		//之前一步操作的矩阵 
    
    void GameStart(void);		//游戏开始界面
    void Print(void);			//打印界面、计分
    void Operator(char op);		//对用户交互进行处理
    int Operated(void);			//判断矩阵是否发生变化 
    void Copy(void);			//备份上一步的矩阵 
    void MoveUp(int op);		//上移方格
    void MoveLeft(int op);		//左移方块 
    void Transpose(int op);		//矩阵翻转
    int GameOver(char op);		//游戏结束:失败,退出和游戏胜利(需设置条件)
    int Win(void);				//判断游戏胜利 
    //void Recall(void);		//撤回功能 
    void Random(void);			//生成随机数
    int HasNull(void);			//判断矩阵存在空白位置
    void PrintSum(void);		//计算游戏积分并打印
    
    int main(void)
    {
    	char op = ' ';
    
    	GameStart();
    	Random();
    	Operator(op);
    	while (!GameOver(op)) {
    		Copy();
    		while (!Operated()) {
    			op = getch();
    			Operator(op);
    		}
    		Random();
    		system("cls");
    		Print();
    	}
    	system("pause");
    	
    	return 0;
    }
    
    //初始化游戏参数
    void GameStart(void) {
    	int i, j;
    
    	sum = 0;
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			squares[i][j] = 0;
    			old_squares[i][j] = 0;
    		}
    	}
    	
    	printf("Press any key to start the game.
    ");
    }
    
    //打印矩阵
    void Print(void) {
    	int i, j;
    
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			if (squares[i][j] == 0) {
    				printf(" 	");
    				continue;
    			}
    			printf("%d	", squares[i][j]);
    		}
    		printf("
    
    ");
    	}
    	
    	printf("
    ");
    	printf("(W)Up (S)Down (A)Left (D)Right
    ");
    	printf("    (Q)Quit (R)Recall
    
    ");
    }
    
    
    void Operator(char op) {
    	switch (op) {
    	case 'w':
    	case 'W':
    		MoveUp(1); break;
    	case 'a':
    	case 'A':
    		MoveLeft(1); break;
    	case 's':
    	case 'S':
    		MoveUp(0); break;
    	case 'd':
    	case 'D':
    		MoveLeft(0); break;
    	default:
    		break;
    	}
    }
    
    int Operated(void) {
    	int i, j;
    	
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			if (old_squares[i][j] != squares[i][j])
    				return 1;
    		}
    	}
    	
    	return 0;
    }
    
    void Copy(void) {
    	int i, j;
    	
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			old_squares[i][j] = squares[i][j];
    		}
    	}
    }
    
    //在一行中,使用两个下标变量来遍历列项,假设使用j和k,其中j总在k的后面,用来寻找k项后面第一个不为0的数字,而k项用于表示当前待比较的项,总是和j项之间隔着若干个数字0,或者干脆紧挨着。
    void MoveUp(int op) {
    	int i, j, k;
    
    	if (op == 0)
    		Transpose(0);
    	
    	for (i = 0; i < N; i++) {
    		for (j = 1, k = 0; j < 4; j++) {
    			if (squares[j][i] > 0) { /* 找出k后面第一个不为空的项,下标为j,之后分三种情况 */
    				//合并
    				if (squares[k][i] == squares[j][i]) {
    					squares[k][i] = 2 * squares[k][i];
    					squares[j][i] = 0;
    					k++;
    				}
    				//移动
    				else if (squares[k][i] == 0) {
    					squares[k][i] = squares[j][i];
    					squares[j][i] = 0;
    				}
    				//碰撞
    				else {
    					squares[k + 1][i] = squares[j][i];
    					if (j != k + 1) { /* 原先两数不挨着 */
    						squares[j][i] = 0;
    					}
    					k++;
    				}
    			}
    		}
    	}
    	
    	if (op == 0)
    		Transpose(0);
    }
    
    void MoveLeft(int op) {
    	int i, j, k;
    
    	if (op == 0)
    		Transpose(1);
    	
    	for (i = 0; i < N; i++) {
    		for (j = 1, k = 0; j < 4; j++) {
    			if (squares[i][j] > 0) {
    				//合并
    				if (squares[i][k] == squares[i][j]) {
    					squares[i][k] = 2 * squares[i][k];
    					squares[i][j] = 0;
    					k++;
    				}
    				//移动
    				else if (squares[i][k] == 0) {
    					squares[i][k] = squares[i][j];
    					squares[i][j] = 0;
    				}
    				//碰撞
    				else {
    					squares[i][k + 1] = squares[i][j];
    					if (j != k + 1) { /* 原先两数不挨着 */
    						squares[i][j] = 0;
    					}
    					k++;
    				}
    			}
    		}
    	}
    	
    	if (op == 0)
    		Transpose(1);
    }
    
    void Transpose(int op) {
    	int i, j, temp = 0;
    
    	//左右翻转
    	if (op == 1) {
    		for (i = 0; i < N; i++) {
    			for (j = 0; j < N / 2; j++) {
    				temp = squares[i][j];
    				squares[i][j] = squares[i][N - j - 1];
    				squares[i][N - j - 1] = temp;
    			}
    		}
    	}
    	//上下翻转
    	else {
    		for (i = 0; i < N; i++) {
    			for (j = 0; j < N / 2; j++) {
    				temp = squares[j][i];
    				squares[j][i] = squares[N - j - 1][i];
    				squares[N - j - 1][i] = temp;
    			}
    		}
    	}
    }
    
    int GameOver(char op) {
    	int i, j;
    
    	if (op == 'q' || op == 'Q')
    		printf("You have quit the game! GameOver!
    ");
    	else if (Win())
    		printf("Congratulation! You win!
    ");
    	else {
    		if (HasNull())
    			return 0;
    		for (i = 1; i < N; i++) {
    			for (j = 0; j < N; j++) {
    				//任意两个相邻的单元值相同,游戏继续
    				if (squares[i - 1][j] == squares[i][j])
    					return 0;
    				if (squares[j][i - 1] == squares[j][i])
    					return 0;
    			}
    		}
    	}
    	
    	PrintSum();
    	return 1;
    }
    
    int Win(void) {
    	int i, j;
    	
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			if (squares[i][j] == Max)
    				return 1;
    		}
    	}
    	
    	return 0;
    }
    
    //在矩阵中随机位置生成数字2/4
    void Random(void) {
    	int sitex, sitey;
    
    	sitex = rand() % 4;
    	sitey = rand() % 4;
    	while (squares[sitex][sitey] != 0) {
    		sitex = rand() % 4;
    		sitey = rand() % 4;
    	}
    	
    	//生成2的概率是2/3,生成4的概率是1/3 
    	if (rand() % 3 == 0)
    		squares[sitex][sitey] = 4;
    	else
    		squares[sitex][sitey] = 2;
    }
    
    int HasNull(void) {
    	int i, j;
    
    	for (i = 0; i < N; i++) {
    		for (j = 0; j < N; j++) {
    			if (squares[i][j] == 0)
    				return 1;
    		}
    	}
    	
    	return 0;
    }
    
    void PrintSum(void) {
    	int i, j;
    
    	for (i = 0; i < N; i++)
    		for (j = 0; j < N; j++)
    			sum += squares[i][j];
    	
    	printf("Game Over! Your total score is: %d! 
    ", sum);
    }
    
  • 相关阅读:
    linux进程管理类
    linux关机重启指令
    linux分区及磁盘挂载
    linux的运行级别
    property
    访问限制机制
    类的组合与封装
    继承与派生
    logging模块
    re模块
  • 原文地址:https://www.cnblogs.com/tuzkizki/p/13638933.html
Copyright © 2020-2023  润新知