Java制作智能拼图游戏原理及代码_java

今天突发奇想,想做一个智能拼图游戏来给哄女友。

需要实现这些功能
第一图片自定义
第二宫格自定义,当然我一开始就想的是3*3 4*4 5*5,没有使用3*5这样的宫格。
第三要实现自动拼图的功能,相信大家知道女人耍游戏都不是很厉害,所以这个自动拼图功能得有。

其他什么暂停、排行就不写了!
现在重点问题出来了
要实现自动拼图功能似乎要求有点高哦!计算机有可不能像人一样只能:
先追究下本质

拼图游戏其实就是排列问题:

排列有这么一个定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。
再来一个定义:交换一个排列中的两个数,则排列的奇偶性发生改变。
以上定义都摘自《高等代数》。

拼图排列必须是偶排列。这个在我参考文献中可以找到。
所以我的只能拼图是这样实现的!

后续在写

参考:http://en.wikipedia.org/wiki/Fifteen_puzzle

自动拼图:

首先自动拼图应该有一定的规则,根据我拼图的经验,要完成拼图,不同区域使用的拼图规则是不同的,所以:
我的宫格图分为了4个区域(假如宫格图是n*n个格子)
第一个区域:x坐标范围 0到n-2,y坐标范围 0到n-3
第二个区域:x坐标n-1,y坐标范围 0到n-3
第三个区域:x坐标范围 0到n-3 ,y坐标范围 n-2和n-1
第四个区域:x坐标范围 n-2到n-1 ,y坐标范围 n-2和n-1;即最后四格

每个区域按照各自区域的规则即可完成

Puzzle.java

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Random;

public class Puzzle {
 private long step = 0;
 private int n = 6;// 宫格基数
 private int[][] puzzle;
 private int resetBlock = 0;//
 //空白块位置
 private int whiteBlockX;
 private int whiteBlockY;

 //当前要准备移动的块的坐标即复位块
 private int resetBlockX;
 private int resetBlockY;

 private boolean isPrint=false;

 public Puzzle() {
  init();
 }

 public Puzzle(int n) {
  this.n = n;
  init();
 }

 private void init() {
  puzzle = new int[n][n];
  for (int y = 0; y < n; y++) {
   for (int x = 0; x < n; x++) {
    puzzle[y][x] = x + y * n;
   }
  }
  whiteBlockX = n-1;
  whiteBlockY = n-1;
  int times = 100;// 打乱次数,必须是偶数
  Random random = new Random();
  while (times > 0) {
   int x0 = random.nextInt(n);
   int y0 = random.nextInt(n);
   int x1 = random.nextInt(n);
   int y1 = random.nextInt(n);
   if (x0 != x1 && y0!=y1) {// 保证是偶排序
    if((x0==n-1&&y0==n-1)||(x1==n-1&&y1==n-1)){//最后一个不调换
     continue;
    }
    times--;
    int t = puzzle[x0][y0];
    puzzle[x0][y0] = puzzle[x1][y1];
    puzzle[x1][y1] = t;
   }
  }
//  int[][] p = {{22,9 ,1 ,5 ,0 ,25 },{
//    33,23,20,26,18,21},{
//    6 ,16,17,10,34,31},{
//    19,28,32,7 ,3 ,2},{
//    11,4 ,12,14,27,24},{
//    15,29,30,8 ,13,35}};
//  puzzle = p;
 }

