Check
考核题
1. 五子棋
游戏流程
进入游戏:输入1
游戏界面:打印回合数、棋盘、提示输入落子坐标
第 7 回合的棋盘
棋盘中 空白处为 空地,X 表示 黑子,O 表示 白子

胜利界面:打印回合数,棋盘,以及获胜方。
提示按任意键继续。
按下任意键可以回到主菜单选择继续游戏 或 退出游戏
头文件
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
using namespace std;
数据设计
// C/C++:
// -------------------- 数据设计 --------------------
/*
棋盘:
map[i][j]表示坐标(i,j)的值
0表示空地
1表示黑子
2表示白子
如: map[3][6] = 1 表示(3,6)的位置是黑子
*/
int map[19][19];
// map的行数和列数
const int map_row = sizeof(map) / sizeof(map[0]);
const int map_col = sizeof(map[0]) / sizeof(map[0][0]);
// 表示当前回合数 偶数表示黑棋落子 奇数表示白棋落子
// 如: flag = 20 表示当前是第[20]次落子 由黑方落子
int flag;
// -------------------- 数据设计 --------------------
Service
// -------------------- service --------------------
/*
负责人: Rain
功能: init: 初始化游戏数据
将棋盘的值初始化为0
当前回合设为黑棋(flag设为0)
参数: void
返回值: void
*/
void init();
/*
*难点1
负责人: Rain
功能: isWin: 根据传入的坐标(map对应位置)和flag值 判断落点后是否获胜
参数:
x: 当前回合落子的x坐标
y: 当前回合落子的y坐标
返回值:
0表示没有获胜
1表示黑子胜利
2表示白子胜利
*/
int isWin(int x, int y);
/*
负责人: Rain
功能: dfs: 根据输入的map和起始坐标进行深度优先搜索 以及 连子计数
参数:
map: 棋盘
cur_row: 当前位置x坐标
cur_col: 当前位置y坐标
visit: 访问数组
prevNode: 当前棋子颜色
win_cnt: 连子计数
direction: 方向
返回值:
void
*/
void dfs(int (&map)[map_row][map_col], int cur_row, int cur_col, vector<vector<bool>> &visit, int prevNode, int &win_cnt, int direction);
/*
负责人: Rain
功能: playerMove: 在指定位置落子
如果map[x][y]是空地 则修改map[x][y]的值:改为相应颜色(flag对应颜色) 否则不操作
参数:
x: 当前回合落子的x坐标
y: 当前回合落子的y坐标
返回值:
0表示落子失败 (棋盘已经有子)
1表示落子成功
*/
int playerMove(int x, int y);
// -------------------- service --------------------
View
// -------------------- view --------------------
/*
负责人: Rain
功能: menuView: 展示选项, 玩家可以在这里选择进入游戏, 进入设置或退出游戏
进入游戏: 调用游戏界面函数gameView();
进入设置: 敬请期待...
退出游戏: 调用exit(0);
参数: void
返回值: void
*/
void menuView();
/*
负责人: Rain
功能: gameView_ShowMap: 根据map数组 打印游戏棋盘
参数: void
返回值: void
*/
void gameView_ShowMap();
/*
负责人: Rain
功能: winView: 根据flag的值 打印游戏胜利界面 用户可以按任意键回到主菜单
参数: void
返回值: void
*/
void winView();
/*
*难点2
负责人: Rain
功能: gameView: 游戏界面整合
初始化游戏数据(调用函数init())
while(1){
打印游戏界面(调用函数gameView_ShowMap())
接收玩家坐标输入
落子(调用落子函数playerMove())
(如果落子失败 重新开始循环)
判断游戏是否胜利(调用胜利判断函数isWin())
(如果游戏胜利 调用胜利界面函数 然后结束当前界面)
切换玩家(修改flag值)
}
参数: void
返回值: void
*/
void gameView();
// -------------------- view --------------------
主函数
int main()
{
menuView(); // 调用菜单界面函数
return 0;
}
函数定义
// 初始化游戏数据
void init()
{
// init map
for (auto &row : map) // 遍历棋盘的每一行
{
for (auto &element : row) // 遍历当前行的每一个元素
{
element = 0; // 将元素初始化为0,表示空地
}
}
// init flag
flag = 0; // 初始化回合数为0,表示黑棋先落子
return;
}
/*
思路:使用DFS算法 从落子点开始 向8个方向搜索 统计连子数量
*/
// 判断当前落子是否获胜
int isWin(int x, int y)
{
// 返回值,默认棋子落子失败
int r_val = 0;
// 从落子点开始进行深度优先搜索
for(int dir = 1; dir <= 4; dir++)
{
// 访问标记
vector<vector<bool>> visit(map_row, vector<bool>(map_col, false));
// 连子计数
int win_cnt = 0;
dfs(map, x, y, visit, map[x][y], win_cnt, dir);
// 如果连子数量达到5,表示获胜
if(win_cnt >= 5)
{
r_val = map[x][y]; // 返回获胜方的棋子颜色
break;
}
}
return r_val;
}
// 深度优先搜索函数
void dfs(int (&map)[map_row][map_col], int cur_row, int cur_col, vector<vector<bool>> &visit, int prevNode, int &win_cnt, int direction)
{
// 越界、当前位置不是同色棋子、已经访问过、是空地或者连子数量达到5,返回
if (cur_row < 0 || cur_col < 0 || cur_row == map_row || cur_col == map_col || map[cur_row][cur_col] != prevNode || visit[cur_row][cur_col] || prevNode == 0 || win_cnt == 5)
{
return ;
}
win_cnt++; // 连子数量加1
visit[cur_row][cur_col] = true; // 标记当前位置已访问
// 向8个方向进行深度优先搜索
if(direction == 1) // 上下搜索
{
dfs(map, cur_row + 1, cur_col, visit, map[cur_row][cur_col], win_cnt, direction); // 向下
dfs(map, cur_row - 1, cur_col, visit, map[cur_row][cur_col], win_cnt, direction); // 向上
}
else if(direction == 2) // 左右搜索
{
dfs(map, cur_row, cur_col + 1, visit, map[cur_row][cur_col], win_cnt, direction); // 向右
dfs(map, cur_row, cur_col - 1, visit, map[cur_row][cur_col], win_cnt, direction); // 向左
}
else if(direction == 3) // 左上右下搜索
{
dfs(map, cur_row - 1, cur_col - 1, visit, map[cur_row][cur_col], win_cnt, direction); // 左上
dfs(map, cur_row + 1, cur_col + 1, visit, map[cur_row][cur_col], win_cnt, direction); // 右下
}
else if(direction == 4) // 左下右上搜索
{
dfs(map, cur_row - 1, cur_col + 1, visit, map[cur_row][cur_col], win_cnt, direction); // 右上
dfs(map, cur_row + 1, cur_col - 1, visit, map[cur_row][cur_col], win_cnt, direction); // 左下
}
return ;
}
// 玩家落子函数
int playerMove(int x, int y)
{
// 落子结果,默认落子失败
int r_val = 0;
// 如果当前位置是空地
if (map[x][y] == 0)
{
// 根据flag的值确定落子颜色
map[x][y] = flag % 2 + 1;
r_val = 1; // 落子成功
}
// 棋盘上已有棋子,落子失败
else
{
r_val = 0;
}
return r_val;
}
// 菜单界面函数
void menuView()
{
// 循环显示菜单
while (true)
{
cout << "--------- 游戏主菜单 请选择 -------" << endl;
cout << "--------- 1. 进入游戏 -------" << endl;
cout << "--------- 2. 进入设置 -------" << endl;
cout << "--------- 3. 退出游戏 -------" << endl;
cout << " 请输入你的选择: ";
// 接收用户输入
int select;
cin >> select;
switch (select)
{
// 进入游戏
case 1:
gameView();
break;
// 进入设置
case 2:
cout << "敬请期待" << endl;
break;
// 退出游戏
case 3:
exit(0);
break;
// 输入无效
default:
cout << "输入无效" << endl;
break;
}
}
return ;
}
// 显示游戏棋盘
void gameView_ShowMap()
{
// 显示当前回合数
cout << "当前回合数: " << flag << endl;
// 打印棋盘边界
cout << "-----------------------------棋盘--------------------------" << endl;
cout << " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18" << endl;
int i = 0;
for (auto &row : map) // 遍历棋盘的每一行
{
cout << setiosflags(ios::left) << setw(2) << i << "| "; // 打印行号
for (auto element : row) // 遍历当前行的每一个元素
{
cout << element << setiosflags(ios::left) << setw(2) << "|"; // 打印元素
}
cout << endl;
i++;
}
return ;
}
// 显示胜利界面
void winView()
{
// 根据flag的值判断获胜方
if ((flag) % 2 == 0)
{
gameView_ShowMap();
cout << "黑棋玩家获胜!" << endl;
}
else if ((flag) % 2 == 1)
{
gameView_ShowMap();
cout << "白棋玩家获胜!" << endl;
}
return ;
}
// 游戏界面整合函数
void gameView()
{
// 初始化游戏数据
init();
// 游戏循环
while(true)
{
int x, y;
gameView_ShowMap(); // 显示游戏棋盘
// 提示用户输入落子坐标
cout << "请输入落子坐标(格式: x y, 按回车确认): " << endl;
cin >> x >> y;
// 检查坐标合法性
if (x < 0 || x >= map_row || y < 0 || y >= map_col)
{
cout << "输入的坐标不合法,请重新输入" << endl;
continue;
}
// 落子
if(playerMove(x, y) == 0)
{
cout << "落子失败,请重新落子" << endl;
// 落子失败,重新开始循环
continue;
}
// 落子成功
cout << "落子成功" << endl;
// 判断游戏是否胜利
if(isWin(x, y) == 1) // 黑子胜利
{
winView(); // 显示胜利界面
break;
}
else if(isWin(x, y) == 2) // 白子胜利
{
winView(); // 显示胜利界面
break;
}
// 游戏未结束,继续循环
flag++; // 回合数加1
}
return ;
}
2. 问答题
以下内容的代码实现, 由view还是service负责? (填写view或service)
游戏逻辑判断: Service
用户输入: View
用户输入数据合法判断/类型判断(比如区分输入是[方向]还是[空格]): View
界面展示: View
游戏数据修改: Service
以下说法是否正确? (填写true或false)
view有时需要调用service的功能 以实现逻辑判断和数据修改: True
service有时需要调用view的功能 以实现界面展示: False
service中可以写scanf和printf 用于接收用户输入和展示界面: False
涉及游戏数据判断和修改的, 大多在service实现: True
数据的设计不需要描述很清晰, 自己能看懂即可: False
3. 推箱子游戏
开始界面: 可以选择: [选关界面]/[设置界面]/[排行榜界面]/退出游戏
选关界面: 可以选择关卡进入[游戏界面], 或者回到[开始界面]
游戏界面: 可以移动人物, 回退到[选关界面], 或者游戏胜利后展示[胜利界面]
胜利界面: 提示游戏胜利, 并回到[选关界面]
设置界面: 展示[未完待续...]
排行榜界面: 展示[未完待续...]
数据设计层
// C/C++:
// -------------------- 数据设计 --------------------
/*
地图:
map[i][j][k]表示地图i中坐标(j,k)的值
0表示空地 格子
1表示遮挡物 格子
2表示玩家 格子
3表示目标 格子
如: map[4][3][6] = 1 表示地图4中(3,6)的位置是 遮挡物
*/
int map[10][19][19];
/*
当前地图目标点:
(target[0], target[1], target[2]), 表示地图中的目标坐标
*/
int target[3];
// -------------------- 数据设计 --------------------
服务 service 层
// -------------------- service --------------------
/*
负责人: 张三
功能: init: 初始化游戏数据
将地图的值初始化为 Level 关卡地图
玩家位置设置为地图上某点
参数: int Level: 关卡数
返回值: void
*/
void init(int Level);
/*
*难点1
负责人: 张三
功能: isWin: 根据传入的玩家当前坐标(map对应位置) 判断是否达到目标
参数:
x: 当前玩家的x坐标
y: 当前玩家的y坐标
返回值:
0表示没有获胜
1表示玩家胜利
*/
int isWin(int x, int y);
/*
负责人: 张三
功能: playerMove: 玩家向指定方向移动一个格子
如果map[l][x][y]是空地 / 目标值 则修改map[l][x][y]的值为玩家对应值
并 修改玩家上一个位置为空地
否则 不操作
参数:
l: 当前地图编号
x: 当前回合玩家移动的x坐标
y: 当前回合玩家移动的y坐标
返回值:
0表示移动失败(有遮挡物)
1表示移动成功
*/
int playerMove(int l, int x, int y);
// -------------------- service --------------------
展示界面 view 层
// -------------------- view --------------------
/*
负责人: 张三
功能: menuView: 展示选项, 玩家可以在这里选择
[选关界面] / [设置界面] / [排行榜界面] / 退出游戏
选关界面: 调用选关界面函数levelView();
设置界面: 敬请期待...
排行榜界面: 敬请期待...
退出游戏: 调用exit(0);
参数: void
返回值: void
*/
void menuView();
/*
负责人: 张三
功能: levelView: 展示选项, 玩家可以在这里选择
[游戏界面], 或者回到[开始界面]
游戏界面: 调用游戏界面函数mapView();
开始界面: 调用开始界面函数menuView();
参数: void
返回值: void
*/
void levelView();
/*
负责人: 张三
功能: gameView_ShowMap: 根据map数组 打印地图
参数: void
返回值: void
*/
void gameView_ShowMap();
/*
负责人: 张三
功能: winView: 将goal坐标和用户当前坐标进行匹配 打印游戏胜利界面
用户可以按任意键回到选关界面
参数: void
返回值: void
*/
void winView();
/*
*难点2
负责人: 张三
功能: gameView: 游戏界面整合
初始化游戏数据(调用函数init())
while(1){
打印游戏界面(调用函数gameView_ShowMap())
接收玩家方向输入: 'w' 'a' 's' 'd'
移动(调用移动函数playerMove())
(如果移动失败 重新开始循环)
判断游戏是否胜利(调用胜利判断函数isWin())
(如果游戏胜利 调用胜利界面函数 然后结束当前界面)
}
参数: void
返回值: void
*/
void gameView();
// -------------------- view --------------------
Last updated