拼图游戏就是将用户选择的图片根据选择的难度进行分割,并抽出一张图片用空白块代替,同时随机打乱顺序,作为拼图的初始游戏界面。当用户点击空白块周围上下左右相邻的图片时,可以移动该图片,当整个图片的位置都与原始图片一致时,拼图完成。

拼图算法

这个拼图游戏用到了人工智能领域的一个非常著名的算法——N Puzzle问题。随机交换图片的位置之后,生成的拼图游戏很多是无解的,且这个比例高达50%左右,所以必须先判断生成的拼图是否有解。

我们将图片暂时用数字来代替,这样整个拼图游戏就变成了一个数字矩阵,假设随机得到了这个矩阵,其中X用来代表空格的图片,如下所示:

⎡⎣⎢⎢⎢12758111X1310496214153⎤⎦⎥⎥⎥拼图矩阵

\left[\begin{matrix}12 & 1 & 10 & 2 \\7 & 11 & 4 & 14 \\5 & X & 9 & 15 \\8 & 13 & 6 & 3\end{matrix}\right] 拼图矩阵
对图片拼图的还原,与还原上图中的数字矩阵,其实是一个道理。现在,将这个矩阵写成一维数组的形式,并将其记为序列A, 如下所示。

A = {12, 1, 10, 2, 7, 11, 4, 14, 5, X, 9, 15, 8, 13, 6, 3}

再定义一个“倒置变量值”的算法—— T T。TiT_i表示序列 A A中位于第i位之后,比AiA_i小的元素的个数(不算X)。例如对上面的序列 A A中的每个元素进行“倒置变量值”的计算,其结果如下所示。

11, 0, 8, 0, 4, 6, 1, 6, 1, 3, 4, 2, 2, 1

最后,求得所有“倒置变量值”的和SumT=49。Sum_T = 49。在N Puzzle算法中,使用如下两个原则来判断一个N Puzzle问题是否有解。

  • 如果序列A的宽度为奇数,那么每个可解的问题所定义的“倒置变量值”的和—— SumT Sum_T必须为偶数。
  • 如果序列A的宽度为偶数,那么当空格X位于从下往上数的奇数行中时,定义的“倒置变量值”的和—— SumT Sum_T必须为偶数;当空格X位于从下往上数的偶数行中时,定义的“倒置变量值”的和—— SumT Sum_T必须为奇数。

图片工具

通过这两步处理,就把图片分割成了NxN个小的Item,并将最后一个图片剔除,用于显示要移动的空格图片(即数字X)。最后,通过GridView的数据适配器,将这些图片添加到拼图游戏的GridView中显示出来。

/*** Created by Administrator on 2016/6/14.* 图像工具类:实现图像的分割与自适应*/
public class ImagesUtil {/*** 切图、初始状态(正常顺序)** @param type        游戏种类* @param picSelected 选择的图片* @param context     context*/public void createInitBitmaps(int type, Bitmap picSelected, Context context) {ItemBean itemBean = null;Bitmap bitmap = null;List<Bitmap> bitmapItems = new ArrayList<Bitmap>();// 每个Item的宽高int itemWidth = picSelected.getWidth() / type;int itemHeight = picSelected.getHeight() / type;for (int i = 1; i <= type ; i++) {for (int j = 1; j <= type; j++) {bitmap = Bitmap.createBitmap(picSelected, (j - 1) * itemWidth, (i -1) * itemHeight,itemWidth, itemHeight);bitmapItems.add(bitmap);itemBean = new ItemBean((i - 1) * type + j, (i - 1) * type + j, bitmap);GameUtil.mItemBeans.add(itemBean);}}// 保存最后一个图片在拼图完成时填充PuzzleActivity.mLastBitmap = bitmapItems.get(type * type -1);// 设置最后一个为空ItembitmapItems.remove(type * type -1);GameUtil.mItemBeans.remove(type * type -1);Bitmap blankBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.blank);blankBitmap = Bitmap.createBitmap(blankBitmap, 0 , 0, itemWidth, itemHeight);bitmapItems.add(blankBitmap);GameUtil.mItemBeans.add(new ItemBean(type * type, 0, blankBitmap));GameUtil.mBlankItemBean = GameUtil.mItemBeans.get(type * type - 1);}/*** 处理图片 放大、缩小到合适位置** @param newWidth  缩放后Width* @param newHeight 缩放后Height* @param bitmap    bitmap* @return bitmap*/public Bitmap resizeBitmap(float newWidth, float newHeight, Bitmap bitmap) {Matrix matrix = new Matrix();matrix.postScale(newWidth / bitmap.getWidth(), newHeight/ bitmap.getHeight());Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);return newBitmap;}
}

生成游戏

前面获取了按顺序分割的图片,下面通过一个循环来随机交换Item中的图片,从而生成杂乱的拼图游戏。由于随机生成的拼图游戏有将近50%都是无解的,所以还需要判断当前生成的游戏是否有解。