 public void sort(){
  for (int y = 0; y < n; y++) {
   for (int x = 0; x < n; x++) {
    if (x == n - 1 && y == n - 1) {// 最后一个为空白,
    } else {
     reset(x, y);
    }
   }
  }
 }
 //把块复位移动目标位置
 private void reset(int targetX, int targetY) {
  // 找到复位块当前的位置
  initResetBlock(targetX, targetY);
  /*
   * 复位顺序是从左到右,从上到下
   * 移动方式 先上移动,再左移动
   * 当前复位块,它要复位的位置可分为 四种情况
   * 1、不在最右边一行也不是最下面两行
   * 2、最右边一行 x=n-1,但不是下面两行;
   * 3、最下面两行 y=n-2,但不是最右边一行;
   * 4、即使最右边的一行也是最下面两行
   */
  if(targetX < n-1 && targetY < n-2){
   if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
    return;//退出递归
   }
   resetBlockToTarget(targetX, targetY);
  }else if(targetX==n-1 && targetY < n-2){//第二种情况
   if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
    return;//退出递归
   }
   reset2(targetX, targetY);
  }else if(targetX < n-2 && targetY == n-2){
//   isPrint=true;
   reset3(targetX);
   return;
  }else{
   initResetBlock(n-2, n-2);
   resetBlockToTarget(n-2, n-2);
   if(whiteBlockX<n-1){
    whiteBlockRight();
   }
   if(whiteBlockY<n-1){
    whiteBlockDown();
   }
   if(whiteBlockX==n-1&&whiteBlockY==n-1){
    return;
   }
  }
  reset(targetX, targetY);//递归
 }
 private void initResetBlock(int targetX,int targetY){
  resetBlock = targetX + targetY * n;
  for (int y = 0; y < n; y++) {
   for (int x = 0; x < n; x++) {
    if (puzzle[y][x] == resetBlock) {// x,y就是复位块的位置
     resetBlockX = x;
     resetBlockY = y;
     break;
    }
   }
  }
 }
 private void reset3(int targetX){
//  if(targetX>=2){
//  }
  initResetBlock(targetX, n-1);
  resetBlockToTarget(targetX, n-2);

  initResetBlock(targetX, n-2);
  resetBlockToTarget(targetX+1, n-2);
  l:
  while (!(whiteBlockX==targetX && whiteBlockY==n-1)) {
   if(whiteBlockY<n-1){
    whiteBlockDown();
    continue l;
   }
   if(whiteBlockX>targetX){
    whiteBlockLeft();
    continue l;
   }
   break;
  }
  whiteBlockUp();
  swapWhiteBlockAndCurrentBlock();

  if(puzzle[n-2][targetX]!=resetBlock||puzzle[n-1][targetX]!=(resetBlock+n)){//没有复位成功
//   isPrint=true;
   swapWhiteBlockAndCurrentBlock();
   reset3_0();
   reset3(targetX);
  }
 }
 private void reset3_0(){
  if(resetBlockX<n-1){
   whiteBlockDown();
   whiteBlockRight();
   whiteBlockRight();
   whiteBlockUp();
   swapWhiteBlockAndCurrentBlock();
   reset3_0();
   return;
  }
  return;
 }

 private void reset2_3(){
  if(whiteBlockX==resetBlockX && whiteBlockY==resetBlockY+1){
   return;//满足条件,退出递归
  }
  //白块可能在复位块的:左方、左下、下方
  if(whiteBlockY==resetBlockY){//左方
   whiteBlockDown();
  }else if(whiteBlockX < resetBlockX){//左下
   whiteBlockRight();
  }else {
   whiteBlockUp();
  }
  reset2_3();//递归
 }

 private void reset2_2(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//2、把复位块移到目标位置正下方
   return;//退出递归
  }

  //复位块可能位置,目标位置左方、正下方、左下方
  if(resetBlockX==targetX){//正下方 上移
   resetBlockUp(targetX, targetY);
  }else{//左方或左下方;先右移再上移
   resetBlockRight(targetX, targetY);
  }
  reset2_2(targetX, targetY);//递归
 }

 private void reset2(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
   return;//退出递归
  }
  /* 1、如果白块正好占了目标位置:如果复位块正好在下方,交换及完成复位,如果下方不是复位块,把白块移开目标位置
   * 2、把复位块移到目标位置正下方
   * 3、把白块移动复位块下方
   * 4、按照规定的步骤复位
   */
  //第一步
  if(whiteBlockX==targetX&& whiteBlockY==targetY){
   if(whiteBlockX==resetBlockX&&whiteBlockY==resetBlockY+1){//复位块在下方
    swapWhiteBlockAndCurrentBlock();
    return;
   }else{
    whiteBlockDown();
   }
  }
  //第二步 把复位块移到目标位置正下方
  reset2_2(targetX, targetY+1);
  //第三步 把白块移动复位块下方
  reset2_3();
  //第四步 按照规定的步骤复位
  swapWhiteBlockAndCurrentBlock();
  whiteBlockLeft();
  whiteBlockUp();
  whiteBlockRight();
  whiteBlockDown();
  whiteBlockLeft();
  whiteBlockUp();
  whiteBlockRight();
  whiteBlockDown();
  swapWhiteBlockAndCurrentBlock();
  whiteBlockLeft();
  whiteBlockUp();
  whiteBlockUp();
  whiteBlockRight();
  swapWhiteBlockAndCurrentBlock();
 }

 private void resetBlockToTarget(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
   return;//退出递归
  }

  if(resetBlockY==targetY){//正左
   resetBlockLeft(targetX, targetY);
  }else{//左下,下,右下
   if(resetBlockX>=targetX){//右下||下;上移
    if(resetBlockX==n-1){//复位块在最右边,先左移;方便上移时统一的采用白块逆时针方式
     resetBlockLeft(targetX, targetY);
    }else{
     resetBlockUp(targetX, targetY);
    }
   }else{//左下;右移
    resetBlockRight(targetX, targetY);
   }
  }
  resetBlockToTarget(targetX, targetY);//递归
 }

 private void resetBlockRight(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
   return;//退出递归
  }
  if(resetBlockX==n-1){//复位块在最右边了,无法右移,直接退出
   return;
  }
