拼图游戏

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

 

转载于:https://www.cnblogs.com/magicianlyx/p/5205799.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值