article banner

Exercise: Migrating a Kotlin/JVM project to KMP

Clone the following project:

This is a Kotlin/JVM project that implements a logic that can generate and solve sudoku puzzles. However, you need to use these capabilities in a React project written in TypeScript. Transform your project to a Kotlin Multiplatform project and generate a JavaScript library named "sudoku-generator" from it. Then, use it in your React project.

In the web-client folder, you can find a React project. It is already set to use the generated library, assuming it is going to be named "sudoku-generator" and located in the default path "build/productionLibrary". You can run it using the npm start command. It is a simple project that displays an unsolved and a solved version of a sudoku. To make it work, you need to transform the Kotlin parts to Kotlin multiplatform and define a Kotlin/JS wrapper over the sudoku generator that is exported to JavaScript and exposes objects that can be used in TypeScript.

The exported class should be named SudokuGenerator; it should have no package, an empty constructor, and a single generateSudoku method that takes no arguments and returns an object Sudoku with a random sudoku and its solution. The Sudoku object should have two properties: sudoku and solved. Both should be of type Array<Array<Int?>>. The sudoku should be generated using SudokuGenerator and SudokuSolver. Both these classes can be created using the SudokuGenerator() and SudokuSolver() constructors. The sudoku should be generated using the generate method from the SudokuGenerator class, with the solver from the SudokuSolver class used as an argument.

To transform SudokuState to Array<Array<Int?>>, you can use the following function:

fun SudokuState.toJs(): Array<Array<Int?>> = List(9) { row -> List(9) { col -> val cell = this.cells[SudokuState.Position(row, col)] when (cell) { is SudokuState.CellState.Filled -> cell.value is SudokuState.CellState.Empty, null -> null } }.toTypedArray() }.toTypedArray()

Hints:

  • IntelliJ often has trouble with recognizing a change from Kotlin/JVM to Kotlin Multiplatform. If you encounter this problem, try to invalidate the cache and restart IntelliJ. Also, give it a moment.
  • To set the name of the generated module, you need to set the moduleName property in the js(IR) block.
  • If you have problems with generating TypeScript definitions, try to call generateTypeScriptDefinitions in the js(IR) block.
  • Generate the library using the Gradle

jsBrowserProductionLibraryDistribution task, then remember to use npm install in web-client.

Once you are done with the exercise, you can check your solution here.