//  System.out.println("resetBlockRight");
  if(whiteBlockY<resetBlockY){//上方
   if(whiteBlockY<resetBlockY-1){//上方多行
    whiteBlockDown();
   }else{//上方一行
    if(whiteBlockX<resetBlockX+1){//左上和正上
     whiteBlockRight();
    }else{//右上
     whiteBlockDown();
    }
   }
  }else if(whiteBlockY==resetBlockY){//同一行
   if(whiteBlockX<resetBlockX){//左方
    if(whiteBlockY==n-1){//到底了,只能往上
     whiteBlockUp();
    }else{
     whiteBlockDown();
    }
   }else{//右方
    if(whiteBlockX==resetBlockX+1){
     swapWhiteBlockAndCurrentBlock();
     return;//退出递归
    }else{
     whiteBlockLeft();
    }
   }
  }else{//下方
   if(whiteBlockX <= resetBlockX){//左下、下
    whiteBlockRight();
   }else{//右下
    whiteBlockUp();
   }
  }
  resetBlockRight(targetX, targetY);//递归
 }

 private void resetBlockLeft(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
   return;//退出递归
  }
  if(resetBlockX==0){//在左边边界 复位块无法左移,直接退出递归
   return;
  }
//  System.out.println("resetBlockLeft");
  if(whiteBlockY<resetBlockY){//上方
   if(whiteBlockY<resetBlockY-1){//上方多行
    whiteBlockDown();
   }else{//上方一行
    if(whiteBlockX==resetBlockX){//上方
     if(whiteBlockX==n-1){//最右边,白块无法右移,只能左移
      whiteBlockLeft();
     }else{
      if(resetBlockY==n-1){//复位块在最低端,白块不能顺时针移动
       whiteBlockLeft();
      }else{
       whiteBlockRight();
      }
     }
    }else if(whiteBlockX>resetBlockX){//右上方
     if(resetBlockY==n-1){//复位块在最低端,白块不能顺时针移动
      whiteBlockLeft();
     }else{
      whiteBlockDown();
     }
    }else{//左上方
     whiteBlockDown();
    }
   }
  }else if(whiteBlockY==resetBlockY){//左方、右方
   if(whiteBlockX<resetBlockX){//左方
    if(whiteBlockX==resetBlockX-1){//左边一格
     swapWhiteBlockAndCurrentBlock();//退出递归
     return;
    }else{
     whiteBlockRight();
    }
   }else{//右方
    if(whiteBlockY==n-1){//到底了,不能下移。只能上移
     whiteBlockUp();
    }else{
     whiteBlockDown();
    }
   }
  }else{//左下、下方、右下
   if(whiteBlockX<resetBlockX){//左下
    if(whiteBlockX==resetBlockX-1){
     whiteBlockUp();
    }else{
     whiteBlockRight();
    }
   }else{//下方、右下
    whiteBlockLeft();
   }
  }
  resetBlockLeft(targetX, targetY);//递归
 }

 private void resetBlockUp(int targetX, int targetY){
  if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动
   return;//退出递归
  }
  if(resetBlockY==0){//复位块到顶了,无法上移
   return;
  }