 // 游戏信息单元格Beanpublic static List<ItemBean> mItemBeans = new ArrayList<ItemBean>();// 空格单元格public static ItemBean mBlankItemBean = new ItemBean();/*** 生成随机的Item*/public static void getPuzzleGenerator() {int index = 0;// 随机打乱顺序for (int i = 0; i < mItemBeans.size(); i++) {index = (int) (Math.random() * PuzzleActivity.TYPE * PuzzleActivity.TYPE);swapItems(mItemBeans.get(index), mBlankItemBean);}List<Integer> data = new ArrayList<Integer>();for (int i = 0; i < mItemBeans.size(); i++) {data.add(mItemBeans.get(i).getBitmapId());}// 判断生成是否有解if (!canSolve(data))getPuzzleGenerator();}/*** 交换空格与点击Item的位置** @param from  交换图* @param blank 空白图*/public static void swapItems(ItemBean from, ItemBean blank) {ItemBean tempItemBean = new ItemBean();// 交换BitmapIdtempItemBean.setBitmapId(from.getBitmapId());from.setBitmapId(blank.getBitmapId());blank.setBitmapId(tempItemBean.getBitmapId());// 交换BitmaptempItemBean.setBitmap(from.getBitmap());from.setBitmap(blank.getBitmap());blank.setBitmap(tempItemBean.getBitmap());// 设置新的BlankGameUtil.mBlankItemBean = from;}/*** 该数据是否有解** @param data 拼图数组数据* @return 该数据是否有解*/public static boolean canSolve(List<Integer> data) {//获取空格Idint blankId = mBlankItemBean.getItemId();// 可行性原则if (data.size() % 2 == 1) {return getInversions(data) % 2 == 0;} else {// 从底往上数,空格位于奇数行if (((blankId - 1) / PuzzleActivity.TYPE) % 2 == 1) {return getInversions(data) % 2 == 0;} else {// 从底往上数,空位位于偶数行return getInversions(data) % 2 == 1;}}}/*** 计算倒置和算法** @param data 拼图数组数据* @return 该序列的倒置和*/public static int getInversions(List<Integer> data) {int inversions = 0;int inversionCount = 0;for (int i = 0; i < data.size(); i++) {for (int j = i + 1; j < data.size(); j++) {int index = data.get(i);if (data.get(j) != 0 && data.get(j) < index)inversionCount++;}inversions += inversionCount;inversionCount = 0;}return inversions;}

移动图片

生成游戏后,就可以给GridView的每个Item来响应点击事件了。当点击的图片是空格图片上下左右的图片时,就可以交换两个Item,实现移动的效果。如果点击的是其他图片,自然是不能移动。

