跳格子小游戏,winform gdi+ 小游戏算法讲解—— 接上篇格子类小游戏

小游戏的算法就是就是对游戏规则的抽象。一切事物皆可以成抽象成数学语言 ,程序语言。对游戏而言首先 要明确定义游戏规则,一般我们在向他人讲述一个游戏 规则时都很随意。 比如五子棋 我们就会说一句 “连成五个子 就行了”。其他的就靠人们通常的理解,和我们之间基本的默契了,但是当我写游戏就要把游戏规则 高度精确的定义出来。
首先要能够用比较严谨的语言将规则表述清楚这个很重要。
下面我就有相对精确的语言把五子棋的规则给定义出,来并且说出每句的必要性;
1.棋盘:五子棋的 棋盘是15*15的方格组成。棋子必须落在格点上
注释:15*15这个的必要性就是 让五子棋有个适当的终结以免五子棋无穷的下下去,他对我们的影响就是:
即使你有4个子了但 是到达了边界 你还是没赢; 由于这个规则就影响了你的落子,和你的策略;
对于程序: 来说就是 如果 你鼠标点击 了棋盘之外的点视为无效操作可以继续走。
如你点击的不是刚好在格点上就视为 你点了离你鼠标位置最近的格点
2.棋子:就是黑子和白子棋子到时要求不大如果 非要说一个的话 就是棋子的 直径要<=格子的边长
在程序中的体现就是注意下素材 和算法关系不大
3.落子:一局棋中一个玩家只能使用一种颜色的棋子,双方交替落子 一次只能落一子,两个棋子不能落在同一位置
对于程序:点击棋盘,如果你点击的那个部位超出界限 ,或对应的格点上已有 棋子,或者对方尚未落子,则视为无效点击,可继续落子
3.赢:就是如果 有经过 玩家最后一次落子位置 水平,竖直,与水平线成45度角,与水平线成135度角,这四条直线上又连续5个同色的棋子 连续就是之中间没有中间没有空格点也没有异色的子
如果你能对一个游戏描述的像上面的那样 那你基本上就可以根据游戏规则 自己设计算法了 而不是贴别人现成的
首先我解释下下面这个方法的参数:
int[,] winarr : 就是记录棋盘上所有 格点上落子情况的数组 无子为0,黑子为1,白子为2
Point luozi : 这个只得是棋盘上 最后落下的那个子的坐标 。 int x : 代表的是棋盘上最后落地是黑子1,还是白子2
对于人人对战的 来说 核心的算法 就是
int a, int b, int A, int B : 代 表目前棋盘 的有效范围 分别 就是 最左 最上 最右 最下
有效范围:就是包含所有已经落子区域的最小矩形 因为我这个五子棋 做的是有AI的为了减小 在棋盘上检索的范围 就只检索这个有效范围
如果 你不想考虑这些 就a=0 ,b=0,a=14,b=14;
bool win(int[,] winarr, Point luozi, int a, int b, int A, int B,int x) {
//这两个for指的就是所有的行和列 for (int row = a; row <= A; row++) { for (int colum = b; colum <= B; colum++) {
//4个if 指的就是 经过 最后落子位置的4条线 为什么要弄最后落子经过 的4条线呢 因为这样大大缩小了检索的范围
//我是怎吗让这4个if里面的直线 经过 最后的落子呢 这个 其实就是一个简单高中学的数学 的一次函数的知识
//row == luozi.X就保障了该直线 上所有的点都和最后落子在同一行 4个if()中写包含 luozi的都是为了保障 该线经过 落子
if (row == luozi.X && colum + 4 <= B && winarr[row, colum] == x && winarr[row, colum + 4] == x && winarr[row, colum + 1] == x && winarr[row, colum + 2] == x && winarr[row, colum + 3] == x) return true; if (colum == luozi.Y && row + 4 <= A && winarr[row, colum] == x && winarr[row + 4, colum] == x && winarr[row + 1, colum] == x&& winarr[row + 2, colum] == x && winarr[row + 3, colum] == x) return true; if (colum + row == luozi.X + luozi.Y && row - 4 >= a && colum + 4 <= B && winarr[row, colum] == x && winarr[row - 4, colum + 4] == x && winarr[row - 1, colum + 1] == x && winarr[row - 2, colum + 2] == x && winarr[row - 3, colum + 3] == x) return true; if (row - colum == luozi.X - luozi.Y && row + 4 <= A && colum + 4 <= B && winarr[row, colum] == x && winarr[row + 4, colum + 4] == x && winarr[row + 1, colum + 1] == x && winarr[row + 2, colum + 2] == x && winarr[row + 3, colum + 3] == x) return true; }
} return false; }
或许 有人认为这个方法 有些麻烦 因为 为了缩小检索的范围 我多弄了好多参数。 如果不考虑这些的 话仅用一个数组参数 就OK了
这些 代码核心 就是 4个if 只要你 认真弄懂 1一个if的含义 其他的都差不多 我个人认为 此方法的代码 已经够短了 对于5子棋 判断输赢 而且方法也比较好 减少了至少一半的运算量 如果你有其他好的方法 可以贴出来交流下
对于人人 对战的五子棋来说 核心的 算法 就是我上面贴出来的判断输赢 关于联机下五子棋 如果你学了协议方面的东西 就不用我多说了 相信你会做的 如果你对界面的绘制有问题 请看我的上一篇 如果你想了解 五子棋的AI制作 也就是做人机对战的五子棋我将在下一篇中讲解
上面的问题 我讲的比较细致 下面我就直接贴出 几个其他游戏的核心算法 来供大家 参考
先来个 简单的启发下新手的思维 其实 很多事物都是可以用程序表达的 如果你经常能把自己周围的事物也程序的眼光去看待 相信你的编程会有极大的提高 下面我就有一个程序描述出 石头剪刀布 这个游戏
enum CaiQuan//这就是个枚举 定义 了石头 ,剪刀 ,布 { ShiTou,//石头值为0 枚举类型的值默认等于他出现的次序 从0开始 JianDao,//剪刀值为1 Bu//布值为2 }
int win(CaiQuan A, CaiQuan B)//此方法 就是石头 剪刀 布的规则 参数 为 A的出招 ,和B的出招 { if (A == B)//A,B出招相同返回0 return 0; else if ((int)A - (int)B == 1 || (int)A - (int)B == 2)//A胜 返回 1 这个规律是我 总结的 石头剪刀布就那么 几种情况很好总结 return 1; else return -1;//没胜没平 自然就是输了 输了返回-1 }//这个算法 游戏规则 大家 都很清楚 根据 游戏规则直接转化成代码的 就需要列举所有的对阵情况 而我写的代码是从所有对阵情况的总结
下面在贴练练看的算法 好像没写注释 等有空我把他们一个一个给大家细细讲解 给对这方面有兴趣的朋友一个学习的帮助
练练看 连连看中基本上就一个算法就是 他的消除算法 如下
/// /// 连连看消除 /// /// 你鼠标上次点击的有效点
/// 你鼠标本次点击的有效点
/// 地图信息本地图 以大于等于0的一个整数来 表达 地图上的一个图片 -1表示无图片
/// 返回是否消除成功 public bool xiao(Point point1, Point point2,ref int [,]map) { bool isXiao = false; if (map[point1.X, point1.Y] != map[point2.X, point2.Y] || (point1.X == point2.X && point1.Y == point2.Y)) { return false; } if ((ISxiao(point1, new Point(0, point1.Y), false) && ISxiao(point2, new Point(0, point2.Y), false)) || (ISxiao(point1, new Point(point1.X, 0), true) && ISxiao(point2, new Point(point2.X, 0), true)) || (ISxiao(point1, new Point(point1.X, columnsCount - 1), true) && ISxiao(point2, new Point(point2.X, columnsCount - 1), true)) || (ISxiao(point1, new Point(rowsCount - 1, point1.Y), false) && ISxiao(point2, new Point(rowsCount - 1, point2.Y), false))) { isXiao = true; } for (int i = 0; i < columnsCount; i++) { if (ISxiao(new Point(point1.X, i), new Point(point2.X, i), false) && ISxiao(new Point(point1.X, i), point1, true) && ISxiao(new Point(point2.X, i), point2, true)) { isXiao = true; } } for (int j = 0; j < rowsCount; j++) { if (ISxiao(new Point(j, point1.Y), new Point(j, point2.Y), true) && ISxiao(new Point(j, point1.Y), point1, false) && ISxiao(new Point(j, point2.Y), point2, false)) { isXiao = true; } } if (isXiao) { map[point1.X, point1.Y] = -1; map[point2.X, point2.Y] = -1; point1 = new Point(); point2 = new Point(); } return isXiao; }
//线面这个方法是练练看的消除需要用到的
/// /// 返回一条从A1点到B1点之间这条线端上的点 是否有可通行 /// /// nt [,]map就是记录地图上所有信息的2为数组 -1代表无图片 其余值 个对应一张图片
/// 线段的一个端点
/// 另一个
/// 指的是这A1 和B1是在 横坐标相同 还是纵坐标相同
/// 是否可通行 public bool ISxiao(int [,]map,Point A1, Point B1, bool XY) { if (XY) { if (A1.Y > B1.Y) { for (int i = B1.Y; i <= A1.Y; i++) { if (map[A1.X, i] != -1 && new Point(A1.X, i) != point1 && new Point(A1.X, i) != point2) { return false; } } } else { for (int i = A1.Y; i <= B1.Y; i++) { if (map[A1.X, i] != -1 && new Point(A1.X, i) != point1 && new Point(A1.X, i) != point2) { return false; } } }
} else { if (A1.X > B1.X) { for (int i = B1.X; i <= A1.X; i++) { if (map[i, A1.Y] != -1 && new Point(i, A1.Y) != point1 && new Point(i, A1.Y) != point2) { return false; } } } else { for (int i = A1.X; i <= B1.X; i++) { if (map[i, A1.Y] != -1 && new Point(i, A1.Y) != point1 && new Point(i, A1.Y) != point2) { return false; } } } } return true; }
}
这个方法我写的比较长 如果你见到更好的算法 请发我研究下
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
本来想多帖几个小游戏的算法呢 可我的其他 的小游戏的算法 没整理好 直接用的群居变量 没用参数 贴出来不好看
本篇就讲到这里 下一篇讲 五子棋AI设计
本人喜欢研究算法问题 有同样爱好 的朋友加我QQ 851912010共同研究 另外 我最近想学C++求 高手指点
留个名 湖北省银河信息技术学院 10届学院 N2D10003班 胡成亮 写于 2011年 6月14号 本篇为原创可转载 勿复制winform gdi+ 小游戏算法讲解—— 接上篇格子类小游戏跳格子小游戏
Tags:  winform 跳格子小游戏

延伸阅读

最新评论

发表评论