//  System.out.println("resetBlockUp");
  if (whiteBlockY < resetBlockY) {//上方
   if(whiteBlockY < resetBlockY - 1){//上方多行
    whiteBlockDown();
   }else{//上方一行
    if(whiteBlockX == resetBlockX){//白块和复位块在同一列(竖列) 白块和复位块直接交换位置
     swapWhiteBlockAndCurrentBlock();//退出递归
     return;
    }else{
     if(whiteBlockX<resetBlockX){//白块在复位块的左边;白块右移
      whiteBlockRight();
     }else{//白块在复位块的右边;白块左移
      whiteBlockLeft();
     }
    }
   }
  } else if (whiteBlockY == resetBlockY) {//白块和复位块同一行;白块上移
   if(whiteBlockX<resetBlockX){//正左
    if(whiteBlockX<resetBlockX-1){//正左多格
     whiteBlockRight();
    }else{//正左一格
     if(whiteBlockY==n-1){//到底了
      whiteBlockUp();
     }else {
      if(resetBlockX==n-1){//复位块在最右边,无法逆时针,只有顺指针移动白块
       whiteBlockUp();
      }else{
       whiteBlockDown();
      }
     }
    }
   }else{//正右
    whiteBlockUp();
   }
  }else{//白块在复位块下方,白块需要饶过复位块上移,白块逆时针绕到白块上面
   //三种情况:左下,下,右下
   if(whiteBlockX<=resetBlockX){//左下,下;白块右移
    if(resetBlockX==n-1){//复位块在最右边,无法逆时针,只有顺指针移动白块
     if(whiteBlockX==resetBlockX){//正下方
      whiteBlockLeft();
     }else{//左下方
      whiteBlockUp();
     }
    }else{
     whiteBlockRight();
    }
   }else{//右下;白块上移
    whiteBlockUp();
   }
  }
  resetBlockUp(targetX, targetY);//递归
 }

 //白块和复位块交换位置
 private void swapWhiteBlockAndCurrentBlock(){
  step++;
  int tempX = whiteBlockX,tempY = whiteBlockY;
  int temp = puzzle[whiteBlockY][whiteBlockX];
  puzzle[whiteBlockY][whiteBlockX] = puzzle[resetBlockY][resetBlockX];
  puzzle[resetBlockY][resetBlockX] = temp;
  whiteBlockX = resetBlockX;
  whiteBlockY = resetBlockY;
  resetBlockX = tempX;
  resetBlockY = tempY;
  println("swap");
 }

 private void whiteBlockDown(){
  step++;
  int temp = puzzle[whiteBlockY][whiteBlockX];
  puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY+1][whiteBlockX];
  puzzle[whiteBlockY+1][whiteBlockX] = temp;
  whiteBlockY++;
  println("↓");
 }
 private void whiteBlockUp(){
  step++;
  int temp = puzzle[whiteBlockY][whiteBlockX];
  puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY-1][whiteBlockX];
  puzzle[whiteBlockY-1][whiteBlockX] = temp;
  whiteBlockY--;
  println("↑");
 }

 private void whiteBlockLeft(){
  step++;
  int temp = puzzle[whiteBlockY][whiteBlockX];
  puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX-1];
  puzzle[whiteBlockY][whiteBlockX-1] = temp;
  whiteBlockX--;
  println("←");
 }
 private void whiteBlockRight(){
  step++;
  int temp = puzzle[whiteBlockY][whiteBlockX];
  puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX+1];
  puzzle[whiteBlockY][whiteBlockX+1] = temp;
  whiteBlockX++;
  println("→");
 }

 @Override
 public String toString() {
  StringBuilder sb = new StringBuilder();
  sb.append("resetBlock=("+resetBlock+","+resetBlockX+","+resetBlockY+")\n");
  if(puzzle!=null){
   int len = String.valueOf(n*2-1).length();
   for (int y = 0; y < n; y++) {
    for (int x = 0; x < n; x++) {
     if(x>0){
      sb.append(",");
     }
     sb.append(_str(String.valueOf(puzzle[y][x]), len));
    }
    sb.append("\n");
   }
   sb.append("---------------------------------------");
  }else{
   sb.append("puzzle is null");
  }
  return sb.toString();
 }
 private String _str(String str,int len){
  str=str==null?"":str;
  if(str.length()<len){
   return _str(str+" ", len);
  }
  return str;
 }

 private void println(String str){
  if(isPrint){
   System.out.println(str);
   System.out.println(this);
  }
 }

 public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
//  System.setOut(new PrintStream("e:/puzzle.txt","UTF-8"));
  Puzzle p = new Puzzle();
  System.out.println(p);
  try {
   p.sort();
  } catch (Exception e) {
   e.printStackTrace();
   System.out.println("Exception:");
  }finally{
   System.out.println(p);
  }
 }
}

