在看了Java语言程序设计(基础篇)之后,萌生了想用javaFX来编个小游戏的想法,想了想就做打算做个拼图游戏,并实现自动拼图。
下面按我完成这个游戏的过程来说明,下面有些实现没有把全部代码贴上,贴太多我自己看着都难受,所以想了解细节的直接去看源码就好了,源码链接在文章末尾。
打乱图片
以3X3的拼图为例,将整张图片切割为9个大小相同的图块,将其视为一组数。
然后采用随机数,生成一组不含有重复数字的排列。如下图:
这里需要注意的是,并非是任意打乱的排列都是可以恢复的,这其中的限制是,该排列的逆序数必须为偶数,即偶排列,该拼图才可解。具体解释可以参照以下两篇博客:
如果有线性代数的基础的话,应该知道:
- 在n元标准排列中,偶排列和奇排列各占一半。
- 在n元排列中,任意两个元素对换,排列奇偶性改变。
下面为生成不含重复数字的偶排列的代码:
RandomArray.java
// 生成num个不重复的逆序数为偶数的排列
public static int[] getEvenPermutation(int num) {
int[] ran = generateRandomArray(num);
if (getNumberOfInversions(ran) % 2 != 0) {
int temp = ran[0]; //如果不是偶排列则交换下标为0和1的数,当然其他也可以
ran[0] = ran[1];
ran[1] = temp;
}
return ran;
}
// 生成num个不重复数
public static int[] generateRandomArray(int num) {
int[] array = new int[num];
Random random = new Random();
for (int i = 0; i < array.length -1; i++) {
array[i] = random.nextInt(num -1);
for (int j = 0; j < i; j++) {
if (array[i] == array[j]) {
i--;
break;
}
}
} //这里把最大的数放在了排列的末尾,一开始是为了美观,后来发现这样好像可以降低搜索难度—_—!
array[array.length - 1] = num - 1; //这句删掉,再把上面for循环条件判断语句的减1去掉就可以完全随机
return array;
}
// 求逆序数
public static int getNumberOfInversions(int[] array) {
int sum = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] > array[j]) {
sum++;
}
}
}
return sum;
}
重组图片
得到随机排列之后,根据排列在图片对应位置将图块切割下来,再按顺序放到矩阵中即可。
这里用到一个Cell类,用于存储图片和各个坐标信息,基本上整个游戏都有用到这个类
Cell.java
public class Cell {
private int x; //在nxn的矩阵中的x坐标
private int y; //在nxn的矩阵中的y坐标
private int validIndex; //图块的应该在的正确位置
private int currentIndex; //图块的当前位置
private ImageView ImageView; //图块的图像
public Cell(int x, int y, ImageView initialImageView,int validIndex,int currentIndex) {
this.x = x;
this.y = y;
this.ImageView = initialImageView;
this.validIndex=validIndex;
this.currentIndex=cur