在学习 标C之后,试着做的一个小游戏
设计思路:
1、 打印界面
(界面初始化,采用二维数组)
2、操作控制
(上下左右操作时数组计算)
3、判断以及重打印
(判断是否操作有效以及游戏结束)
设计思路:
1、 打印界面
(界面初始化,采用二维数组)
2、操作控制
(上下左右操作时数组计算)
3、判断以及重打印
(判断是否操作有效以及游戏结束)
4、文件保存
缺点:
1、 文件代码不够精简,很多地方都可以优化
2、初次用多文件处理,文件管理有点混乱
3、注释不够
界面如下:
-----------------------------------------------------------------------------------------------
代码如下:
头文件
headfile.h
#ifndef __HEADFILE_H__
#define __HEADFILE_H__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 4
int arr[SIZE][SIZE];
int score;
int best;
int if_game_over;
extern same[SIZE][SIZE];
// linux_getch.c
char my_getch();
// show.c
void refresh_show();
void start_game();
// file.c
void read_file();
void save_file(int, int);
// main.c
void game_operate();
// opertate.c
void assign(void);
int same_judge(void);
int game_judge(void);
void add_number(void);
void move_up(void);
void move_left(void);
void move_down(void);
void move_right(void);
void restart(void);
#endif //__HEADFILE_H__
游戏入口
2048.c
#include "headfile.h"
int main(void)
{
srand((unsigned)time(0));
read_file();
start_game();
return 0;
}
主操作面板
main.c
#include "headfile.h"
int same[SIZE][SIZE] = {};
void start_game()
{
int judge = 0;
char quit =0;
char move =0;
while(1)
{
refresh_show();
assign(); //记录数组,对比可知操作后数字是否有移动
move = my_getch();
switch(move)
{
case 'w':
case 'W':
move_up();
break;
case 'a':
case 'A':
move_left();
break;
case 's':
case 'S':
move_down();
break;
case 'd':
case 'D':
move_right();
break;
case 'q':
case 'Q':
printf("Are you sure? Y/N\n");
quit = getchar();
if (quit == 'y' || quit == 'Y')
{
save_file(score, best);
return;
}
else
continue;
case 'r':
case 'R':
restart();
score = 0;
continue;
default:
continue;
}
save_file(score, best);
switch (game_judge())
{
case 2:
printf("YOU WIN !!!\n");
printf("Do you want to play again (Y/N)\n");
restart();
score = 0;
save_file(score, best);
quit = getchar();
if (quit == 'y' || quit == 'Y')
{
continue;
}
else
{
return;
}
case 1:
break;
default:
printf("\e[31mYOU FAIL !!!\e[m\n");
printf("Do you want to restart (Y/N)\n");
restart();
score = 0;
save_file(score, best);
quit = getchar();
if (quit == 'y' || quit == 'Y')
{
continue;
}
else
{
return;
}
}
if (same_judge())
{
continue;
}
add_number();
}
}
界面显示
show.c
#include "headfile.h"
void line(void)
{
int i = 0;
for (i =0; i <SIZE; i++)
{
printf("-----");
}
}
void set_number(int row, int vol)
{
switch(arr[row][vol])
{
case 0:
printf("|\e[1;47m \e[m");
break;
case 2:
printf("|\e[0;43;37m 2 \e[m");
break;
case 4:
printf("|\e[0;44;37m 4 \e[m");
break;
case 8:
printf("|\e[0;45;37m 8 \e[m");
break;
case 16:
printf("|\e[0;45;37m 16 \e[m");
break;
case 32:
printf("|\e[0;47;34m 32 \e[m");
break;
case 64:
printf("|\e[1;47;34m 64 \e[m");
break;
case 128:
printf("|\e[1;47;35m 128\e[m");
break;
case 256:
printf("|\e[1;47;31m 256\e[m");
break;
case 512:
printf("|\e[1;47;31m 512\e[m");
break;
case 1024:
printf("|\e[1;47m1024\e[m");
break;
case 2048:
printf("|\e[1;47m2048\e[m");
break;
default:
break;
}
}
void refresh_show(void)
{
int i =0, j =0;
system("clear");
printf("\n\n");
printf(" GAME: 2048\n");
printf(" SCORE BEST \n");
printf(" %-4d \e[31m %d\e[m \n", score, best);
line();
printf("\n");
for(i =0; i <SIZE; i++)
{
for(j =0; j <SIZE; j++)
{
set_number(i, j);
}
printf("|");
printf("\n");
line();
printf("\n");
}
printf("Q(exit) R(restart)\n");
}
移动与判断
operate.c
#include "headfile.h"
void move_up(void)
{
int i =0, j =0; // 循环变量
int point = 0; // 定位作用
for (i =0; i <SIZE; i++)
{
point = 0;
for(j =1; j <SIZE; j++)
{
//如果没这个if,则要在两者相等处做个同为O的分支
if (arr[j][i] > 0)
{
// 定位点要不为0,不为0则有可能与对比数相等或不相等`
if (arr[point][i] == arr[j][i])
{
arr[point][i] *= 2;
score += arr[point][i];
arr[j][i] = 0;
point++;
}
else if(arr[point][i] == 0)
{
arr[point][i] = arr[j][i];
arr[j][i] = 0;
}
else
{
arr[++point][i] = arr[j][i];
if (point != j)
{
arr[j][i] = 0;
}
}
}
}
}
}
void move_down(void)
{
int i =0, j =0; // 循环变量
int point = 0; // 定位作用
for (i =0; i <SIZE; i++)
{
point = SIZE-1;
for(j =SIZE-2; j >=0; j--)
{
//如果没这个if,则要在两者相等处做个同为O的分支
if (arr[j][i] > 0)
{
// 定位点要不为0,不为0则有可能与对比数相等或不相等`
if (arr[point][i] == arr[j][i])
{
arr[point][i] *= 2;
score += arr[point][i];
arr[j][i] = 0;
point--;
}
else if(arr[point][i] == 0)
{
arr[point][i] = arr[j][i];
arr[j][i] = 0;
}
else
{
arr[--point][i] = arr[j][i];
if (point != j)
{
arr[j][i] = 0;
}
}
}
}
}
}
void move_left(void)
{
int i =0, j =0; // 循环变量
int point = 0; // 定位作用
for (i =0; i <SIZE; i++)
{
point = 0;
for(j =1; j <SIZE; j++)
{
//如果没这个if,则要在两者相等处做个同为O的分支
if (arr[i][j] > 0)
{
// 定位点要不为0,不为0则有可能与对比数相等或不相等`
if (arr[i][point] == arr[i][j])
{
arr[i][point] *= 2;
score += arr[i][point];
arr[i][j] = 0;
point++;
}
else if(arr[i][point] == 0)
{
arr[i][point] = arr[i][j];
arr[i][j] = 0;
}
else
{
arr[i][++point] = arr[i][j];
if (point != j)
{
arr[i][j] = 0;
}
}
}
}
}
}
void move_right(void)
{
int i =0, j =0; // 循环变量
int point = 0; // 定位作用
for (i =0; i <SIZE; i++)
{
point = SIZE-1;
for(j =SIZE-2; j >=0; j--)
{
//如果没这个if,则要在两者相等处做个同为O的分支
if (arr[i][j] > 0)
{
// 定位点要不为0,不为0则有可能与对比数相等或不相等`
if (arr[i][point] == arr[i][j])
{
arr[i][point] *= 2;
score += arr[i][point];
arr[i][j] = 0;
point--;
}
else if(arr[i][point] == 0)
{
arr[i][point] = arr[i][j];
arr[i][j] = 0;
}
else
{
arr[i][--point] = arr[i][j];
if (point != j)
{
arr[i][j] = 0;
}
}
}
}
}
}
int game_judge(void)
{
int i = 0, j = 0;
// 判断是否胜利
for (i =0; i <SIZE; i++)
for(j =0; j <SIZE; j++)
{
if (arr[i][j] == 2048)
{
return 2;
}
}
//判断是否有空格,有则继续
for (i =0; i <SIZE; i++)
for(j =0; j <SIZE; j++)
{
if(arr[i][j] == 0)
{
return 1;
}
}
//判断是否相邻有重复,有则游戏继续
for (i =0; i <SIZE; i++)
for(j =0; j <SIZE-1; j++)
{
if ((arr[i][j] == arr[i][j+1]) || (arr[j][i] == arr[j+1][i]))
{
return 1;
}
}
//没地可走,则game over
return 0;
}
void add_number(void)
{
int num = rand() % 3 ? 2 : 4; // 生成2的概率是4的2倍
int un[SIZE * SIZE] = {}; // 记录没有被占据的位置
int i = 0, j =0, cnt = 0;
int loc = 0;
for (i =0; i <SIZE; i++)
for (j =0; j <SIZE; j++)
{
//if (arr[i][j] == 0 && loc-- == 0 )
if (arr[i][j] == 0)
{
un[cnt] = i * 10 + j;
cnt++;
}
}
loc = rand() % cnt; //随机挑选未被占据的位置
// 复原数组存放数字对应的序列
i = un[loc] / 10;
j = un[loc] % 10;
arr[i][j] = num;
}
void restart(void)
{
int i = 0, j = 0;
int row = 0, vol = 0;
for (i =0; i <SIZE; i++)
for(j =0; j <SIZE; j++)
{
arr[i][j] = 0;
}
row = rand() % SIZE;
vol = rand() % SIZE;
arr[row][vol] = 2;
add_number();
}
void assign(void)
{
int i =0, j =0;
for (i =0; i <SIZE; i++)
for (j =0; j <SIZE; j++)
{
same[i][j] = arr[i][j];
}
}
int same_judge()
{
int i = 0, j =0;
for (i =0; i <SIZE; i++)
for (j =0; j <SIZE; j++)
{
if (same[i][j] != arr[i][j])
{
return 0;
}
}
return 1;
}
实现键盘输入不回显,不用按回车(网上摘录)
my_getch.h
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
char my_getch()
{
struct termios tm, tm_old;
int fd = STDIN_FILENO;
char c =0;
if (tcgetattr(fd, &tm) < 0)
{
return -1;
}
tm_old = tm;
cfmakeraw(&tm);
if (tcsetattr(fd, TCSANOW, &tm) < 0)
{
return -1;
}
c = fgetc(stdin);
if (tcsetattr(fd,TCSANOW,&tm_old) < 0)
{
return -1;
}
return c;
}
文件处理
file.c
#include "headfile.h"
void read_file(void)
{
FILE *fp;
// 打开记录上次游戏的位置
if (!(fp = fopen("location.txt", "rb")))
{
printf("Fail to read the file\n");
return;
}
if(!(fread(arr, sizeof(arr), 1, fp)))
{
printf("fail to open the record!");
}
fclose(fp);
// 打开记录分数文档
if (!(fp = fopen("score.txt", "rb")))
{
printf("Fail to read the file");
return;
}
if(!(fread(&score, sizeof(int), 1, fp)))
{
printf("Not record the score last time!");
}
fclose(fp);
// 打开记录最高分文档
if (!(fp = fopen("best.txt", "rb")))
{
printf("Fail to read the file");
return;
}
if(!(fread(&best, sizeof(int), 1, fp)))
{
printf("Need you to do the best!");
}
fclose(fp);
}
void save_file(int score, int best)
{
FILE *fp;
// 记录上次游戏的位置
if (!(fp = fopen("location.txt", "wb")))
{
printf("Fail to read the file");
return;
}
if(!(fwrite(arr, sizeof(arr), 1, fp)))
{
printf("fail to save the record!");
}
fclose(fp);
// 记录分数
if (!(fp = fopen("score.txt", "wb")))
{
printf("Fail to read the file");
return;
}
if(!(fwrite(&score, sizeof(int), 1, fp)))
{
printf("fail to save the record!");
}
fclose(fp);
// 记录最高分
if (score > best)
{
best = score;
}
if (!(fp = fopen("best.txt", "wb")))
{
printf("Fail to read the file");
return;
}
if(!(fwrite(&best, sizeof(int), 1, fp)))
{
printf("fail to save the record!");
}
}