前两天只是简单复习了下C语言的基础知识,到第三天就采用项目驱动的方式,带着我们一个班的学生做项目----Popstar游戏
其实还是很倾向于项目驱动的方式来学习的,老师在上边一边讲一边敲代码,我们就只要听,和抄下投影仪上的代码。带着我们走过一遍流程以后,再让我们自己写一个小游戏,老师只提供技术难点帮助。
话不多说,给各位君看看记录的东西。
首先做了一个控制台下的Popstar,用于测试算法的正确性,由于Popstar涉及到选择附近四个方向的同颜色的星星,因此要用到扩展查找算法。因为是学习,老师展示了递归、非递归方式来实现查找的过程。
开始定义了一系列的数据对象
就是想一下需要用到哪些数据对象,头文件要用头文件卫士#ifndef……这是编程规范
data.h
1 #ifndef _DATA_H_//以文件名命名 2 #define _DATA_H_ 3 4 //pragma once 5 6 #include <windows.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <stdlib.h> 10 11 #define ROW 10 12 #define COLUMN 10 13 14 typedef struct pos 15 { 16 int _x; 17 int _y; 18 }POS; 19 20 typedef enum color 21 { 22 RED = 0, 23 BLUE = 1, 24 GREEN = 2, 25 YELLOW = 3, 26 PURPLE = 4 27 }eCOLOR; 28 29 typedef struct star 30 { 31 eCOLOR _color;//颜色 32 POS _pos; //位置 33 BOOL _isSelect; 34 }sSTAR; 35 36 typedef enum directory 37 { 38 UP, 39 DOWN, 40 LEFT, 41 RIGHT 42 }eDIRECT; 43 44 #endif;
接着写了fun.cpp
定义了一个sSTAR类型的数据对象 g_arrStars[row][column]
并且对数据对象进行了初始化:
void InitDataObj(void) { int row = 0; int column = 0; srand((unsigned)time(0)); for(row = 0; row < ROW; row++) { for(column = 0; column < COLUMN; column++) { g_arrStars[row][column]._color = (eCOLOR)(rand()%5); g_arrStars[row][column]._isSelect = FALSE; g_arrStars[row][column]._pos._x = row; g_arrStars[row][column]._pos._y = column; } } }
判断是否越界:
1 BOOL IsOutOfBorder(eDIRECT direct,int x,int y) 2 { 3 switch(direct) 4 { 5 case UP: 6 case DOWN: 7 { 8 if(x<0 || x>ROW-1) 9 { 10 return TRUE; 11 } 12 else return FALSE; 13 break; 14 } 15 16 case LEFT: 17 case RIGHT: 18 { 19 if(y<0 || y>COLUMN-1) 20 { 21 return TRUE; 22 } 23 else 24 { 25 return FALSE; 26 } 27 break; 28 } 29 default: 30 { 31 return FALSE; 32 break; 33 } 34 } 35 }
接着用了递归方式实现了选择星星的过程
1 void SelectStar(const int x,const int y,int* pCount) 2 { 3 g_arrStars[x][y]._isSelect = TRUE; 4 (*pCount)++; 5 6 //如果 没越界 四个方向某个颜色相等 并且没有被选择 7 //每次递归调用自己 上下左右依次判断 8 if(!IsOutOfBorder(UP,x-1,y) && 9 g_arrStars[x-1][y]._color == g_arrStars[x][y]._color && 10 g_arrStars[x-1][y]._isSelect == FALSE 11 ) 12 { 13 SelectStar(x-1,y,pCount); 14 } 15 16 if(!IsOutOfBorder(DOWN,x+1,y) && 17 g_arrStars[x+1][y]._color == g_arrStars[x][y]._color && 18 g_arrStars[x+1][y]._isSelect == FALSE 19 ) 20 { 21 SelectStar(x+1,y,pCount); 22 } 23 24 if(!IsOutOfBorder(LEFT,x,y-1) && 25 g_arrStars[x][y-1]._color == g_arrStars[x][y]._color && 26 g_arrStars[x][y-1]._isSelect == FALSE 27 ) 28 { 29 SelectStar(x,y-1,pCount); 30 } 31 32 if(!IsOutOfBorder(RIGHT,x,y+1) && 33 g_arrStars[x][y+1]._color == g_arrStars[x][y]._color && 34 g_arrStars[x][y+1]._isSelect == FALSE 35 ) 36 { 37 SelectStar(x,y+1,pCount); 38 } 39 }
这样在main函数中写上这样一段:
1 int x = 0, y =0, count = 0; 2 ////初始化数据对象 3 InitDataObject(); 4 ////显示星星 5 Display(); 6 ////选取星星 7 printf("Please Input x And y :"); 8 scanf_s("%d%d", &x, &y); 9 //SelectStart(x, y, &count); 10 11 SelectStarMethod1(x,y,&count); 12 printf("%d ", count); 13 Display();
就可以进行星星的选择了。。。。。。。
再接着就忙着用非递归的方式实现扩展查找
非递归方式需要用到栈与队列,因此写了两个版本的栈与队列,一个是C语言版,一个是C++版的模版
这里我就忽略实现过程,直接上查找过程的函数了。
1 int SelectStarMethod2(int x,int y) 2 { 3 SEQUEN_QUEUE queue; 4 SEQUEN_STACK stack; 5 InitSequenStack(&stack); 6 InitSequenQueue(&queue); 7 sSTAR *p = NULL; 8 9 EnQueue(&queue,&g_arr[x][y]); 10 int currx = 0,curry = 0; 11 while(!IsEmptyQueue(&queue)) 12 { 13 DelQueue(&queue,&p); 14 Push(&stack,p); 15 p->_isSelect = true; 16 17 currx = p->_pos._x; 18 curry = p->_pos._y; 19 if(!IsOutOfBorder(UP,currx-1,curry) && 20 g_arr[currx-1][curry]._color == g_arr[currx][curry]._color && 21 g_arr[currx-1][curry]._isSelect == false) 22 { 23 EnQueue(&queue,&g_arr[currx-1][curry]); 24 } 25 26 if(!IsOutOfBorder(DOWN,currx+1,curry) && 27 g_arr[currx+1][curry]._color == g_arr[currx][curry]._color && 28 g_arr[currx+1][curry]._isSelect == false) 29 { 30 EnQueue(&queue,&g_arr[currx+1][curry]); 31 } 32 33 if(!IsOutOfBorder(LEFT,currx,curry-1) && 34 g_arr[currx][curry-1]._color == g_arr[currx][curry]._color && 35 g_arr[currx][curry-1]._isSelect == false) 36 { 37 EnQueue(&queue,&g_arr[currx][curry-1]); 38 } 39 40 if(!IsOutOfBorder(UP,currx,curry + 1) && 41 g_arr[currx][curry + 1]._color == g_arr[currx][curry]._color && 42 g_arr[currx][curry + 1]._isSelect == false) 43 { 44 EnQueue(&queue,&g_arr[currx][curry + 1]); 45 } 46 } 47 return GetSequenLength(&stack); 48 }
非递归方式实现扩展查找,其实这里是有一点小问题的,就是当我星星同色的形成一个正方形的时候,选择就会出错。会多几个数字。解决办法就是在 if 判断之后加上
g_arr[currx-1][curry]._isSelect == true
这个扩展查找的非递归方式还是由你们自己去理解吧,在纸上模拟一下进队出队的过程你就明白了
还有就是用C++模版写的版本
1 int SelectStarMethod3(int x,int y) 2 { 3 CSequenStack<sSTAR,MAX_SIZE> stack; 4 SequenQueue<sSTAR,MAX_SIZE> queue; 5 sSTAR obj; 6 int currx = 0,curry = 0; 7 queue.EnQueue(g_arr[x][y]); 8 9 while(!queue.IsEmpty()) 10 { 11 queue.DelQueue(obj); 12 currx = obj._pos._x; 13 curry = obj._pos._y; 14 stack.Push(g_arr[currx][curry]);// 15 g_arr[currx][curry]._isSelect = true;//次两处不可以用obj,因为其为值,不为地址引用 16 17 if(!IsOutOfBorder(UP,currx-1,curry) && 18 g_arr[currx-1][curry]._color == g_arr[currx][curry]._color && 19 g_arr[currx-1][curry]._isSelect == false) 20 { 21 queue.EnQueue(g_arr[currx-1][curry]); 22 } 23 24 if(!IsOutOfBorder(DOWN,currx+1,curry) && 25 g_arr[currx+1][curry]._color == g_arr[currx][curry]._color && 26 g_arr[currx+1][curry]._isSelect == false) 27 { 28 queue.EnQueue(g_arr[currx+1][curry]); 29 } 30 31 if(!IsOutOfBorder(LEFT,currx,curry-1) && 32 g_arr[currx][curry-1]._color == g_arr[currx][curry]._color && 33 g_arr[currx][curry-1]._isSelect == false) 34 { 35 queue.EnQueue(g_arr[currx][curry-1]); 36 } 37 38 if(!IsOutOfBorder(RIGHT,currx,curry + 1) && 39 g_arr[currx][curry + 1]._color == g_arr[currx][curry]._color && 40 g_arr[currx][curry + 1]._isSelect == false) 41 { 42 queue.EnQueue(g_arr[currx][curry+1]); 43 } 44 } 45 return stack.GetLength(); 46 }
最后:
我个人觉得编写软件就像盖一座房子,我们看别人写好的代码,为什么这么难?这时因为别人的代码已经是完成了的一个项目,经过不断重构之后,就像建好的一座
房子,我们外来的人在房子里边跑啊跑啊,想知道这房子到底是怎么盖的啊,从楼上跑到楼下一无所获。看不懂就是这样的一个过程。所以,如果没有人带着你写东西,那么你需要花费更多的精力来将整个房子一点点拆开,理解为什么这样做,这样的一个过程是一个很长的过程。因此看别人构建好的代码不能着急,原著都写了三五天,你想一天就看懂,那怎么能符合逻辑呢?
对一些新的冷的知识更是如此,如果你一点都看不懂学不会,那么不如去找一下视频,跟着别人学一遍,走一边构建整个房子的流程,那么再写东西,看代码就如鱼得水了。
代码下载:点击