不知道为什么分成9份的时候无法移动,请高手指教
分成36份的时候程序有可能卡住没反应
分成4份的时候有可能无法成功恢复原图
附件运行方式:解压后,双击文件:run.bat
代码语言:txt复制import javafx.application.Application
import javafx.application.Platform
import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Pos
import javafx.geometry.Rectangle2D
import javafx.scene.control.RadioButton
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.input.MouseEvent
import javafx.scene.layout.GridPane
import javafx.scene.layout.VBox
import javafx.stage.FileChooser
import tornadofx.*
import java.io.File
import java.util.*
import kotlin.math.sqrt
fun main(args: Array<String>) = Application.launch(PingTuApp::class.java, *args)
class PingTuApp : App(PingTuView::class)
class PingTuView : View("拼图") {
var N = intProperty(4)
var swapN = intProperty()
var timeUsed = longProperty(0)
var n = random(N.value - 1) //自定义的函数,产生逆序数为偶数的不重复数组
var m = findnum(n) //找出那个不在随机数组里面的数字
var imageViews = (1..N.value).map { ImageView() }.toTypedArray()
// 大图片路径
val imgPath = stringProperty("pingtu/1.png")
// 空图片路径
val imgBlankPath = "pingtu/2.png"
lateinit var rbox: VBox
lateinit var gridPane: GridPane
lateinit var bigImageView: ImageView
lateinit var smallImageView: ImageView
val bigImage = SimpleObjectProperty<Image>(Image(imgPath.value))
val smallImage = SimpleObjectProperty<Image>()
// 大图片宽度
val imageSize = 400.0
// 每个小方格宽度
var smallSize = imageSize / sqrt(N.value.toDouble())
var start = 0L
var timer = Timer()
override val root = borderpane {
paddingAll = 10
prefHeight = 700.0
prefWidth = 1000.0
primaryStage.isResizable = false
top = hbox(10) {
alignment = Pos.CENTER
button("选择图片") {
action {
val imgType = listOf("*.jpg", "*.png", "*.bmp", "*.gif")
val efset = arrayOf(FileChooser.ExtensionFilter("$imgType", imgType))
val imgFile = chooseFile("选择图片", efset, FileChooserMode.Single) {
// p初始目录为当前项目目录
initialDirectory = File(File("").canonicalPath)
}
if (imgFile.isNotEmpty()) {
var imgpath1 = imgFile.first().toString().replace("\", "/")
// linux系统下文件绝对路径以“/”开头,windows系统下文件绝对路径包含":"
if (imgpath1.startsWith("/").or(imgpath1.contains(":"))) {
imgPath.value = "file:$imgpath1"
}
reset()
}
}
}
togglegroup {
listOf(4, 9, 16, 25, 36).map { v ->
radiobutton(v.toString(), this, v) { if (v === 4) isSelected = true }
}
selectedToggleProperty().addListener { _, _, _ ->
N.value = (selectedToggle as RadioButton).text.toInt()
smallSize = imageSize / sqrt(N.value.toDouble())
reset()
}
}
button("重置").action {
reset()
}
label(swapN.stringBinding { "交换次数:$it" })
label(timeUsed.stringBinding { "耗时:$it 秒" })
}
center = gridpane {
alignment = Pos.CENTER
gridPane = this
isGridLinesVisible = true
}
right = vbox(20) {
alignment = Pos.CENTER
rbox = this
run {
//显示空格子的图片
imageview(smallImage) { smallImageView = this }
//完整的大图
imageview(bigImage) {
bigImageView = this
fitHeight = imageSize
fitWidth = imageSize
}
}
}
primaryStage.setOnCloseRequest { timer.cancel() }
}
fun reset() {
start = System.currentTimeMillis()
timeUsed.value=0L
swapN.value = 0
bigImage.value = Image(imgPath.value)
run {
imageViews = initImageViews(N.value, imgPath.value)
}
initView(N.value - 1, smallSize)
}
private val swapListener: (MouseEvent) -> Unit = { arg0 ->
val img = arg0.source as ImageView
val sx = img.layoutX
val sy = img.layoutY
val dispx = sx - imageViews[m].layoutX
val dispy = sy - imageViews[m].layoutY
// println("m:$m, sx:$sx, sy:$sy, dispx:$dispx, dispy:$dispy")
if (dispx == -smallSize && dispy == 0.0) { //点击的空格左边的格子
swapimg(img, imageViews[m]) //交换imageView
swapN.value = 1
if (issucc(imageViews)) { //判断是否拼成功
timer.cancel()
warning("Info", "成功!")
}
} else if (dispx == 0.0 && dispy == -smallSize) { //上面的格子
swapimg(img, imageViews[m])
swapN.value = 1
if (issucc(imageViews)) {
timer.cancel()
warning("Info", "成功!")
}
} else if (dispx == smallSize && dispy == 0.0) { //右边的格子
swapimg(img, imageViews[m])
swapN.value = 1
if (issucc(imageViews)) {
timer.cancel()
warning("Info", "成功!")
}
} else if (dispx == 0.0 && dispy == smallSize) { //下面的格子
swapimg(img, imageViews[m])
swapN.value = 1
if (issucc(imageViews)) {
timer.cancel()
warning("Info", "成功!")
}
}
}
fun swapimg(i1: ImageView, i2: ImageView) { //交换两个imageView的实现
val row1 = GridPane.getRowIndex(i1)
val colu1 = GridPane.getColumnIndex(i1)
val row2 = GridPane.getRowIndex(i2)
val colu2 = GridPane.getColumnIndex(i2)
GridPane.setRowIndex(i1, row2)
GridPane.setColumnIndex(i1, colu2)
GridPane.setRowIndex(i2, row1)
GridPane.setColumnIndex(i2, colu1)
}
val task = object : TimerTask() {
override fun run() {
Platform.runLater {
timeUsed.value = (System.currentTimeMillis() - start)/1000
}
}
}
init {
reset()
timer.schedule(task, 0, 100)
}
// nn : 8,15,24
fun initView(nn: Int, smallSize: Double) {
n = random(nn) //自定义的函数,产生逆序数为偶数的不重复数组
m = findnum(n) //找出那个不在随机数组里面的数字
// println(n.toList())
// println(m)
gridPane.clear()
// nn1 =3-1,4-1,5-1
val nn1 = sqrt(nn 1.0).toInt() - 1
// println("nn1:$nn1")
var k = 0
(0..nn1).forEach { i ->
(0..nn1).forEach { j ->
//切割图片
imageViews[k].viewport = Rectangle2D(smallSize * j, smallSize * i, smallSize, smallSize)
k
}
}
run {
// nn1-1=2,3,4
var t = 0
(0..nn1).forEach { r ->
(0..nn1).forEach { c ->
if (t < nn) {
// println("$t,$c,$r")
gridPane.add(imageViews[n[t]], c, r)
}
t
}
}
}
smallImage.value = imageViews[m].image
smallImageView.viewport = imageViews[m].viewport
imageViews[m].image = Image(imgBlankPath, smallSize, smallSize, false, true) //2.png为一个透明图,放在空格子中
gridPane.add(imageViews[m], nn1, nn1)
}
//读取类路径下的图片
fun initImageViews(nn: Int, imgPath: String): Array<ImageView> {
return (1..nn).map {
imageview(Image(imgPath, imageSize, imageSize, false, true)) {
setOnMouseClicked(swapListener)
}
}.toTypedArray()
}
//判断是否拼成功
fun issucc(imageViews: Array<ImageView>): Boolean {
val t = imageViews.size
val sqrtt = sqrt(t.toDouble()).toInt()
imageViews.indices.forEach { i ->
if (i != sqrtt * GridPane.getRowIndex(imageViews[i]) GridPane.getColumnIndex(imageViews[i])) {
return false
}
}
return true
}
// j=IntArray.size 1, IntArray比imageViews少一个元素
fun findnum(n: IntArray): Int {
(0..n.size).forEach { j ->
if (j in n) {
} else {
return j
}
}
return -1 //如果返回-1,则会造成imageViews数组越界
}
/**
* println(random(8).toList()),output: [3, 6, 5, 4, 7, 1, 2, 0],or [2, 5, 6, 4, 1, 0, 3, 0]
*/
//生成nn个不重复的逆序数为偶数的数字,比imageViews少一个元素,nn=N.value-1
fun random(nn: Int): IntArray {
var ran = IntArray(nn)
while (!iso(ran)) {
ran = random_num(nn)
}
return ran
}
//生成nn个不重复数,比imageViews少一个元素,nn=N.value-1
fun random_num(nn: Int): IntArray {
val r = IntArray(nn)
val random = Random()
var i = 0
while (i < nn) {
r[i] = random.nextInt(nn 1)
for (j in 0 until i) {
while (r[i] == r[j]) {
i--
break
}
}
i
}
return r
}
//判断逆序数是否为偶数
fun iso(num: IntArray): Boolean {
var sum = 0
val t = num.size
(0..t - 2).forEach { i ->
(i until t).forEach { j ->
if (num[i] > num[j]) {
sum
}
}
}
return sum % 2 == 0 && sum != 0
}
}