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);
  }
 }
}

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

(0)

相关推荐

  • java实现的简单猜数字游戏代码

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 具体代码如下: 复制代码 代码如下: import java.util.InputMismatchException; import java.util.Scanner; public class Main {         public static void main(String[] args) {                 // 产生一个随机数                 int number = (in

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

  • Java编写掷骰子游戏

    废话不多说了,直接奔主题. **多线程&&观察者模式 题目要求:<掷骰子>窗体小游戏,在该游戏中,玩家初始拥有1000的金钱,每次输入押大还是押小,以及下注金额,随机3个骰子的点数,如果3个骰子的总点数小于等于9,则开小,否则开大,然后判断玩家是否押对,如果未押对则扣除下注金额,如果押对则奖励和玩家下注金额相同的金钱. 分析:这个题目要求灵活运用多线程的相关知识,达到点击开始按钮时,有3个线程启动,分别控制3颗骰子的转动,在3颗骰子全部转完以后,回到主线程计算游戏结果. //个

  • java基于swing实现的五子棋游戏代码

    本文实例讲述了java基于swing实现的五子棋游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Main extends JFrame implements ActionListener{         private static final long serialVersionUID = 1L;      

  • java实现五子棋小游戏

    java实现五子棋小游戏 package Gomoku; import java.awt.Toolkit; import javax.swing.JFrame; public class GomokuFrame extends JFrame { //定义一个操作面板 OperatorPane op=null; public GomokuFrame() { //设置名称 this.setTitle("五子棋"); //设置窗口大小 this.setSize(510,510); //设置窗

  • java编写贪吃蛇小游戏

    废话不多说,直接奉上代码: Frame.java package snake; import java.awt.Graphics; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import

  • Java基于swing实现的弹球游戏代码

    本文实例讲述了Java基于swing实现的弹球游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: package Game; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Random;

  • java使用OGEngine开发2048

    最近有一款2048的游戏非常火,本文将来介绍一下使用OGEngine游戏引擎开发游戏2048. OGEngine引擎是开源的,我们很容易找到,搭建起来也很方便,我们只需在Android工程下添加OGEngine的jar包或者直接引用源码就可以了. 源码下载:http://www.ogengine.com/download/resources.jsp private void initView() { // 游戏背景 AnimatedSprite game_bg = new AnimatedSpr

  • java版实现2048游戏功能

    本文实例为大家分享了java实现2048游戏功能的具体代码,供大家参考,具体内容如下 功能要求:2048的基本界面,能够实现2048的游戏功能. 总思路:两个类:Game和GameListener. Game负责界面的实现和paint方法的重写 GameListener负责实现键盘和鼠标事件的处理.移动方法,相加方法,输赢判断和随机数的出现都要在键盘监听的方法中实现. 实现分析:要实现2048游戏,首先需要考虑2048都有些什么? 界面实现: 2048的游戏界面很简单,就是一些方格和数字.要实现

  • Java完美实现2048小游戏

    完美地模仿了2048游戏,是根据网友的一个2048改的. Block.java import javax.swing.*; import java.awt.*; public class Block extends JLabel { private int value; public Block() { value = 0;//初始化值为0 setFont(new Font("font", Font.PLAIN, 40));//设定字体 setBackground(Color.gray

随机推荐