小彩球游戏

小彩球游戏1 实验题目 彩球游戏实现过程 1 1 问题描述 游戏规则 1 游戏区域为 77 9 9 具体可由键盘输入确定 共有七种颜色的彩球随机出现 其中状态为 5 个 以后每次出现 3 个 2 用鼠标选中某个彩球

大家好,我是讯享网,很高兴认识大家。

1.实验题目:彩球游戏实现过程

1.1问题描述(游戏规则):

(1)游戏区域为77-99(具体可由键盘输入确定),共有七种颜色的彩球随机出现,其中状态为5个,以后每次出现3个。
(2)用鼠标选中某个彩球,在选择一个空白区域作为目标位置,如果从源到目标位置有通路可走,将彩球移动到目标位置;如果没有通路可走,则不移动并给出提示。
(3)当同色彩球在横向,纵向,斜向达到5个及以上时,可以消除,同时得到相应的分数。
(4)当棋盘中没有空位时,游戏结束。

1.2题目要求:
1.2.1整体要求:

(1)所有小题放在一个程序中,以菜单的形式进行选择
(2)右侧得分,预告彩球以及统计信息。
(3)用伪图形界面进行游戏设计。

1.2.2 显示要求:

(1)被选中的彩球要有不同效果
(2)彩球移动是,要有动画效果沿着通路进行移动
(3)消除时要有相应的动画效果
(4)打印球时以不同的颜色输出
(5)伪图形界面中,鼠标在棋盘上移动实时显示当前所在的行,列位置。

1.2.3游戏规则具体要求:

(1)连续5个及以上则消除,得分规则自定义(具体实现中,我的规则是消除数量为n,则得分为(n-1)*(n-2),其中交叉点要重复计数)。
(2)若本次移动得分,则不产生新球,否则随机产生三个新球。
(3)鼠标左键选择,右键退出。
(4)小彩球只允许在空白位置进行移动,且只可横或竖走,不允许对角线走。

1.2.4 代码要求

(1)尽量使各菜单项中的程序公用函数,用参数解决细微差异。
(2)各函数代码长度尽量不超过50行
(3)不允许使用全局变量,全局指针以及全局数组,允许使用宏定义。
(4)只允许使用目前为止讲过的内容(包括课后补充知识。)

2.整体设计思路

整体流程
讯享网

3.主要功能的实现

3.1寻路
3.1.1 利用递归算法找到通路
  • 自定义函数找到鼠标左键选择的起点和终点后,将起点和终点的坐标(即在二维数组内部存储的i,j值)存入两个大小为2 的数组begin[2]和final[2].
  • 确定好起点和终点后,就可以开始寻路了。将整一个过程拆分成多个小过程,每个过程由两步组成----起点走一步到起点2;起点2走到终点。不需要考虑每一个小过程到底发生了什么。

函数说明:函数返回类型设置为int型,0代表无返回,也就是没找到路;1代表找到路。找到之后原路返回,一路return 同时存储路径上的点 的坐标。算法完成之后,路径上所有的点逆序存放在rout数组之中。

例如下图:

递归流程

具体函数代码如下

int search(int(*p)[10], int(*rout)[2], int x1, int y1, int x2, int y2, int rows, int cols, int *num_pace) { if (x1 >= 0 && x1 < cols&&y1 >= 0 && y1 < rows) { if (x1 == x2&&y1 == y2) { rout[*num_pace][0] = y1; rout[*num_pace][1] = x1; (*num_pace)++; return 1; } else p[y1][x1] = -1; if (p[y1][x1 + 1] == 0) { search(p, rout, x1 + 1, y1, x2, y2, rows, cols, num_pace); if (*num_pace) { rout[*num_pace][0] = y1; rout[*num_pace][1] = x1; (*num_pace)++; return 1; } } if (p[y1 - 1][x1] == 0) { search(p, rout, x1, y1 - 1, x2, y2, rows, cols, num_pace); if (*num_pace) { rout[*num_pace][0] = y1; rout[*num_pace][1] = x1; (*num_pace)++; return 1; } } if (p[y1][x1 - 1] == 0) { search(p, rout, x1 - 1, y1, x2, y2, rows, cols, num_pace); if (*num_pace) { rout[*num_pace][0] = y1; rout[*num_pace][1] = x1; (*num_pace)++; return 1; } } if (p[y1 + 1][x1] == 0) { search(p, rout, x1, y1 + 1, x2, y2, rows, cols, num_pace); if (*num_pace) { rout[*num_pace][0] = y1; rout[*num_pace][1] = x1; (*num_pace)++; return 1; } } return 0; } else return 0; } 

