在中国数独游戏似乎没那么流行,但是在日本这个游戏非常受欢迎,在通勤的电车上,经常能看到一些人一个手拿着一本数独游戏的书,另一个手拿着一支铅笔,就这么一路计算着。现在我用lufylegend.js引擎来将这款游戏搬到浏览器上来,游戏界面如下图所示。
游戏分为两个阶段,第一个阶段,是比较简单的玩法,只需要横,竖,没有重复的数字就可以了,另一个高级阶段,还需要保证每一个小的九宫格内的数字也不重复。想挑战一下的朋友,可以点击下面的游戏链接试一下自己能通过几关。
和之前的推箱子游戏一样,一共6关,游戏里也有排名系统,每过一关可以上传自己的成绩,跟大家比拼一下。
制作开始
一,首先,你需要下载lufylegend.js引擎
下面是我在博客的lufylegend-1.6发布帖
下面一步步来进入开发正题。
二,游戏算法
这个游戏,我们首先要解决的就是数字如何打乱的问题,因为不但要把数字打乱,还要保证这些数字被打乱后,依然符合数独的规则,然后在打乱的数字中隐藏一部分,就可以开始游戏了。
我们先来看一组数字
可以看到,在这组数字中,它的横,竖列上的数字都是不重复的。我们如何来把它的顺序打乱呢?不难看出,如果我们只把它的每一行打乱,那么它的完整性是不受影响的。同样,我们只把它的每一列进行打乱,它也是不会受到影响的。所以,要打乱它只需要以行和列为单位进行打乱就行了,算法如下。
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.
13. for(i=0;i<9;i++){
14. for(j=0;j>> 0;
15. result[i][ran1] = 0;
16. ran1 = Math.random()*9 >>> 0;
17. result[ran1][i] = 0;
18. }
19. }
20. return result;
21. }
上面的函数,我首先生成了一组有规律的数字,然后按照行和咧进行打乱,最后,随机拿掉一些数字。
下面再看另一组数字。
这种情况下,我们还要保证每个小九宫格内的数字的完整性,又要怎么做呢?在这里我有一种偷懒的算法,看下面的图4。
我们将行和列每3个作为一个单位进行打乱,就很简单的达到了目的了,当然这只是一种偷懒的算法,如果你有更好的算法,欢迎一起讨论,我的算法如下。
[javascript] view plaincopy
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.
21. for(i=0;i<9;i++){
22. for(j=0;j>> 0;
23. result[i][ran1] = 0;
24. ran1 = Math.random()*9 >>> 0;
25. result[ran1][i] = 0;
26. }
27. }
28. return result;
29. }
三,判断数字的正确性
当玩家将所有被取走的数字都恢复了之后,就要判断一下他们填写的数字是否正确,是不是符合数独的游戏规则,方法很简单,就是验证每一行,每一列,以及高级阶段的时候每个九宫格内的数字,是不是没有重复,下面是代码
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 31. for(var j=j2*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. }
这个游戏很简单,以上,整个游戏的核心算法都已经解决了。
四,建一个开始画面
如下。
上次我也说了,使用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文档。
五,建一个选择画面
如下。
代码如下。
[javascript] view plaincopy
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 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. }