70,038
社区成员
发帖
与我相关
我的任务
分享任务描述
本关任务:编写一个 2048 小游戏。
相关知识
为了完成本关任务,你需要掌握:C 语言基础。
游戏规则
首先我们来描述一下 2048 游戏的规则;
1.游戏开始的时候,在一个 5*5 的二维空间,随机产生 2;
2.可以选择上下左右的滑动,如果遇到相同的数字,该数字乘 2;
3.滑动结束后,检测是否有剩余的空间,如果有,则在该位置随机生成 2;
4.然后继续步骤 2.
5.如果检测到有数字 2048,游戏胜利,则游戏结束;无法继续滑动,游戏失败,游戏结束。
基于以上规则,我们设计游戏结构:
生成二维 5*5 的空间,以数组 map[5][5] 描述,随机种子数 rand();
滑动的函数 move();由于四个方向的移动代码类似,可以专门写一个移动的类实现;
检测是否可以移动的函数,gameover();
在终端显示的类 display;
对于初学者,我们可以先写出一维空间的“2048”;
核心功能
1. 游戏失败
主要思想:如果数组当中还有 0,说明还能移动,返回 0,说明游戏还没结束呢。25 个格子全部有数字,都不为 0,接下来判断5行,5 列。每相邻两个数字,是否有相同的,如果有,说明通过移动还可以动,return 1 说明 25 个格子全部都有数字,都不为 0,而且各个方向无论怎么移动都不能合并,那么游戏结束 game over。
代码:
1. #define SIZE 25
2. #define width 5
3. int is_dead()
4. {
5. int i, j;
6. for(i = 0; i < SIZE; i++)
7. {
8. if(!arr[i])
9. {
10. return 0;
11. }
12. }
13. for(i = 0; i < SIZE; i += width)
14. {
15. for(j = i; j < i + width-1; j++)
16. {
17. if(arr[j] == arr[j + 1])
18. {
19. return 0;
20. }
21. }
22. }
23. for(i = 0; i < width; i++)
24. {
25. for(j = i; j < i + width*(width-1); j += width)
26. {
27. if(arr[j] == arr[j + width])
28. {
29. return 0;
30. }
31. }
32. }
33. return 1;
34. }
功能实现
1. 生成新数字
主要思想:在移动或者合并的循环中,根据生成的随机数,对 SIZE 进行取模,达到生成一定概率的数,此程序生成数为 2.
2. 判断游戏是否过关
主要思想:遍历二维数组,找出数组中的最大值,如果最大值等于 2048 ,表示游戏过关。
3. 合并计算得分
主要思想:判断相邻两个数字是否相等,如果相等将当前数字乘以 2,并且消除。
4. 完成向上移动代码函数
5. 完成向下移动代码函数
6. 完成向左移动代码函数
7. 完成向右移动代码函数
编程要求
根据提示,在右侧编辑器 /** Begin **/ 到 /** End **/ 处补充代码。
测试说明
代码测评成功后:
启动平台游戏代码:
进入终端,进入
cd /data/workspace/myshixun/step2/

输入以下命令:将当前地址设为 c++ 寻址动态链接库的地址
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

将 student.cpp 编译成动态链接库。
g++ student.cpp -fPIC -shared -o libstudent.so

将 main.cpp 编译并连接动态链接库。
g++ main.cpp -L. -lstudent -o main

完成后输入:
./main game
后开始游戏;