讯享网
3.1.2找通路时内部存储变化

每次查找过程中,首先判断是否为结束条件,如果不是,则将内部数组该位置上的数值设置为-1,避免重复判断查找,保证不走同一个位置。
而在判断能不能走的条件时,首先,要走的点对应的数值需要为0,同时不超出棋盘界限,所以当search完之后,需要将所有值为-1 的恢复成为原先的值,也就是0.除此之外,起点和终点的值要进行互换。
不是所有值为-1的都是路径上的点,还有可能是探了一下但没有成功的点! 真正路径上的点都存储在相应的数组中。通过路径数组中存储的位置值,也就是对应二维数组中的i,j值对输出形式,位置进行选择。

3.1.3伪图形显示移动路径

通过路径数组中存储的位置值,也就是对应二维数组中的i,j值确定路径!由于存储时是先存终点后存起点,所以要逆方向读取。

  • 判断路径上有几个点,用简单的循环和条件就可以判断
  • 从倒数第二个开始,对应伪图形界面中的坐标,打印相应颜色的字符串,同时在倒数第一个位置打印空字符串

以此类推,一直到路径数组中的点全都对应完毕。

3.2判断得分

在新的一颗子落下之前,没有达到可以消除的条件;这颗子落下后,消除条件形成,发生消除动作。所以,每次寻路成功之后,以此次寻路中的终点作为第一颗子进行展开,判断是否满足消除条件。

判断得分

具体代码如下

讯享网void judge(int(*p)[10], char final[2], const int rows, const int cols, int *score, int *eve_score) { int new_chess = p[final[0] - 'A'][final[1] - '1']; int x = final[1] - '1', y = final[0] - 'A'; int i1 = 1, i2 = 1, i3 = 1, i4 = 1, j1 = 1, j2 = 1, j3 = 1, j4 = 1, sum = 0; if (x >= 1 && new_chess == p[y][x - 1] || x<cols - 1 && new_chess == p[y][x + 1]) { while (x - i1 >= 0 && p[y][x - i1] == new_chess) i1++; while (x + j1<cols&&p[y][x + j1] == new_chess) j1++; } if (y >= 1 && p[y - 1][x] == new_chess || y < rows - 1 && p[y + 1][x] == new_chess) { while (p[y - i2][x] == new_chess && y - i2 >= 0) i2++; while (p[y + j2][x] == new_chess && y + j2<rows) j2++; } if (x >= 1 && y >= 1 && p[y - 1][x - 1] == new_chess || x < cols - 1 && y < rows - 1 && new_chess == p[y + 1][x + 1]) { while (p[y + i3][x + i3] == new_chess && y + i3<rows && x + i3<cols) i3++; while (p[y - j3][x - j3] == new_chess &&y - j3 >= 0 && x - j3 >= 0) j3++; } if (x<cols - 1 && y >= 1 && p[y - 1][x + 1] == new_chess || x >= 1 && y < rows - 1 && new_chess == p[y + 1][x - 1]) { while (p[y - i4][x + i4] == new_chess && y - i4 >= 0 && x + i4<cols) i4++; while (p[y + j4][x - j4] == new_chess && x - j4 >= 0 && y + j4<rows) j4++; } if (i1 + j1 >= 6) { sum += (i1 + j1 - 1); for (int i = x + 1 - i1; i < x + j1; i++) p[y][i] = 0; } if (i2 + j2 >= 6) { sum += (i2 + j2 - 1); for (int i = y - i2 + 1; i < y + j2; i++) p[i][x] = 0; } if (i3 + j3 >= 6) { sum += (i3 + j3 - 1); for (int i = 1 - j3; i < i3; i++) p[y + i][x + i] = 0; } if (i4 + j4 >= 6) { sum += (i4 + j4 - 1); for (int i = 1 - i4; i<j4; i++) p[y + i][x - i] = 0; } if (sum) { *eve_score = (sum - 1)*(sum - 2); *score += (sum - 1)*(sum - 2); } else *eve_score = 0; } 

