lufy's legend

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
楼主: lufy

[html5游戏开发]数独游戏-完整算法-开源讲座

[复制链接]

30

主题

5

好友

7745

积分

诸侯王

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

发表于 2013-3-11 00:16:45 |显示全部楼层
开言:
本次讲一下数独游戏的开发,数独游戏是一个填数字的游戏,在一个9x9的方格内,这个9x9的大格子又可以分为9个3x3的小的九宫格,在这些格子内填写上1至9的数字,使得每一行,每一列,并且每个小的九宫格内的数字都不重复,游戏玩法简单,数字组合千变万化,所以玩起来特别有意思。
在中国数独游戏似乎没那么流行,但是在日本这个游戏非常受欢迎,在通勤的电车上,经常能看到一些人一个手拿着一本数独游戏的书,另一个手拿着一支铅笔,就这么一路计算着。现在我用lufylegend.js引擎来将这款游戏搬到浏览器上来,游戏界面如下图所示。

图1


游戏分为两个阶段,第一个阶段,是比较简单的玩法,只需要横,竖,没有重复的数字就可以了,另一个高级阶段,还需要保证每一个小的九宫格内的数字也不重复。想挑战一下的朋友,可以点击下面的游戏链接试一下自己能通过几关。
和之前的推箱子游戏一样,一共6关,游戏里也有排名系统,每过一关可以上传自己的成绩,跟大家比拼一下。

制作开始一,首先,你需要下载lufylegend.js引擎
下面是我在博客的lufylegend-1.6.0发布帖

下面一步步来进入开发正题。
二,游戏算法
这个游戏,我们首先要解决的就是数字如何打乱的问题,因为不但要把数字打乱,还要保证这些数字被打乱后,依然符合数独的规则,然后在打乱的数字中隐藏一部分,就可以开始游戏了。
我们先来看一组数字
图2
可以看到,在这组数字中,它的横,竖列上的数字都是不重复的。我们如何来把它的顺序打乱呢?不难看出,如果我们只把它的每一行打乱,那么它的完整性是不受影响的。同样,我们只把它的每一列进行打乱,它也是不会受到影响的。所以,要打乱它只需要以行和列为单位进行打乱就行了,算法如下。
  1. function randomNum01(lv){
  2.         var i,j,list = new Array(),result = new Array();
  3.         for(i=0;i<9;i++){
  4.                 list.push([1,2,3,4,5,6,7,8,9]);
  5.                 for(j=0;j.5?-1:1;});
  6.         var rand = new Array(0,1,2,3,4,5,6,7,8).sort(function(a,b){return Math.random()>.5?-1:1;});
  7.         for(i=0;i<9;i++){
  8.                 for(j=0;j<9;j++){
  9.                         result[i].push(list[i][rand[j]]);
  10.                 }
  11.         }

  12.         for(i=0;i<9;i++){
  13.                 for(j=0;j>> 0;
  14.                         result[i][ran1] = 0;
  15.                         ran1 = Math.random()*9 >>> 0;
  16.                         result[ran1][i] = 0;
  17.                 }
  18.         }
  19.         return result;
  20. }
复制代码
上面的函数,我首先生成了一组有规律的数字,然后按照行和咧进行打乱,最后,随机拿掉一些数字。
下面再看另一组数字。
图3
这种情况下,我们还要保证每个小九宫格内的数字的完整性,又要怎么做呢?在这里我有一种偷懒的算法,看下面的图4。
图4
我们将行和列每3个作为一个单位进行打乱,就很简单的达到了目的了,当然这只是一种偷懒的算法,如果你有更好的算法,欢迎一起讨论,我的算法如下。
  1. function randomNum02(lv){
  2.         var i,j,k,list = [],result = [],rand;
  3.         for(i=0;i<9;i++){
  4.                 list.push([1,2,3,4,5,6,7,8,9]);
  5.                 for(j=0;j.5?-1:1;}).concat(
  6.                         new Array(3,4,5).sort(function(a,b){return Math.random()>.5?-1:1;}),
  7.                         new Array(6,7,8).sort(function(a,b){return Math.random()>.5?-1:1;})
  8.                 );
  9.         for(i=0;i<9 i="" result="" push="" list="" rand="" i="" list="result;" rand="new" array="" 0="" 1="" 2="" sort="" function="" a="" b="" return="" math="" random="">.5?-1:1;}).concat(
  10.                         new Array(3,4,5).sort(function(a,b){return Math.random()>.5?-1:1;}),
  11.                         new Array(6,7,8).sort(function(a,b){return Math.random()>.5?-1:1;})
  12.                 );
  13.         result = [];
  14.         for(i=0;i<9;i++){
  15.                 result.push([]);
  16.                 for(j=0;j<9;j++){
  17.                         result[i].push(list[i][rand[j]]);
  18.                 }
  19.         }

  20.         for(i=0;i<9;i++){
  21.                 for(j=0;j>> 0;
  22.                         result[i][ran1] = 0;
  23.                         ran1 = Math.random()*9 >>> 0;
  24.                         result[ran1][i] = 0;
  25.                 }
  26.         }
  27.         return result;
  28. }
