
1package com.cyy.game.pingtu 2 3import javafx.application.Application 4import javafx.beans.property.SimpleObjectProperty 5import javafx.event.EventHandler 6import javafx.geometry.Pos 7import javafx.geometry.Rectangle2D 8import javafx.scene.control.Alert 9import javafx.scene.control.RadioButton 10import javafx.scene.image.Image 11import javafx.scene.image.ImageView 12import javafx.scene.input.MouseEvent 13import javafx.scene.layout.GridPane 14import javafx.scene.layout.VBox 15import javafx.stage.FileChooser 16import tornadofx.* 17import java.io.File 18import java.util.* 19import kotlin.math.sqrt 20 21fun main(args: Array<String>) = Application.launch(PingTuApp::class.java, *args) 22 23class PingTuApp : App(PingTuView::class) 24 25class PingTuView : View("拼图") { 26 var N = intProperty(4) 27 var n = random(N.value - 1) //自定义的函数,产生逆序数为偶数的不重复数组 28 var m = findnum(n) //找出那个不在随机数组里面的数字 29 var imageViews = (1..N.value).map { ImageView() }.toTypedArray() 30 // 大图片路径 31 val imgPath = stringProperty("pingtu/1.png") 32 // 空图片路径 33 val imgBlankPath = "pingtu/2.png" 34 lateinit var rbox: VBox 35 lateinit var gridPane: GridPane 36 lateinit var bigImageView: ImageView 37 lateinit var smallImageView: ImageView 38 val bigImage = SimpleObjectProperty<Image>() 39 val smallImage = SimpleObjectProperty<Image>() 40 // 大图片宽度 41 val imageSize = 300.0 42 // 每个小方格宽度 43 var smallSize = imageSize / sqrt(N.value.toDouble()) 44 45 override val root = borderpane { 46 paddingAll = 10 47 prefHeight = 700.0 48 prefWidth = 1000.0 49 primaryStage.isResizable = false 50 top = hbox(10) { 51 alignment=Pos.CENTER 52 button("选择图片") { 53 action { 54 val imgType = listOf("*.jpg", "*.png", "*.bmp", "*.gif") 55 val efset = arrayOf(FileChooser.ExtensionFilter("$imgType", imgType)) 56 val imgFile = chooseFile("选择图片", efset, FileChooserMode.Single) { 57 // p初始目录为当前项目目录 58 initialDirectory = File(File("").canonicalPath) 59 } 60 if (imgFile.isNotEmpty()) { 61 val imgPath = imgFile.first().toString().replace("\\", "/") 62 bigImage.value = Image(File(imgPath).inputStream()) 63 imageViews=initImageViews1(N.value, imgPath) 64 initView(N.value, imgPath, smallSize,imageViews) 65 } 66 } 67 } 68 69 togglegroup { 70 listOf(4,9, 16, 25).map { v -> 71 radiobutton(v.toString(), this, v) { if (v === 4) isSelected = true } 72 } 73 selectedToggleProperty().addListener { _, _, _ -> 74 N.value = (selectedToggle as RadioButton).text.toInt() 75 smallSize = imageSize / sqrt(N.value.toDouble()) 76 } 77 } 78 79 button("重置") { 80 action { 81 bigImage.value = Image(imgPath.value) 82 83 imageViews =initImageViews(N.value,imgPath.value) 84 initView(N.value, imgPath.value, smallSize,imageViews) 85 } 86 } 87 paddingAll = 10 88 } 89 center = gridpane { 90 alignment=Pos.CENTER 91 92 gridPane = this 93 isGridLinesVisible = true 94 } 95 right = vbox(20) { 96 alignment=Pos.CENTER 97 98 rbox = this 99 //显示空格子的图片 100 imageview(smallImage) { 101 smallImageView = this 102 } 103 //完整的大图 104 imageview(bigImage) { 105 bigImageView = this 106 fitHeight = imageSize 107 fitWidth = imageSize 108 } 109 } 110 } 111 112 inner class Myevent : EventHandler<MouseEvent> { //点击事件的实现 113 override fun handle(arg0: MouseEvent) { 114 val img = arg0.source as ImageView 115 val sx = img.layoutX 116 val sy = img.layoutY 117 val dispx = sx - imageViews[m].layoutX 118 val dispy = sy - imageViews[m].layoutY 119 if (dispx == -smallSize && dispy == 0.0) { //点击的空格左边的格子 120 swapimg(img, imageViews[m]) //交换imageView 121 if (issucc(imageViews)) { //判断是否拼成功 122 val alert = Alert(Alert.AlertType.WARNING, "成功!") 123 alert.show() 124 } 125 } else if (dispx == 0.0 && dispy == -smallSize) { //上面的格子 126 swapimg(img, imageViews[m]) 127 if (issucc(imageViews)) { 128 val alert = Alert(Alert.AlertType.WARNING, "成功!") 129 alert.show() 130 } 131 } else if (dispx == smallSize && dispy == 0.0) { //右边的格子 132 swapimg(img, imageViews[m]) 133 if (issucc(imageViews)) { 134 val alert = Alert(Alert.AlertType.WARNING, "成功!") 135 alert.show() 136 } 137 } else if (dispx == 0.0 && dispy == smallSize) { //下面的格子 138 swapimg(img, imageViews[m]) 139 if (issucc(imageViews)) { 140 val alert = Alert(Alert.AlertType.WARNING, "成功!") 141 alert.show() 142 } 143 } 144 } 145 146 fun swapimg(i1: ImageView, i2: ImageView) { //交换两个imageView的实现 147 val row1 = GridPane.getRowIndex(i1) 148 val colu1 = GridPane.getColumnIndex(i1) 149 val row2 = GridPane.getRowIndex(i2) 150 val colu2 = GridPane.getColumnIndex(i2) 151 152 GridPane.setRowIndex(i1, row2) 153 GridPane.setColumnIndex(i1, colu2) 154 GridPane.setRowIndex(i2, row1) 155 GridPane.setColumnIndex(i2, colu1) 156 } 157 } 158 159 init { 160 imageViews =initImageViews(N.value,imgPath.value) 161 initView(N.value, imgPath.value, smallSize,imageViews) 162 } 163 164 // nn : 9,16,25 165 fun initView(nn: Int, imgPath: String, smallSize: Double,imageViews:Array<ImageView>) { 166 n = random(nn) //自定义的函数,产生逆序数为偶数的不重复数组 167 m = findnum(n) //找出那个不在随机数组里面的数字 168 gridPane.clear() 169 // nn1 =3,4,5 170 val nn1 = sqrt(nn.toDouble()).toInt() 171 var i = 0 172 var k = 0 173 while (i <= nn1 - 1) { 174 var j = 0 175 while (j <= nn1 - 1) { 176 //切割图片 177 imageViews[k].viewport = Rectangle2D(smallSize * j, smallSize * i, smallSize, smallSize) 178 ++j 179 ++k 180 } 181 ++i 182 } 183 184 // nn1-1=2,3,4 185 var t = 0 186 (0 until nn1).forEach { r -> 187 (0 until nn1).forEach { c -> 188 if (t < nn - 1) { 189 gridPane.add(imageViews[n[t]], c, r) 190 } 191 ++t 192 } 193 } 194 195 smallImage.value = imageViews[m].image 196 smallImageView.viewport = imageViews[m].viewport 197 198 imageViews[m].image = Image(imgBlankPath) //2.png为一个透明图,放在空格子中 199 gridPane.add(imageViews[m], nn1 - 1, nn1 - 1) 200 } 201 202 //读取类路径下的图片 203 fun initImageViews(nn: Int, imgPath: String):Array<ImageView>{ 204 return (1..nn).map { 205 imageview(imgPath) { 206 onMouseClicked = Myevent() 207 } 208 }.toTypedArray() 209 } 210 //读取电脑文件系统中图片文件的路径 211 fun initImageViews1(nn: Int, imgPath: String):Array<ImageView>{ 212 return (1..nn).map { 213 imageview(Image(File(imgPath).inputStream())) { 214 onMouseClicked = Myevent() 215 } 216 }.toTypedArray() 217 } 218 219 //判断是否拼成功 220 fun issucc(imageViews: Array<ImageView>): Boolean { 221 val t = imageViews.size 222 imageViews.indices.forEach { i -> 223 if (i != sqrt(t.toDouble()).toInt() * GridPane.getRowIndex(imageViews[i]) + GridPane.getColumnIndex(imageViews[i])) { 224 return false 225 } 226 } 227 return true 228 } 229 230 fun findnum(n: IntArray): Int { 231 (n.indices).forEach { j -> 232 if (j in n) { 233 } else { 234 return j 235 } 236 } 237 238 return -1 239 } 240 241 //生成nn个不重复的逆序数为偶数的数字 242 fun random(nn: Int): IntArray { 243 var ran = IntArray(nn) 244 while (!iso(ran)) { 245 ran = random_num(nn) 246 } 247 return ran 248 } 249 250 //生成nn个不重复数 251 fun random_num(nn: Int): IntArray { 252 val r = IntArray(nn) 253 val random = Random() 254 var i = 0 255 while (i < nn - 1) { 256 r[i] = random.nextInt(nn) 257 for (j in 0 until i) { 258 while (r[i] == r[j]) { 259 i-- 260 break 261 } 262 } 263 ++i 264 } 265 return r 266 } 267 268 //判断逆序数是否为偶数 269 fun iso(num: IntArray): Boolean { 270 var sum = 0 271 val t = num.size 272 for (i in 0..t - 2) { 273 for (j in i..t - 1) { 274 if (num[i] > num[j]) { 275 sum++ 276 } 277 } 278 } 279 return sum % 2 == 0 && sum != 0 280 } 281}