(如图只是为解释,该情况在实际中是不可能出现的)
判断时,从黑色小球出发,以上下为例,分两个方向进行搜索,分别定义i=1,j=1,循环判断p[y-i][x]?=p[y][x],不等于循环结束,记录i值;等于则i++,继续搜索。。。j同理,向黑色小球的下方进行搜索,最终纵向的小球个数为i+j-1;其他方向都是同理。
由于交叉点需要重复计数,所以选择先判断完所有方向,记录所有可以消除的球(包括交叉点的多次计数)后再对内部数组进行改变,防止交叉小球满足一个条件后就被消除,对潜在的其他方向的消除条件判断造成影响。
记录完之后计算此次得分,以此次得分是否为零,用以后续判断是否进行了消除。

void seven(int(*p)[10]) { HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); const HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); int rows, cols, X, Y;//X,Y用于存放打印完棋盘后的光标坐标,方便打印结束语 char begin[2], final[2];//存放鼠标输入的起点坐标和终点坐标 int next[3], rout[81][2];//next用于存放下一轮将会出现的球的信息;rout用于存放寻到的路上的点坐标 init(&rows, &cols, p, 5);//初始化内部数组+随机产生5个球 const int *row_ptr = &rows;//防止不小心对cols rows篡改 const int *col_ptr = &cols; int score = 0, eve_score = 0;//总得分,每次得分 int leap = 0; print_console2(rows, cols, p);//打印棋盘 getxy(hout, X, Y); print_console3(rows, cols, next, 0);//打印得分,预示等 for (int i = 0; i < 3; i++) next[i] = rand() % 7; print_console3(rows, cols, next, 4); while (1) { int num_pace = 0; bgn_fnl_mouse(begin, final, rows, cols, Y, p);//输入起点和终点的坐标 int begin_value = p[begin[0] - 'A'][begin[1] - '1'];//将起点值先存起来,寻完路后再赋给终点,防止寻路过程中值被“破坏 if (search(p, rout, begin[1] - '1', begin[0] - 'A', final[1] - '1', final[0] - 'A', *row_ptr, *col_ptr, &num_pace)) {//search返回1代表寻到路,否则没寻到路!但不论是否寻到路,这个函数中的操作已经执行,也就是路径上的点的值已被改变 reset_array(p, col_ptr, row_ptr);//search是吧探索过的店全都变成了-1要变回来,包括起始点 p[final[0] - 'A'][final[1] - '1'] = begin_value; show_rout(rout, begin_value);//把存在rout里的路径上的点坐标按顺序(加延时)显示,即移动路径 for (int i = 0; i < 81; i++) for (int j = 0; j < 2; j++) rout[i][j] = -1;//清空存储的路径记录 judge(p, final, *row_ptr, *col_ptr, &score, &eve_score);//判断能否得分,若得分,设置为0,更新内部数组 if (eve_score == 0) { update_array(p, next, col_ptr, row_ptr, 1);//将next中存的值随机赋给"棋盘"中空白的位置,也就是给内部数组p for (int i = 0; i < 3; i++) next[i] = rand() % 7+1; print_console3(rows, cols, next, 4);//4用于控制打印位置 } else {/*遍历棋盘,把刚消去球的位置打印空格*/ for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) if (p[i][j] == 0) showstr(hout, 2 + j * 4, (i + 1) * 2, " ", COLOR_HWHITE, COLOR_HWHITE); setcolor(hout, COLOR_HWHITE, COLOR_BLACK); gotoxy(hout, 4 * cols + 12, 2); cout << score; } } else//如果没有找到路 { p[begin[0] - 'A'][begin[1] - '1']=begin_value; showstr(hout, 2 +(begin[1] - '1') * 4, (begin[0] - 'A' + 1) * 2, "○", begin_value + 1, COLOR_HWHITE); reset_array(p, col_ptr, row_ptr); continue; } if (game_over(p, row_ptr, col_ptr,Y-1)) break; } end(); } 
小讯
上一篇 2025-02-19 21:08
下一篇 2025-02-23 20:33

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/26244.html