复制代码
三,判断数字的正确性
当玩家将所有被取走的数字都恢复了之后,就要判断一下他们填写的数字是否正确,是不是符合数独的游戏规则,方法很简单,就是验证每一行,每一列,以及高级阶段的时候每个九宫格内的数字,是不是没有重复,下面是代码
  1. function checkWin(){
  2.         var check01,check02;
  3.         for(var i=0;i<9;i++){
  4.                 check01 = [];
  5.                 check02 = [];
  6.                 for(var j=0;j<9 j="" if="" stagenumlist="" i="" j="" value=""> 0)check01.push(stageNumList[i][j].value);
  7.                         if(stageNumList[j][i].value > 0)check02.push(stageNumList[j][i].value);
  8.                 }
  9.                 check01 = deleteEleReg(check01);
  10.                 check02 = deleteEleReg(check02);
  11.                 if(check01.length < 9)return false;
  12.                 if(check02.length < 9)return false;
  13.         }
  14.         var stage = stageMenu[stageIndex];
  15.         if(stage.flag){
  16.                 return checkWin02();
  17.         }
  18.         return true;
  19. }
  20. function checkWin02(){
  21.         for(var i=0;i<3;i++){
  22.                 for(var j=0;j<3;j++){
  23.                         if(!check_mini(i,j))return false;
  24.                 }
  25.         }
  26.         return true;
  27. }
  28. function check_mini(i2,j2){
  29.         var check_arr = [];
  30.         for(var i=i2*3;i<i2*3+3;i++){
  31.                 for(var j=j2*3;j<j2*3+3;j++){
  32.                         if(check_arr[stageNumList[i][j].value])return false;
  33.                         check_arr[stageNumList[i][j].value] = 1;
  34.                 }
  35.         }
  36.         return true;
  37. }
复制代码


这个游戏很简单,以上,整个游戏的核心算法都已经解决了。
四,建一个开始画面
如下。
图4

上次我也说了,使用lufylegend.js引擎做个界面,可以说毫无难度,代码如下。
  1. function GameLogo(){
  2.         base(this,LSprite,[]);
  3.         var self = this;
  4.        
  5.         var logolist = [[1,1,1,1],[1,2,4,1],[1,4,2,1],[1,1,1,1]];
  6.         var bitmap,logoLayer;
  7.         logoLayer = new LSprite();
  8.         bitmap = new LBitmap(new LBitmapData(imglist["logo"]));
  9.         bitmap.scaleX = bitmap.scaleY = 2;
  10.         logoLayer.addChild(bitmap);
  11.         self.addChild(logoLayer);
  12.         var social = new Social();
  13.         social.x = 60;
  14.         social.y = 500;
  15.         self.addChild(social);
  16.        
  17.         labelText = new LTextField();
  18.         labelText.font = "HG行書体";
  19.         labelText.size = 14;
  20.         labelText.x = 50;
  21.         labelText.y = 650;
  22.         labelText.text = "- Html5 Game Engine lufylegend.js";
  23.         self.addChild(labelText);
  24.         labelText = new LTextField();
  25.         labelText.color = "#006400";
  26.         labelText.font = "HG行書体";
  27.         labelText.size = 14;
  28.         labelText.x = 50;
  29.         labelText.y = 700;
  30.         labelText.text = "http://www.lufylegend.com/lufylegend";
  31.         self.addChild(labelText);
  32.        
  33.         self.addEventListener(LMouseEvent.MOUSE_UP,menuShow);
  34. };
