2048游戏(C语言LINUX环境下,键盘读取实例)
2048游戏(C语言LINUX环境下,键盘读取实例)目录2048游戏(C语言LINUX环境下,键盘读取实例)一、Linux键盘值的调用 “get_keyboard.h”二、代码基本思路三、源代码一、Linux键盘值的调用 “get_keyboard.h”在Linux下是没有自带的调取键盘的库的,所以我们得自己写一个头文件“get_keyborad.h”来获取键盘的值。当然如果在Windows环境
·
2048游戏(C语言LINUX环境下,键盘读取实例)
一、Linux键盘值的调用 “get_keyboard.h”
在Linux下是没有自带的调取键盘的库的,所以我们得自己写一个头文件“get_keyborad.h”来获取键盘的值。当然如果在Windows环境下,直接调用“conio.h”头文件中就可以了。
// get_keyboard.h在linux下没有直接的get_ch()读取键盘,所以要自己写一个。
#ifndef GETCH_H
#define GETCH_H
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
typedef enum KEYBOARD
{
KEY_UP = 183,
KEY_DOWN = 184,
KEY_RIGHT = 185,
KEY_LEFT = 186,
KEY_BACKSPACE = 127,
KEY_ENTER = 10,
KEY_0 = 48,
KEY_1 = 49,
KEY_2 = 50,
KEY_3 = 51,
KEY_4 = 52,
KEY_5 = 53,
KEY_6 = 54,
KEY_7 = 55,
KEY_8 = 56,
KEY_9 = 57,
KEY_A = 65,
KEY_B = 66,
KEY_C = 67,
KEY_D = 68,
KEY_E = 69,
KEY_F = 70,
KEY_G = 71,
KEY_H = 72,
KEY_I = 73,
KEY_J = 74,
KEY_K = 75,
KEY_L = 76,
KEY_M = 77,
KEY_N = 78,
KEY_O = 79,
KEY_P = 80,
KEY_Q = 81,
KEY_R = 82,
KEY_S = 83,
KEY_T = 84,
KEY_U = 85,
KEY_V = 86,
KEY_W = 87,
KEY_X = 88,
KEY_Y = 89,
KEY_Z = 90,
KEY_a = 97,
KEY_b = 98,
KEY_c = 99,
KEY_d = 100,
KEY_e = 101,
KEY_f = 102,
KEY_g = 103,
KEY_h = 104,
KEY_i = 105,
KEY_j = 106,
KEY_k = 107,
KEY_l = 108,
KEY_m = 109,
KEY_n = 110,
KEY_o = 111,
KEY_p = 112,
KEY_q = 113,
KEY_r = 114,
KEY_s = 115,
KEY_t = 116,
KEY_u = 117,
KEY_v = 118,
KEY_w = 119,
KEY_x = 120,
KEY_y = 121,
KEY_z = 122
}KEYBOARD;
//此函数能立即从键盘不回显的接收数据
static int get_keyboard(void)
{
//接收系统调用的执行结果
int ret = 0;
//存储终端设备的配置信息
struct termios old;
//通过系统调用获取终端的配置信息
ret=tcgetattr(STDIN_FILENO,&old);
if(0 > ret)
{
perror("tcgetattr");
return -1;
}
//初始化新的终端配置信息
struct termios new = old;
//取消回显并立即获取
new.c_lflag &= ~(ICANON|ECHO);
//设置新的终端配置信息
ret= tcsetattr(STDIN_FILENO,TCSANOW,&new);
if(0 > ret)
{
perror("tcsetattr");
return -2;
}
//在新的模式下从终端获取数据
int key_value = 0;
do
{
key_value += getchar();
//由于和系统对FILE结构体的实现各不相同
//linux系统 while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//OS系统 while(stdin->_r);
}while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//还原终端的配置信息
ret = tcsetattr(STDIN_FILENO,TCSANOW,&old);
if(0 > ret)
{
perror("tcsetattr");
return -3;
}
//返回获取到的数据
return key_value;
}
#endif//GETCH_H
二、代码基本思路
-
先初始化加载游戏界面,用二维char类型数组(char map [row1] [col1])来储存交互界面。
-
再建一个数值的二维数组(int nmap [row2] [col2])来储存每个格子的数值。
-
将数值数组和界面数组建立映射关系,就可以把数值直接反应到交互界面。
-
生成随机数,存放到nmap中,刚开始生成3个,之后一次生成一个随机数(2、4、8)。
-
方向键的调用与游戏运行的函数设计
-
key = get_keyboard();获取方向值
-
调用函数判断,对是否能进行移动进行判断。
-
此处,我采取的是==将每一个方向重新抽离出来==,这样就可以四个方向进行一起判断,再重新写回
-
如果能移动,那么是否存在两个相邻或者其中间隔若干个空格的两数相同,如果存在则合并
-
先合并完成再进行移动。
-
顺便计算一下得分情况。
-
三、源代码
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include"get_keyboard.h" //#include <conio.h> windows下通过这个头文件获取键盘值。
#define MAX_ROW 6 //规格MAX_ROW*MAX_ROW
#define EACH_ROW 3 //每个格子的高度
#define EACH_COL 7 //每个格子的宽度
#define TOTAL_ROW MAX_ROW*(1+EACH_ROW)+1 //总共需要的行数
#define TOTAL_COL MAX_ROW*(1+EACH_COL)+1 //总共需要的列数
#define EACH_TIME_NUM 3 //初始化数字个数<EACH_TIME_NUM
void load();
int multi(int a,int b){ //求指数
int i;
int s = 1;
for(i=0;i<b;i++){
s*=a;
}
return s;
}
void findplace(int *px,int *py,int flag){ //数值和地图位置的映射关系
*px = (flag/MAX_ROW)*(EACH_ROW+1)+EACH_ROW/2+1;
*py = (flag%MAX_ROW)*(EACH_COL+1)+EACH_COL/2+1;
}
void printf_map(char (*map)[]){ //打印游戏地图
int i,j;
char (*board)[TOTAL_COL] = map;
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
printf("%c",board[i][j]);
}
printf("\n");
}
}
int num_len(int num){ //求int的位数
int cnt = 0;
while(num>0){
num/=10;
++cnt;
}
return cnt;
}
int can_arr_move(int arr[]){
int i=0;
int cnt = 0;
for(i=0;i<MAX_ROW;i++){
while(arr[i]==0){
cnt++;
i++;
if(cnt==MAX_ROW) return 0;
}
if(cnt>0 && arr[i]!=0 && i<MAX_ROW){
return 1;
}
if(i<MAX_ROW-1 && arr[i] == arr[i+1] && arr[i]!=0){
return 1;
}
}
return 0;
}
int arr_move(int arr[],int (*nmap)[MAX_ROW],int *pscore){
int i;
int p;
int n=0;
int temp;
for(i=0;i<MAX_ROW;i++){
while(i<MAX_ROW-1 && arr[i]==0){//找到首非零元素
i++;
}
if(i == MAX_ROW-1) break;
p = i+1;
while(p<MAX_ROW && arr[p]==0) ++p;//找下一个非零元素的位置
if(p==MAX_ROW) break;
if(arr[p]==arr[i]){//如果两数相等则合并
arr[i] = arr[i]*2;
*pscore += arr[i];
arr[p] = 0;
i = p;
}
}
//合并完成后,开始移动位置
for(i=1;i<MAX_ROW;i++){
temp = i;
while(arr[temp-1]==0&&temp>0){
arr[temp-1] = arr[temp];
arr[temp] = 0;
--temp;
}
}
}
int can_move(int (*nmap)[MAX_ROW],int dirc,int mod,int *pscore){
int i,j;
int x,y;
int arr[MAX_ROW]={0};
int res = 0;
int cnt=0;
// 把所有序列转存到新的数组arr
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
arr[j] = nmap[j][i];
break;
case KEY_DOWN:
arr[j] = nmap[MAX_ROW-j-1][i];
break;
case KEY_LEFT:
arr[j] = nmap[i][j];
break;
case KEY_RIGHT:
arr[j] = nmap[i][MAX_ROW-j-1];
break;
}
}
res = can_arr_move(arr);
if(mod && res) return 1;
cnt += res;
// 如果可以移动,反向存回nmap(4*4数字表)
if(res){
arr_move(arr,nmap,pscore);
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
nmap[j][i] = arr[j];
break;
case KEY_DOWN:
nmap[MAX_ROW-j-1][i] = arr[j];
break;
case KEY_LEFT:
nmap[i][j] = arr[j];
break;
case KEY_RIGHT:
nmap[i][MAX_ROW-j-1] = arr[j];
break;
}
}
}
}
return cnt;
}
int move(char (*map)[TOTAL_COL],int (*nmap)[MAX_ROW],int dirc,int *pscore){ //运动
int i,j,k;
int cnt0=0;//记录0的个数
int x=0,y=0;
int nlen=0;
int m2;
if(can_move(nmap,dirc,0,pscore)){
srand((unsigned)time(NULL));
int a = rand()%3+1;
m2 = multi(2,a); //2^1~2^3
int p = rand()%(MAX_ROW*MAX_ROW);
while(nmap[p/MAX_ROW][p%MAX_ROW]!=0){
p = rand()%(MAX_ROW*MAX_ROW);
}
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
//将nmap 4*4的int数组 映射到map里。
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
findplace(&x,&y,i*MAX_ROW+j);
nlen = num_len(nmap[i][j]);
for(k=0;k<EACH_COL-2;k++){
map[x][y-EACH_COL/2+k] = ' ';//每次清空上次数据
}
if(nmap[i][j]!=0){
for(k=0;k<nlen;k++){
map[x][y-nlen/2+k] = nmap[i][j]/multi(10,nlen-k-1)%10+'0';//以字符的形式传入
}
}
}
}
}
for(i=0;i<MAX_ROW*MAX_ROW;i++){
if(nmap[i/MAX_ROW][i%MAX_ROW]==0){
++cnt0;
break;
}
}
printf(" SCORE: %d\n",*pscore);
printf_map(map);
if(cnt0==0 && can_move(nmap,KEY_UP,1,pscore)==0 && can_move(nmap,KEY_LEFT,1,pscore)==0){
return -1;
}
}
void play(char (*map)[],int (*nmap)[],int *pscore){
int key;
int r=0;
while(1){
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
switch(key){
case KEY_UP:
case KEY_DOWN:
case KEY_LEFT:
case KEY_RIGHT:
system("clear"); //windows system("cls")
r = move(map,nmap,key,pscore);
break;
case KEY_R:
case KEY_r:
system("clear"); //windows system("cls")
load();
break;
case KEY_Q:
case KEY_q: exit(0);
}
if(r==-1) {
printf("Game over ~\n");
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
if(key == KEY_R || key == KEY_r) load();
else exit(0);
}
}
}
void load(){
int i,j;
int m,p;
int m2;
int score = 0;
char map[TOTAL_ROW][TOTAL_COL];
system("clear"); //windows system("cls")
printf("小游戏1024\n");
printf("press 'r' to restart , press 'q' to quit.");
printf("\nAre you ready? Press any key to start ...\n");
get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
system("clear"); //windows system("cls")
printf(" SCORE: %d\n",score);
//初始化 游戏界面设计
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
if(i%(1+EACH_ROW)==0||i==TOTAL_ROW-1){
map[i][j] = '-';
}
else{
if(j%(1+EACH_COL)==0||j==TOTAL_COL-1){
map[i][j] = '|';
}
else{
map[i][j] = ' ';
}
}
}
}
//初始化值
srand((unsigned)time(NULL));
int x=0;
int y=0;
int nmap[MAX_ROW][MAX_ROW] = {0};
for(i=0;i<EACH_TIME_NUM;i++){
m = rand()%3+1;
m2 = multi(2,m);
p = rand()%16;
findplace(&x,&y,p);
map[x][y] = m2+'0';
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
}
printf_map(map);
play(map,nmap,&score);
}
int main(){
load();
return 0;
}
四、运行结果
更多推荐
已为社区贡献1条内容
所有评论(0)