From 7dee18a1ca79e8fa41f0c58d49b7dba4a4419106 Mon Sep 17 00:00:00 2001
From: Matej Focko <me@mfocko.xyz>
Date: Tue, 26 Nov 2024 00:02:35 +0100
Subject: [PATCH] =?UTF-8?q?kt:=20add=20=C2=AB773.=20Sliding=20Puzzle=C2=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

URL:	https://leetcode.com/problems/sliding-puzzle/
Signed-off-by: Matej Focko <me@mfocko.xyz>
---
 kt/sliding-puzzle.kt | 63 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)
 create mode 100644 kt/sliding-puzzle.kt

diff --git a/kt/sliding-puzzle.kt b/kt/sliding-puzzle.kt
new file mode 100644
index 0000000..782e9da
--- /dev/null
+++ b/kt/sliding-puzzle.kt
@@ -0,0 +1,63 @@
+class Solution {
+    companion object {
+        private val DIRECTIONS: List<List<Int>> =
+            listOf(
+                listOf(1, 3),
+                listOf(0, 2, 4),
+                listOf(1, 5),
+                listOf(0, 4),
+                listOf(1, 3, 5),
+                listOf(2, 4),
+            )
+        private val TARGET: String = "123450"
+
+        private fun swap(
+            board: String,
+            i: Int,
+            j: Int,
+        ): String {
+            val cells = board.toMutableList()
+
+            val tmp = cells[i]
+            cells[i] = cells[j]
+            cells[j] = tmp
+
+            return cells.joinToString(separator = "")
+        }
+    }
+
+    fun slidingPuzzle(board: Array<IntArray>): Int {
+        val startState =
+            board.flatMap { it.asSequence() }.joinToString(separator = "") {
+                it.toString()
+            }
+
+        val seen = mutableSetOf<String>(startState)
+        val queue = ArrayDeque<String>(listOf(startState))
+
+        var moves = 0
+        while (queue.isNotEmpty()) {
+            for (i in 1..queue.size) {
+                val current = queue.removeFirst()
+                if (current == TARGET) {
+                    return moves
+                }
+
+                val zeroIdx = current.indexOf('0')
+                DIRECTIONS[zeroIdx].forEach {
+                    val next = swap(current, zeroIdx, it)
+                    if (seen.contains(next)) {
+                        return@forEach
+                    }
+
+                    seen.add(next)
+                    queue.addLast(next)
+                }
+            }
+
+            moves += 1
+        }
+
+        return -1
+    }
+}