Here is the problem with java.util.Random
:
Kotlin defines a standard library that is common for all platforms
that Kotlin targets (JVM, JavaScript, Native).
But java.util.Random
is not part of that common subset.
Kotlin-JVM apps must use java.util.Random
.
Where Kotlin-JS apps have to use the function kotlin.js.Math.random
instead.
Below are a few tips for cross-platform kotlin.
You already know how to create Kotlin-JVM apps. So now you need to learn how to create Kotlin-JS apps. Here is a tutorial I made for creating Kotlin-JS apps (it's free):
Once you know how to create Kotlin-JS and Kotlin-JVM apps, the next step is to create a Multiplatform Project. This is a new thing from JetBrains. The idea is that you divide your project into 3 sub-projects. For the blackjack project, you would have:
- bj-common
- bj-js
- bj-jvm.
Here is what goes in each of these:
This contains our Kotlin code that can compile and run correctly on both the JVM and JavaScript platforms. This code will be compiled into both JVM bytecode and JavaScript.
All of our blackjack logic classes (Card, Hand, Deck, Game)
can go here except for the piece of code that computes a random number.
For that, we define only stub, using the keyword expect
:
/**
* return a random number between 1 and 52 inclusive
*/
I added this code to the Deck file:
<project-root>/bj-common/src/main/kotlin/bj/Deck.kt
This contains our Kotlin code that only makes sense for JavaScript. This code will only be compiled into JavaScript.
This is where our JS-friendly version of code to compute a random number goes.
For this we use a the keyword actual
:
actual fun rng52() = floor(Math.random() * 52).toInt()
This is in file:
<project-root>/bj-js/src/main/kotlin/bj/Deck.kt
We also put the JS-friendly Kotlin code to generate our HTML-based UI:
<project-root>/bj-js/src/main/kotlin/bj/Main.kt
Kotlin code that only makes sense for the JVM. This will only be compiled to JVM bytecode.
This is where our JVM-friendly Kotlin code to compute a random number goes:
private val rng = Random()
actual fun rng52() = rng.nextInt(52)
This is in file:
<project-root>/bj-jvm/src/main/kotlin/bj/Deck.kt
We also put our JVM friendly UI here. We don't have much a JVM UI:
<project-root>/bj-jvm/src/main/kotlin/bj/Main.kt
Our unit tests can go here also (junit is a JVM thing):
<project-root>/bj-jvm/src/test/kotlin/bj/GameTest.kt
<project-root>/bj-jvm/src/test/kotlin/bj/DeckTest.kt
<project-root>/bj-jvm/src/test/kotlin/bj/HandTest.kt
<project-root>/bj-jvm/src/test/kotlin/bj/GameTest.kt
I have create a small sample "Multiplatform Project" of the blackjack example and put it on github. This shows you how everything works.
Here are the steps to use this project:
- Clone the project from github (from the command line):
git clone https://github.com/StokeMasterJack/bj-mpp.git
This should create a folder called bj-mpp - Make sure you have a recent version of IntelliJ
- Make sure you have a recent version of Kotlin Plugin:
Tools -> Kotlin -> Configure Kotlin Plugin Updates - Open the project bj-mpp in IntelliJ
- Open the Gradle window:
View -> Tool Windows -> Gradle - From the Gradle window, run the bj-mpp assemble task:
bj-mpp -> Tasks -> Build -> Assemble (double click) - To run the JS impl:
- Locate the file:
<project-root>/bj-js/build/web/index.html
- Right click on that file
- Choose Open in Browser
- Locate the file:
- To run the JVM impl:
- Locate the file:
<project-root>/bj-jvm/src/main/kotlin/bj/Main.kt
- Right click on that file
- Choose Run
- Locate the file:
Here is some more detail on multiplatform projects: https://kotlinlang.org/docs/reference/multiplatform.html
If all you were trying to do was create a version of blackjack that worked the same on Kotlin-JVM and Kotlin-JS, then you could just use List.shuffle(). That uses random numbers internally. But List.shuffle() is available for Kotlin-JVM and Kotlin-JS.