80年代的游戏了吧?个人比较喜欢玩,今天特地收集了一些资料自行写了一个
上点效果
鼠标右键提示方块的最终位置
3*3,4*4,5*5都没问题的
10*10的也玩过,暂时没发现什么bug
控件是一张control派生而来的控件,没有任何控件嵌套,所有的操作都是重新用D2D画的,
控件对外的方法和属性
1.返回一张完成后的图片的样张 public Bitmap perfect_image()
2 . 步数统计 public int Mouseclick
3.初始化控件,开始玩和重新玩时使用 void init_control()
4.完成时的事件 游戏结束时触发 public event onfinished finished
写点思路
一张图片,正方形的,width==height,一个值count(这个count指的是每列每行的块数),裁剪图片,剪成count*count块图片
/// <summary> /// 拼图元素裁剪 /// </summary> private void init_element() {
这里bm是完整的图片 Bitmap bm = new Bitmap(image_dir); // 释放 bmback = new Bitmap(bm.Width, bm.Height); size是每个块的大小,count是每列每行的块数 size = bm.Width / count; white_image = new Bitmap(size, size); Graphics g = Graphics.FromImage(white_image); Pen pen = new Pen(Color.Blue, 1f); g.Clear(Color.White); g.DrawRectangle(pen, 0, 0, size - 1, size - 1); g.Dispose(); Bitmap bmsmall = new Bitmap(size, size); g = Graphics.FromImage(bmsmall); 把每块画到每张图片上,一共count*count张图片(即count*count块),这些图片存放在一个bitmap链表lb中 for (int i = 0; i < count; i++) for (int j = 0; j < count; j++) { Rectangle rect = new Rectangle(i * size, j * size, size, size); Rectangle rect1 = new Rectangle(0, 0, size, size); g.DrawImage(bm, rect1, rect, GraphicsUnit.Pixel); g.DrawRectangle(pen, 0, 0, size - 1, size - 1);
lb是一个链表,存放所有的块 lb[i, j] = (Bitmap)bmsmall.Clone(); }
bmsmall.Dispose(); g.Dispose(); pen.Dispose();
这里根据图片大小设置控件大小 this.Width = bm.Width; this.Height = bm.Height;// +SystemInformation.CaptionHeight; bm.Dispose(); // 已释放 }
创建一个乱序的二维数组,用于记录每个位置对应的图片
创建一个能完成拼图的二维数组,
0元素就是在没完成拼图是空白的那个块
这个二维数组是有条件的:最初二维数组和最终二维数组的逆序数+0元素的x位置+0元素的y位置的奇偶特性是一致的
逆序数就是数组中后面元素小于前面元素的次数和
我以2*2为例
最终被拼成时的块的位置应该是这样的
| 0 1 |
| 2 3 |
二维数组的逆序数一个都没有,0元素的位置也是(0,0),所以为0+0+0=0;偶数
设这个是最初的块的位置分布,这个是可以完成拼图的
| 1 3 |
| 0 2 |
这个二维数组(1,3,0,2)的逆序有(1,0)(3,0)(3,2),逆序数为3,而0元素的位置在(0,1),所以3+0+1=4;偶数
所以这个乱序的二维数组拼图能通过拼图实现完整的图片
这个条件扩展到n*n的拼图都是没问题的
/// <summary> /// 返回一个乱序的二维数组 /// </summary> /// <returns></returns> private int[,] Out_of_Order() { int sum = 0; List<int> li = new List<int>(0); do { //初始化 sum = 0; li.Clear(); for (int i = 0; i < count * count; i++) { li.Add(i); } //乱序 Random rd = new Random(); for (int i = 0; i < count * count; i++) { li.Insert(rd.Next(count * count), li[count * count - 1]); } //奇偶效验 for (int i = 0; i < count * count; i++) { for (int j = 0; j < i; j++) { if (li[i] < li[j]) sum++; } if (li[i] == 0) { sum = sum + i / count + i % count; } } } while (sum % 2 != 0);//偶数? //转为二维数组 for (int i = 0; i < count; i++) for (int j = 0; j < count; j++) { ia[i, j] = li[i * count + j]; } //已经完成了?重新乱序 if (success_check()) Out_of_Order(); return ia; }
主要的思路就这个
至于其他的思路我就不提供了,看源码可以看懂
源码:http://pan.baidu.com/s/1gelvbsn