不知道爲何分紅9份的時候沒法移動,請高手指教java
分紅36份的時候程序有可能卡住沒反應linux
分紅4份的時候有可能沒法成功恢復原圖windows
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 } }