关于这个游戏的创意和较为深入的研究来自于新浪博客大力水手。
拉登游戏的游戏思路是:
一个N*N的方格,每个格子的有两种颜色状态(黑色,黄色);初始时所有格子为同一种颜色(比如:黑色),通过点击其中的一个格子,该格子以及其上下左右的格子的颜色将变为相反的颜色(之前黑色,之后黄色;反之亦然)。
如下面六张图可以看到整个游戏的玩法:
游戏开发过程考虑的几个问题:
1.生成的N*N格子的应该自适应Window
2.点击格子四周的格子的边界问题处理
3.格子的颜色变化设置
4.判断所有格子颜色是否发生改变
5.如何实现自动完成功能
游戏开发的关键就在于这个自动完成的算法实现。
算法:
格子共有N*N个,共N行N列,自动完成基于第一行的实现,每一个格子的状态只有两种,设为0或1.
1.第0行有N个格子,每个格子共有2中状态,全排列共有Pow(2, N)中情况。
2.给每一种情况进行编号[0,Pow(2,N))
如下图3*3的格子,第0行的格子的状态:
分析:第0行的状态共有Pow(2,N)中,接下来对第1行至第N-1一行进行遍历,每一行有N个格子进行点击处理,这样时间复杂度上升为:Pow(2, N)*Pow(N, 2)。如果N为32的时候,就仅仅让计算机走完这个数,Java中Integer.MAX_VALUE尝试了一下没有等到这个数就给Stop了。
具大力水手的说法,目前通过分布式计算,已经完成到了N=35。每一种贴下来的图都是一幅美丽的图片(这个得仔细想象加观察)
下面贴一张图:
下面是C#版的部分代码程序较为简单,主要立足解决分布式问题。
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- using System.Threading;
- namespace OkLight
- {
- public partial class FormMain : Form
- {
- Button[] btns = new Button[25];
- //设置两个全局的数组变量
- static int[] states;
- static int[] operaters;
- //设置一个全局变量用来计算点击的次数
- static int count = 0;
- //构造方法初始化组件
- public FormMain()
- {
- InitializeComponent();
- }
- //初始化下拉菜单的选项值
- private void FormMainLoad(object sender, EventArgs e)
- {
- int min = panelMain.Height;
- if (min > panelMain.Width)
- {
- min = panelMain.Width;
- }
- int maxNumber = min / 40;
- for (int i = 1; i < maxNumber + 1; i++)
- {
- comboBoxIndex.Items.Add(i);
- }
- comboBoxIndex.SelectedIndex = 4;
- InitalButton((int)comboBoxIndex.SelectedItem);
- }
- //初始按钮
- private void InitalButton(int number)
- {
- panelMain.Controls.Clear();
- //获得面板的大小
- int x = (panelMain.Width - number*40) / 2;
- int y = (panelMain.Height - number * 40) / 2;
- btns = new Button[number * number];
- //实例化按钮并且添加到面板中去
- for (int i = 0; i < number*number; i++)
- {
- btns[i] = new Button();
- btns[i].Width = 40;
- btns[i].Height = 40;
- //设置按钮的位置
- btns[i].Left = x + (i % number) * 40;
- btns[i].Top = y + (i / number) * 40;
- //设置按钮表面的颜色
- btns[i].BackColor = Color.Black;
- //为每一个按钮注册单击处理
- btns[i].Click += new EventHandler(FormMainClick);
- panelMain.Controls.Add(btns[i]);
- }
- }
- //格子事件方法
- void FormMainClick(object sender, EventArgs e)
- {
- int number = (int)comboBoxIndex.SelectedItem;
- Button btn = sender as Button;
- //获得面板的大小
- int x = (panelMain.Width - 40*number) / 2;
- int y = (panelMain.Height - 40*number) / 2;
- //得到按钮的索引
- int i = (btn.Left - x) / 40;
- int j = (btn.Top - y) / 40;
- //得到当前单击的按钮的上下左右按钮的坐标
- int top = j - 1;
- int buttoom = j + 1;
- int left = i - 1;
- int right = i + 1;
- count++;
- ChangeButtonColor(btn);
- if (top >= 0)
- {
- int index = i + number * top;
- ChangeButtonColor(btns[index]);
- }
- if (buttoom < number)
- {
- int index = i + number * buttoom;
- ChangeButtonColor(btns[index]);
- }
- if(left>=0)
- {
- int index = left + number * j;
- ChangeButtonColor(btns[index]);
- }
- if (right < number)
- {
- int index = right + number * j;
- ChangeButtonColor(btns[index]);
- }
- showLabel.Text = "您当前已经点击次数为: " + count;
- if (IsSucceed(number))
- {
- DialogResult dr=MessageBox.Show("恭喜你,成功完成", "消息");
- }
- }
- //改变格子背景颜色
- private void ChangeButtonColor(Button btn)
- {
- if (btn.BackColor == Color.Black)
- {
- btn.BackColor = Color.Yellow;
- }
- else
- {
- btn.BackColor = Color.Black;
- }
- btn.Refresh();
- }
- //演示游戏
- private void GetShow(int number)
- {
- //设置方格的边的个数
- //计算格子的总个数
- int count = (int)Math.Pow(number, 2);
- //初始化数组的值
- //计算一共有多少种情况,number=5是32种情况
- //operaters数组中放的是每一种情况的每一个格子的操作取值
- //states数组中放的是每一种情况的每一个格子的状态取值
- //在计算过程中不一定将for语句运行完,当判断states[]的值全为1便可以终止
- for (int i = 0; i < (int)Math.Pow(2, number); i++)
- {
- states = new int[count];
- operaters = new int[count];
- int x = i;//i表示第几种情况
- int j = 0;
- //进行第i种情况的operaters的赋值
- while (true)
- {
- if (x == 0)
- {
- break;
- //当x=0的时候跳出while循环
- }
- //将x转换为二进制数0 1
- operaters[j] = x % 2;
- x = x / 2;
- j++;
- }
- //第i种情况的operaters[]设置完成之后进行操作
- //这个操作只进行一行
- for (int k = 0; k < number; k++)
- {
- //operaters[]值为1的时候表示操作
- if (operaters[k] == 1)
- {
- ToClick(k, number);
- }
- }
- //对第i种情况下从第2行开始操作直到number行
- for (int k = 1; k < number; k++)
- {
- //对第i种情况下从第k行的每一格格子开始操作
- for (int m = 0; m < number; m++)
- {
- //判断k-1行第m格格子的状态
- //在进行操作的时候,只点击上一行状态没有改变的格子对应下面的格子
- //Console.Write(states[(k - 1) * number + m]);
- if (states[(k - 1) * number + m] == 0)
- {
- //一旦将格子点击之后,它的操作状态就职位 1;
- operaters[k * number + m] = 1;
- ToClick(k * number + m, number);
- }
- }
- }
- //通过计算可以判断是否已经完成操作
- int statesCount = 0;
- for (int k = 0; k < states.Length; k++)
- {
- if (states[k] == 1)
- {
- statesCount++;
- }
- }
- //states[]的值和为count表明完成操作
- if (statesCount == count)
- {
- break;
- }
- }
- }
- //判断游戏是否结束
- private bool IsSucceed(int number)
- {
- bool result = false;
- for (int i = 0, j = number * number; i < j; i++)
- {
- if (btns[i].BackColor == Color.Black)
- {
- result = false;
- break;
- }
- else
- {
- result = true;
- }
- }
- return result;
- }
- //下拉菜单改变信息
- private void SelectedIndexChanged(object sender, EventArgs e)
- {
- int number = (int)comboBoxIndex.SelectedItem;
- count = 0;
- showLabel.Text = "您当前已经点击次数为:";
- InitalButton(number);
- }
- //点击格子事件
- private static void ToClick(int tag, int number)
- {
- //tag表示从操作中传递的值,它是格子从 [0-number*number) 的编号
- //计算行号
- int j = tag / number;
- //计算列号
- int i = tag % number;
- int left = i - 1;
- int right = i + 1;
- int top = j - 1;
- int buttom = j + 1;
- ChangeButtonStates(tag);
- if (left >= 0)
- {
- ChangeButtonStates(left + number * j);
- }
- if (right < number)
- {
- ChangeButtonStates(right + number * j);
- }
- if (top >= 0)
- {
- ChangeButtonStates(i + number * top);
- }
- if (buttom < number)
- {
- ChangeButtonStates(i + number * buttom);
- }
- }
- //设置格子状态
- private static void ChangeButtonStates(int index)
- {
- if (states[index] == 0)
- {
- states[index] = 1;
- }
- else
- {
- states[index] = 0;
- }
- }
- //游戏演示按钮事件
- private void BtnShowClick(object sender, EventArgs e)
- {
- int number = (int)comboBoxIndex.SelectedItem;
- GetShow(number);
- for(int i = 0; i < operaters.Length;i++)
- {
- if(operaters[i]==1)
- {
- btns[i].PerformClick();
- Thread.Sleep(1000);
- }
- }
- }
- }
- }
游戏算是成功的开发完了,而且这个游戏是没有终结点的。因为任何人在每一步都走对的情况下都没法通过鼠标点击走到N=32的情况去,甚至更小。这算是一个探讨分布式计算的一个非常好的实例。
本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1073349,如需转载请自行联系原作者