以上所述就是本文的全部内容了,希望大家能够喜欢。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
智能拼图
java拼图游戏原理、java拼图游戏源代码、拼图游戏java代码、java代码生成器原理、java代码混淆原理,以便于您获取更多的相关知识。

时间: 2024-12-21 08:32:44

Java制作智能拼图游戏原理及代码_java的相关文章

用java生成html文件实现原理及代码_java

原理跟用java生成jsp的servlet差不多.我们可以用printStream来向html文件里输出数据. 先创建一个StringBuilder对象,通过append方法来为其添加html语句.如下面例子所示: 复制代码 代码如下: StringBuilder sb = new StringBuilder(); Properties fileProperties = getProperties("file"); Properties sqlProperties = getPrope

用flash制作简单拼图游戏

可能有很多玩Flash的朋友都曾和我一样想自己动手制作一个拼图游戏,但是苦于不知道实现的方法或不了解ActionScript(以下简称AS)而心存遗憾.别急,今天盗匪就告诉你如何利用Flash常用的AS制作一个简单的拼图游戏,我所说的简单可不是将图片简单的拼凑到一起的那种简单拼图啊. 做好的成品如下:大家可以用鼠标将上面的图像碎片拖到下面的方框内的合适位置,为方便大家找位,游戏给出了有一定透明度的原图作为参考.大家可以发现这个游戏还设计了一个"吸附"功能,能够让你将拼图片轻松地整齐排列

i ealth 智能血压计-iHealth 智能血压计设计原理和代码

问题描述 iHealth 智能血压计设计原理和代码 求助:之前小米有一款app叫做"爱健康"app(iHealth),它在红米上可以变成智能血 压计,来测量父母亲人的血压,直接反应在app上,求其设计原理和实现代码(学习).http://www.mi.com/ihealth/ 解决方案 无非就是一个电子血压计,所不同的是,它可以以蓝牙.网络.usb等某种形式把测量结果发送给手机,手机做一个应用显示出来.

java selenium 操作弹出窗口示例代码_java

selenium 中如何处理弹出窗口 阅读目录 原理 测试页面的HTML Java 代码 原理 在代码里, 通过         Set<String> allWindowsId = driver.getWindowHandles(); 来获取到所有弹出浏览器的句柄,   然后遍历,  使用swithcto.window(newwindow_handle)方法. 就可以定位到新的窗口 测试页面的HTML <html> <head> <title>常见web

Java HtmlEmail 邮件发送的简单实现代码_java

Java 项目中常常回遇到发送邮件 Java 发送邮件有几种,今天先给大家介绍用 HtmlEmail 来发送邮件,我这里是用 Maven 来搭建的 HtmlEmail 可以抄带HTML 首先 需要导入jar 包 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-email</artifactId> <version>1.4</versio

Java Web 简单的分页显示实例代码_java

本文通过两个方法:(1)计算总的页数. (2)查询指定页数据,实现简单的分页效果. 思路:首先得在 DAO 对象中提供分页查询的方法,在控制层调用该方法查到指定页的数据,在表示层通过 EL 表达式和 JSTL 将该页数据显示出来. 先给大家展示下效果图: 题外话:该分页显示是用 "表示层-控制层-DAO层-数据库"的设计思想实现的,有什么需要改进的地方大家提出来,共同学习进步.废话不多说了,开始进入主题,详细步骤如下所示: 1.DAO层-数据库 JDBCUtils 类用于打开和关闭数据

Java web的读取Excel简单实例代码_java

目录结构: Data.xls数据:   后台页面: public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //System.out.println(this.getServletContext().getRealPath ("/")); try{ Workbook wb = Workbook.getWorkboo

Java使用正则表达式(regex)匹配中文实例代码_java

只能输入中文 /** * 22.验证汉字 * 表达式 ^[\u4e00-\u9fa5]{0,}$ * 描述 只能汉字 * 匹配的例子 清清月儿 */ @Test public void a1() { Scanner sc = new Scanner(System.in); String input = sc.nextLine(); String regex = "^[\\u4e00-\\u9fa5]*$"; Matcher m = Pattern.compile(regex).matc

Java解压zip文件的关键代码_java

废话不多说了,给大家贴关键代码了,具体代码如下所示: import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import o