当前位置:   article > 正文

贪吃蛇项目总结

贪吃蛇项目总结

贪吃蛇的实现,实现了几遍。从开始的举步维艰到最终的思路清晰,都是不容易的。这里不想针对整个工程大谈。只针对里面的三点进行叙述,便是产生食物时,用到一个算法,也叫洗牌算法,以及整体上的一维数组的使用。而其中的一维数组的使用,而不是二维数组。这里也是为了方便编程,以及提高数据的处理速度。其实在我看来,数组的灵活使用,其实就是下标的灵活使用。也就是说,玩数组就是玩下标。再有一点便是程序的整体上,很多人有一个误区,具体就是处理图形的方式上有所错误理解。接下来一一叙述。

1.洗牌算法

注:这里为了画图以及讲述方便,假设只有10张牌,分别为0-9.

 方式一:在10以内产生一个随机数,然后放到第一张牌,即下标为0处;

               在10以内再产生一个随机数,然后放到第二张牌上,即下标为1处;

              ......

上面这种方式,无非是最简单的方式,但却有一个致命的缺点。即从第二次开始便要查重,而且随着循环的继续,重复的可能性就会越来越高,显然是不合理的。这里在第一种方式的基础上改进,将产生的牌作为最后一张牌,然后每次的基础上产生随机出的范围减一,这样便轻松产生一副随机的牌,而且不需要查重的。对于这个思想,发现这种不叫“洗牌”,因为没有洗。下面给出的方式二,是在这种思路的基础上的,才是真正的洗牌,而这种办法才是具有通用性的。

方式二:首先需要先准备一个一维数组,按照这里的10张牌,即长度为10,依次赋值为下标的值(如图所示),这里赋值为下标的的值,说明之前为一副新牌,而在实际应用中,这里便是用来记录原数据的。

              在10以内随机产生一个数,以这个数为下标,将下标所对应的这个值与最后一个值交换;

             在9以内随机产生一个值,以这个数为下标,将下标所对应的这个值与倒数第二个值交换;

             ......

 

 

这种方式既可以避免查重,而且可以对原数据进行真正意义上的洗牌,时间复杂度为O(n)。代码如下:

  1. int i;
  2. int temp;
  3. int randNum;
  4. int arr[10];
  5. int count = 10;
  6. for(i = 0; i < 10; i++) {
  7. arr[i] = i;
  8. }
  9. srand(time(NULL));
  10. for(i = 0; i < 10; i++) {
  11. randNum = rand() % count;
  12. temp = arr[randNum];
  13. arr[randNum] = arr[count - 1];
  14. arr[count - 1] = temp;
  15. count--;
  16. }
  17. for(i = 0; i < 10; i++) {
  18. printf("%d ", arr[i]);
  19. }

由于洗牌算法在贪吃蛇中的使用牵扯众多,因此在最后详谈。

2.一维数组的使用

一维数组的使用也是源于之前的经验。首先说明,这里的一维数组只是为了方便运算,实际是用一维数组表示二维数组,只不过在转换为坐标时,进行一步运算即可。在贪吃蛇游戏设计过程中,前几次编程时,对于其中的食物的产生以及蛇咬到自己的身体或者对手的身体,这个处理,总是很复杂。因为每一次移动或者产生食物时,需要对身体进行遍历,以及食物的坐标也是需要遍历的。这就会产生很大的时间复杂度。对于这个问题,最终想到一个办法,那就是给一个全局的数组,用来记录屏幕上点的当前状态,至于好几种状态(食物,自己蛇身或蛇头,对手蛇身或蛇头,空地,障碍物墙壁),可以给好几个宏,以记录。这样的话,每次移动或者产生食物时,只需改变相应的几个点的坐标,而在处理之前的几个问题时,就可以直接用下标判断,一句搞定。没有代码很难讲清楚,后面我会用代码详谈。

3.覆盖法

覆盖法只是这么一个叫法。实际想说的是在每次移动蛇或产生食物时,可以用覆盖法代替刷新屏幕的方法。网上很多人的贪吃蛇每次刷新整个屏幕,实际上复杂了问题,因为每次只有几个点在变化。我们可以直接通过覆盖来达到我们的目的。至于具体的就不详说了,可以在最后看看代码。

洗牌算法二叙:

贪吃蛇项目在屏幕信息数组上实际上有两个,一个便是上面的全局的一维数组,因为屏幕上共2000个点,因此便是申请了一个长度为2000的全局一维数组以记录信息,而在产生食物时,还需要有一个局部的长度为两千的一维数组,这个数组就是之前洗牌算法中的需要的数组。这个数组只是为了产生随机的并且不重复的食物点阵信息而存在。先给出这块的代码,再拿代码讲述吧。

  1. //产生食物的坐标
  2. void getFoodXy(int *point) {
  3. int randNum;
  4. int i;
  5. int count = 0;
  6. int array[2000] = {0};
  7. int j = 1999;
  8. for(i = 0; i < 2000; i++) {
  9. if(point[i] == 0) {
  10. array[count] = i;
  11. count++;
  12. }
  13. }
  14. for(i = 0; i < FOODNUM; i++) {
  15. srand(time(0) + i);
  16. randNum = rand() % count;
  17. point[array[randNum]] = FOOD;
  18. array[randNum] = array[j--];
  19. count--;
  20. }
  21. }

这里可以看到得到随机食物的函数相当简单。这便是得益于一维数组和发牌算法的支持。如果按照一般的实现方案,你需要剔除掉蛇身,蛇头,边框,还有剩余的食物,然后再在里面产生食物。我开始也是按照这种方法实现的,这里的代码相当复杂,繁琐,令我恶心之至。不过加上犀利的操作后,一切变得简单方便。可见这几部操作的重要性。

 

 

完整代码已发至Github上

https://github.com/kennDJ/snake

有不同意见,欢迎交流!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/802944
推荐阅读
相关标签
  

闽ICP备14008679号