    /*** 判断点击的Item是否可移动** @param position position* @return 能否移动*/public static boolean isMoveable(int position) {int type = PuzzleActivity.TYPE;// 获取空格Itemint blankId = mBlankItemBean.getItemId() - 1;// 不同行 相差为typeif (Math.abs(blankId - position) == type) {return true;}// 相同行 相差为1if ((blankId / type == position / type) && Math.abs(blankId - position) == 1) {return true;}return false;}

如果判读可以移动,则使用swapItems方法进行交换。每次交换后,还需要对当前游戏进行判断。判断是否已经还原成功,即当前图片Item的ID与初始状态下图片的ID是否相同。如果还原成功,那么就将最后缺失的那一块图片补齐。

    /*** 是否拼图成功** @return 是否拼图成功*/public static boolean isSuccess() {for (ItemBean tempBean : mItemBeans) {if(tempBean.getBitmapId() != 0 && tempBean.getItemId() == tempBean.getBitmapId()){continue;}else if(tempBean.getBitmapId() == 0 &&tempBean.getItemId() == PuzzleActivity.TYPE * PuzzleActivity.TYPE){continue;} else {return false;}}return true;}

程序运行后效果图如下所示:

代码地址

移动迷宫——拼图游戏相关推荐

  1. python拼图游戏代码_GitHub 上哪些勾起回忆的经典小游戏(Python)

    经常有人问我 Python 能开发游戏吗?今天就直接给大家推荐一个汇集多款经典小游戏的Github项目:Free Python Games. 项目地址:grantjenks/free-python-g ...

  2. python迷宫小游戏代码_6.1 | 童年的游戏,Python一行代码就能玩

    作者 | 刘早起来源 | 早起Python 大家好,儿童节就要来了,虽然秃头程序员没有头发,但是童心还是一直都在的,今天就分享一个私藏的GitHub项目--free-python-games,一行代码 ...

  3. HTML5游戏实战之拼图游戏(包含关卡)

    拼图游戏是每个人小时候都玩过的经典休闲游戏,依托Hola Studio强大的图片功能和事件回调体系,实现一个游戏性十足的拼图游戏并不难.本文就介绍整个游戏的制作过程,本游戏包含完整的游戏元素,包括广告 ...

  4. Python游戏开发,pygame模块,Python实现过迷宫小游戏

    前言 今天为大家带来解闷用的过迷宫小游戏分享给大家好了.让我们愉快地开始吧~ 效果展示 开发工具 Python版本: 3.6.4 相关模块: pygame模块: 以及一些Python自带的模块. 环境 ...

  5. 拼图游戏 复制粘贴一个叫lemene的人的,这个人是c++博客的用户,我不是,怕以后找不到这篇文章,所以复制粘贴了。文中最后给出了原文链接连接...

    本文讨论如何判断拼图游戏中图形是否可以还原. 例1:下图是一个3X3的数字拼图. 1 3 2 6 5 4 7 8 图1 它要还原成图2 1 2 3 4 5 6 7 8 图2 将问题一般化,在M*N的方 ...

  6. 拼图游戏_我最喜欢的Java拼图2 + 1 = 4

    拼图游戏 这是我当前最喜欢的Java难题. 您如何获取代码来执行此操作? Integer b = 2; Integer c = 1;System.out.println("b+c : &qu ...

  7. 实验楼项目课学习笔记-jQuery翻转拼图游戏

    2019独角兽企业重金招聘Python工程师标准>>> 项目效果图如下: game/index.html <!DOCTYPE html><html><h ...

  8. python拼图_Python实现, 命令行下的拼图游戏

    需求: 现在要做这样一个拼图游戏, 有一个九宫格, 其中有8个方块, 还有一个空位, 点击其中一个方块, 它会往空位移动... 顺序排列8个方块则游戏通关 结构规划:游戏数据结构 玩家操作 逻辑部分 ...

  9. WPF特效-拼图游戏

    WPF特效-拼图游戏 原文:WPF特效-拼图游戏 此文主要描述我实现碎片化的便捷过程. 步骤1: 选取参考图如下(百度图库搜的): 步骤2: 根据效果图或者模型构建贝塞尔曲线,为了方便查看效果,可以设 ...

最新文章

  1. 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
  2. tensorBoard 初级实现
  3. UIButton 的 imageEdgeInsets 和 titleEdgeInsets
  4. 微信小程序_Bug解决_setData失效
  5. github(入门),不入门找卢姥爷
  6. java高并发(一)导学
  7. Jenkins 持续集成自动化测试配置
  8. 纯CSS实现锚点跳转位置上下偏移的办法
  9. Phaser3让超级玛丽实现轻跳、高跳及加上对应的跳跃声音
  10. [笔记]前端 - 下拉菜单的实现
  11. 支付宝开放新玩法:搜商家可领消费券
  12. 消息称谷歌Pixel系列手机默认禁用美颜功能
  13. Oracle时间函数(转)
  14. Demo(3月28日)
  15. cei()、linspace()、arrange()、full()、eye()、empty()、random()
  16. 程序员新电脑常用软件安装
  17. CTF warmup
  18. c语言汇率转换代码_拜求c语言编写的人民币大小写转换的代码!
  19. 如何改变思维导图的导图结构
  20. ITSS服务项目经理

热门文章

  1. 消附赠配件或助苹果公司节省超65亿美元
  2. Auto Photoshop StableDiffusion - 这是一款可以在 Photoshop 中使用 AI 智能 Automatic1111 进行插画、海报等设计的插件
  3. 食材净化器十大排名,食材净化器怎么选
  4. 阿里双十一为首各巨头入场区块链 下半场真技术角逐开启
  5. SpringCloud分布式事务解决方案汇总收集
  6. ubuntu下最优秀的截屏软件scrot
  7. 入门C语言第一话:分支与循环(下)——你真的知道循环吗?我敢打赌你不太知道。
  8. 更改文件的默认打开方式
  9. 根据正则表达式随机生成满足条件的…
  10. 用python实现一个统计工作天数的系统