复制代码
这一次我用了一张图片做界面,代码就更简单了,文字显示依然是LTextField对象,使用方法请参考官方API文档。
五,建一个选择画面
如下。


图5

代码如下。
  1. function GameMenu(){
  2.         base(this,LSprite,[]);
  3.         var self = this;
  4.        
  5.         var menuLayer;
  6.         menuLayer = new LSprite();
  7.         bitmap = new LBitmap(new LBitmapData(imglist["menu_back"]));
  8.         bitmap.scaleX = bitmap.scaleY = 2;
  9.         menuLayer.addChild(bitmap);
  10.         self.addChild(menuLayer);
  11.        
  12.         labelText = new LTextField();
  13.         labelText.color = "#B22222";
  14.         labelText.font = "HG行書体";
  15.         labelText.size = 40;
  16.         labelText.x = 30;
  17.         labelText.y = 700;
  18.         labelText.stroke = true;
  19.         labelText.lineWidth = 4;
  20.         labelText.text = "Please select !!";
  21.         menuLayer.addChild(labelText);
  22.        
  23.         for(var i=0;i<stageMenu.length;i++){
  24.                 self.stageVsMenu(stageMenu[i]);
  25.         }
  26. };
  27. GameMenu.prototype.stageVsMenu = function(obj){
  28.         var self = this;
  29.        
  30.         var menuButton = new LSprite();
  31.         var bitmap = new LBitmap(new LBitmapData(imglist["menu_stage"]));
  32.         menuButton.addChild(bitmap);
  33.         menuButton.x = obj.x * 220 + 30;
  34.         menuButton.y = obj.y * 200 + 50;
  35.         self.addChild(menuButton);
  36.         if(obj.open){
  37.                 labelText = new LTextField();
  38.                 labelText.color = "#ffffff";
  39.                 labelText.font = "HG行書体";
  40.                 labelText.size = 20;
  41.                 labelText.x = 50;
  42.                 labelText.y = 90;
  43.                 menuButton.addChild(labelText)
  44.                 labelText.text = "第"+(obj.index+1)+"关";
  45.                
  46.                 labelText = new LTextField();
  47.                 labelText.color = "#ffffff";
  48.                 labelText.font = "HG行書体";
  49.                 labelText.size = 12;
  50.                 labelText.x = 30;
  51.                 labelText.y = 30;
  52.                 menuButton.addChild(labelText)
  53.                 labelText.text = "times:"+obj.times;
  54.                 menuButton.obj = obj;
  55.                 menuButton.addEventListener(LMouseEvent.MOUSE_UP,function(event,self){
  56.                         gameStart(self.obj.index);
  57.                 });
  58.         }else{
  59.                 labelText = new LTextField();
  60.                 labelText.color = "#ffffff";
  61.                 labelText.font = "HG行書体";
  62.                 labelText.size = 20;
  63.                 labelText.x = 60;
  64.                 labelText.y = 40;
  65.                 menuButton.addChild(labelText)
  66.                 labelText.text = "???";
  67.         };
  68. }
复制代码
好了,游戏基本的代码已经都贴出来了。

源码
下面提供完整游戏源代码,想研究一下的朋友可以点击下面的连接下载。


注意:该附件只包含本次文章源码,lufylegend.js引擎请到http://lufylegend.com/lufylegend进行下载。

转载请注明:转自lufy_legend的博客


欢迎继续关注我的博客

http://blog.csdn.net/lufy_legend


不回答与技术和引擎不相关的问题
回复

使用道具 举报

1

主题

0

好友

19

积分

士兵

Rank: 1

发表于 2013-4-4 14:41:08 |显示全部楼层
顶一个
回复

使用道具 举报

0

主题

0

好友

4

积分

士兵

Rank: 1

发表于 2014-1-13 00:09:42 |显示全部楼层
多谢楼主分享。回去研究研究。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

Archiver|lufy's legend

GMT+8, 2017-12-16 09:27 , Processed in 0.161992 second(s), 22 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部