平台会对你编写的代码进行测试:
预期输出:
1. 按【I】向上移动
2. 按【K】向下移动
3. 按【J】向左移动
4. 按【L】向右移动
5. 按【Ctrl + Z】退出游戏
6. 最大的数是:4
7. 总分是:12
8. 
9. +------------------ 2048 ------------------+
10. +--------------------------------------------+
11. | | | | | |
12. | | 2| | 4| 4|
13. |--------+--------+--------+--------+--------|
14. | | | | | |
15. | | | | | 4|
16. |--------+--------+--------+--------+--------|
17. | | | | | |
18. | | | | | |
19. |--------+--------+--------+--------+--------|
20. | | | | | |
21. | | | 2| | |
22. |--------+--------+--------+--------+--------|
23. | | | | | |
24. | | | | | |
25. +--------------------------------------------+
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <termios.h>
#include <string>
#include "2048.h"
//16
#define SIZE 25
#define width 5
#define height 5
#define UP 0x69
#define UP_B 0x49
#define DOWN 0x6b
#define DOWN_B 0x4b
#define RIGHT 0x6c
#define RIGHT_B 0x4c
#define LEFT 0x6a
#define LEFT_B 0x4a
int arr[SIZE] = {0}; //用来表示2048矩阵的一维数组,元素为0表示该位置为空
int is_move = 0; //移动标志,如果发生了移动,置为1,产生随机数后归0
int is_merge = 0; //合并标志,如果发生了合并,置为1,产生随机数后归0
int max; //数组中当前最大值
int total;//总得分,为所有格子的数字之和
static struct termios oldt;
void my_restore_terminal_settings(void)
{
tcsetattr(0, TCSANOW, &oldt);
}
void disable_terminal_return(void)
{
struct termios newt;
tcgetattr(0, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &newt);
atexit(my_restore_terminal_settings);
}
void my_init(void)
{
int i, random1, random2;
random1 = rand() % SIZE;
for(i = 0; i < 1; i++)
{
random2 = rand() % SIZE;
if(random1 == random2)
{
i--;
}
}
arr[random1] = 2;
arr[random2] = 2;
}
int my_is_dead()
{
int i, j;
for(i = 0; i < SIZE; i++)
{
if(!arr[i])
{
return 0;
}
}
for(i = 0; i < SIZE; i += width)
{
for(j = i; j < i + width-1; j++)
{
if(arr[j] == arr[j + 1])
{
return 0;
}
}
}
for(i = 0; i < width; i++)
{
for(j = i; j < i + width*(width-1); j += width)
{
if(arr[j] == arr[j + width])
{
return 0;
}
}
}
return 1;
}
/**
* my_max_num :找到此时最大的数字
* return :无返回值
*/
int my_max_num(void)
{
int i;
static int count = 0;
for(i = 0; i < SIZE; i++)
{
/*************** Begin ***************/
/*************** End ***************/
}
if(!count && 2048 == max)
{
count++;
printf("恭喜过关,请按任意键继续!");
getchar();
}
return max;
}
void my_print_game(void)
{
system("clear");
int i;
printf("按【I】向上移动\n按【K】向下移动\n按【J】向左移动\n按【L】向右移动\n按【Ctrl + Z】退出游戏\n最大的数是:%d\n总分是:%d\n", my_max_num(), total);
printf("\n");
printf("+------------------ 2048 ------------------+\n");
printf("+--------------------------------------------+\n");
printf("| | | | | |\n");
for(i = 0; i < SIZE; i++)
{
if(0 == i || width == i || 2*width == i || 3*width == i || 4*width ==i)
{
printf("|");
}
printf(0 == arr[i] ? "%9c|" : "%8d|", arr[i]);
if((width-1) == i || (2*width-1) == i || (3*width-1) == i || (4*width-1)==i)
{
printf("\n");
printf("|--------+--------+--------+--------+--------|\n");
printf("| | | | | |\n");
}
}
printf("\n");
printf("+--------------------------------------------+\n");
printf("\n\n\n");
if(my_is_dead())
{
int i;
printf("game over!\n");
printf("请按任意键重新开始!\n");
getchar();
for(i = 0; i < SIZE; i++)
{
arr[i] = 0;
}
my_init();
my_print_game();
}
}
void my_rand_num(void)
{
while(is_move || is_merge) // 判断上否可以移动或者合并;如果可以在剩下的格子中产生随机数字,对应数组下标,将对应下表赋值为2
{
/*************** Begin ***************/
/*************** End ***************/
}
is_move = 0;
is_merge = 0;
}
void my_move_go(int loop_count, int current_i, int direction)
{
int i;
for(i = 0; i < loop_count; i++)
{
if(arr[current_i] && !arr[current_i + direction])
{
arr[current_i + direction] = arr[current_i];
arr[current_i] = 0;
current_i += direction;
is_move = 1;
}
}
}
/**
* my_move_up : 向下移动,不管数字是否相同,全部一个一个的向下移动
* return : 无返回值
*/
void my_move_up(void)
{
/*************** Begin ***************/
/*************** End ***************/
}
/**
* my_move_down : 向下移动,不管数字是否相同,全部一个一个的向下移动
* return : 无返回值
*/
void my_move_down(void)
{
/*************** Begin ***************/
/*************** End ***************/
}
/**
* my_move_right : 向右移动,不管数字是否相同,全部一个一个的向右移动
* return : 无返回值
*/
void my_move_right(void)
{
/*************** Begin ***************/
/*************** End ***************/
}
/*
* my_move_left : 向左移动,不管数字是否相同,全部一个一个的向左移动
* return : 无返回值
*/
void my_move_left(void)
{
/*************** Begin ***************/
/*************** End ***************/
}
/*
* current_i : 合并格子的当前下标
* direction : 上一个格子距离下一个格子的距离,也是游戏棋盘的边长
* merge : 合并函数,只负责一次合并,把接受当前数字下标,把它上或者下或者右的格子合并一个
* return : 无返回值
*/
void merge(int current_i, int direction)
{
if(arr[current_i] && arr[current_i + direction] && arr[current_i] == arr[current_i + direction])
{
/*************** Begin ***************/
/*************** End ***************/
}
}
void my_move_up_pre(void)
{
my_move_up();
int i, j, direction = width;
for(i = 0; i < width; i++)
{
for(j = i; j < i + (width-1)*width; j += width)
{
merge(j, direction);
}
}
my_move_up();
}
void my_move_down_pre(void)
{
my_move_down();
int i, j, direction = -5;
for(i = width - 1; i >= 0; i--)
{
for(j = i + (width-1)*width; j >= width; j -= width)
{
merge(j, direction);
}
}
my_move_down();
}
void my_move_right_pre(void)
{
my_move_right();
int i, j, direction = -1;
for(i = width - 1; i >= 0; i--)
{
for(j = width * i + (width-1); j > width * i; j--)
{
merge(j, direction);
}
}
my_move_right();
}
void my_move_left_pre(void)
{
my_move_left();
int i, j, direction = 1;
for(i = 0; i <= (width-1); i++)
{
for(j = width * i; j < width * i + (width-1); j++)
{
merge(j, direction);
}
}
my_move_left();
}
//游戏主函数,控制游戏流程
void my_run(){
srand(time(NULL));
my_init();
my_print_game();
disable_terminal_return();
int p=0;
while(1)
{
/**
判断输入 结合上面的功能函数,使游戏运行起来
*/
/*************** Begin ***************/
/*************** End ***************/
}
}