I'm going through Googles Kotlin Compose tutorials. One of the tasks is to build a game where you unscramble words. After completing it, I tried to improve the game on my own, and just can't figure out how to add a countdown timer to it. I want the program to skip a word when time runs out.
I'm a programming noob, it's not quite clear to me yet how classes and objects work and how they differ from functions.
The code for the timer at the moment:
object Timer: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
TODO("Not yet implemented")
}
override fun onFinish() {
skipWord() // <<----------- **Unresolved reference: skipWord**
}
}
Elsewhere in my code I have:
class GameViewModel : ViewModel() {
//....
fun skipWord() { // <<---------------- Function that skips to the next word
updateGameState(_uiState.value.score)
updateUserGuess("")
}
//.....
private fun pickRandomWordAndShuffle(): String {
// Continue picking up a new random word until you get one that hasn't been used before
if (currentLanguage == "English") {
currentWord = engWords.random()
} else {
currentWord = finWords.random()
}
setPointAmount()
Timer.start() // <<---------------Start a new countdown for a new word.
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}
}
Also, a separate problem: the .random() always uses the same seed and picks the same words to unscramble.
Change
object Timer: CountDownTimer(60000, 1000) {
...
to
val timer = object: CountDownTimer(60000, 1000) {
...
and put in into your GameViewModel class.
To solve random issue provide some seed to Random object, like:
var myRandom = Random(System.currentTimeMillis())
and then
currentWord = engWords[myRandon.nextInt(engwords.lastIndex)]
Related
I'm actually new at Kotlin, and I encounter the following problematic:
I have a class holding an ArrayList of EnsembleVerifier class.
This other class is instantiated with an ArrayList of Square.
When I tried to get this ArrayList, I discovered that this one has no element inside.
Is there any absurdity/misconception in my code? Is it something else? Thank you in advance! :)
GridVerifiers.kt
class GridVerifiers(private val grid: Grid) {
private var verifiers: ArrayList<EnsembleVerifier> = ArrayList()
init {
generateVerifiers()
}
private fun generateVerifiers() {
generateLineVerifiers()
generateColumnVerifiers()
generateSubGridVerifiers()
}
private fun generateLineVerifiers() {
val line: ArrayList<Square> = ArrayList()
for (lineIndex in grid.gridState.indices) {
for (columnIndex in grid.gridState.indices)
line.add(grid.gridState[lineIndex][columnIndex])
println(line.size) // returns 9
verifiers.add(EnsembleVerifier(line))
line.clear()
}
}
...
EnsembleVerifier.kt
class EnsembleVerifier(private val squares: ArrayList<Square>) {
...
fun isValid(): Boolean {
val buffer: ArrayList<Int> = ArrayList()
println(squares.size) // returns 0!
for (square in squares) {
if (square.value in buffer) return false
buffer.add(square.value)
}
return true
}
In java most of the time you are working with references to objects. This means in your case, that your are always working with the same array line. Therefore, when you call line.clear you are cleaning the array that that reference is pointing at, and that's causing your issue with empty arrays.
You need to generate new objects every time instead of cleaning the list.
private fun generateLineVerifiers() {
for (lineIndex in grid.gridState.indices) {
val line: ArrayList<Square> = ArrayList()
for (columnIndex in grid.gridState.indices)
line.add(grid.gridState[lineIndex][columnIndex])
println(line.size) // returns 9
verifiers.add(EnsembleVerifier(line))
}
}
wondered if anyone could assist, I'm trying to understand the correct way to access a collection in Kotlin with two threads.
The code below simulates a problem I'm having in a live system. One thread iterates over the collection but another thread can remove elements in that array.
I have tried adding #synchronized to the collections getter but that still gives me a concurrentmodification exception.
Can anyone let me know what the correct way of doing this would be?
class ListTest() {
val myList = mutableListOf<String>()
#Synchronized
get() = field
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.myList.remove("stuff: 54")
}
launch {
listTest.myList.forEach { println(it) }
}
}
You are only synchronizing the getter and setter, so when you start using the reference you get to the list, it is already unlocked.
Kotlin has the Mutex class available for locking manipulation of a shared mutable object. Mutex is nicer than Java's synchronized because it suspends instead of blocking the coroutine thread.
Your example would be poor design in the real world because your class publicly exposes a mutable list. But going along with making it at least safe to modify the list:
class ListTest() {
private val myListMutex = Mutex()
private val myList = mutableListOf<String>()
init {
repeat(10000) {
myList.add("stuff: $it")
}
}
suspend fun modifyMyList(block: MutableList<String>.() -> Unit) {
myListMutex.withLock { myList.block() }
}
}
fun main() = runBlocking<Unit> {
val listTest = ListTest()
launch(Dispatchers.Default) {
delay(1L)
listTest.modifyMyList { it.remove("stuff: 54") }
}
launch {
listTest.modifyMyList { it.forEach { println(it) } }
}
}
If you are not working with coroutines, instead of a Mutex(), you can use an Any and instead of withLock use synchronized (myListLock) {} just like you would in Java to prevent code from within the synchronized blocks from running at the same time.
If you want to lock a collection, or any object for concurrent access, you can use the almost same construct as java's synchronized keyword.
So while accessing such an object you would do
fun someFun() {
synchronized(yourCollection) {
}
}
You can also use synchronizedCollection method from java's Collections class, but this only makes single method access thread safe, if you have to iterate over the collection, you will still have to manually handle the synchronization.
I'm learning kotlin in intelij Idea, and I have to make presentation about interfaces. One subject is callback, where can I find information about it? or can you tell me simply, veery simply, what's call back?
fun main() {
val myphone = Myphone()
myphone.phoneOn()
myphone.onClick()
myphone.onTouch()
myphone.openApp()
myphone.closeApp()
}
interface Application {
var AppName: String
fun openApp()
fun closeApp() {
println("$AppName App is closed!")
}
}
interface Button {
var helloMessage: String
fun phoneOn()
fun onClick()
fun onTouch() {
println("The screen was touched!")
}
}
class Myphone: Button, Application {
override var AppName: String = "Facebook"
override fun openApp() {
println("$AppName Is Open!")
}
override var helloMessage: String = "Hello"
override fun onClick() {
println("The screen was clicked!")
}
override fun phoneOn() {
println("$helloMessage !")
}
}
VERY simply: callback means the function, that is executed on the other function's finish or some specific event happening.
fun execute() {
// Some logic
executeAnotherOnFinish();
}
OR
// filter executes only after array converted to list
myIntArray.toList().filter { it > 0 }
OR
myListener.notify()
// Listener class methid
notify() {
// Do some work
executeCallback()
}
Callback is not just Kotlin related, its very common programming technique which is primarily used with asynchronous programming. The simplest explanation is that it is function that will be called back (hence the name) once some asynchronous event has occurred.
Button's onClick function is quite good example of that, we have some logic that we need to execute but we want it to run only when button is clicked so we provide callback which will be called once that button is clicked.
I'm trying to create a simple program, which is model of Brownian motion using concurrency (impurities randomly move left and right in cells). I have Impurity and Cells classes. Cell class contains cell array which mean how many impurities in each cell at the moment. Each Impurity object changes cell array in Cells in own thread. I'm starting threads and they are running in infinite loop for 1 seconds. But before and after this I print sum of impurities in cells and these values not equal, which means I do something wrong with synchronisation. Here is code:
Cells class:
object Cells {
var cell = Array(N) { 0 }
fun addImpurity(impurity: Impurity) {
cell[impurity.currentCell]++
}
#Synchronized
fun move(impurity: Impurity, direction: Direction) {
if (direction == Direction.LEFT && impurity.currentCell > 0) {
cell[impurity.currentCell]--
cell[impurity.currentCell - 1]++
impurity.currentCell--
} else if (direction == Direction.RIGHT && impurity.currentCell < N - 1) {
cell[impurity.currentCell]--
cell[impurity.currentCell + 1]++
impurity.currentCell++
}
Unit
}
fun printCells() {
for (c in cell)
print("$c ")
}
}
enum class Direction {
LEFT, RIGHT
}
Impurity class:
class Impurity(var currentCell: Int) {
private lateinit var thread: Thread
init {
Cells.addImpurity(this)
}
fun startMoving() {
thread = Thread {
while (true) {
if (random() > P)
Cells.move(this, Direction.RIGHT)
else
Cells.move(this, Direction.LEFT)
}
}
thread.start()
}
fun stopMoving() = thread.interrupt()
}
and Main:
const val N = 10
const val K = 15
const val P = 0.5
fun main(args: Array<String>) {
val impurities = ArrayList<Impurity>()
for (i in 1..K)
impurities.add(Impurity(0))
println(Cells.cell.sum())
startMoving(impurities)
Thread.sleep(1000)
stopMoving(impurities)
Cells.printCells()
println(Cells.cell.sum())
}
private fun startMoving(impurities: ArrayList<Impurity>) {
for (impurity in impurities)
impurity.startMoving()
}
private fun stopMoving(impurities: ArrayList<Impurity>) {
for (impurity in impurities)
impurity.stopMoving()
}
Thanks in advance!
I think it might be better to manually signal to the thread that it should finish its work by having it contain some flag that it refers to in order to know when to quit the loop. For example:
class Impurity(var currentCell: Int) {
...
private var _continue = true
fun startMoving() {
thread = Thread {
while (_continue) {
}
}
...
fun stopMoving() {
_continue = false
}
}
Additionally, you might also want to wait till the actual thread itself dies as part of the call to stopMoving. This will ensure that all the threads have definitely received the signal and quit their loops, before you call Cells.printCells. For example you could add this method to the Impurity class:
fun waitForEnded() = thread.join()
And you could update stopMoving in the main class to call this method after signaling to each thread to stop:
private fun stopMoving(impurities: ArrayList<Impurity>) {
for (impurity in impurities)
impurity.stopMoving()
impurities.forEach(Impurity::waitForEnded)
}
So I've just started on a basic LWJGL 3 program using this tutorial. I've converted all the code into Kotlin to make it work, and everything seemed to be fine. Until I got to the very end where he utilizes glfwWindowShouldClose(window). I tried it the way he showed, and my own method of replacing the running variable with the function call itself. I even tried replacing it with true. Unfortunately, it doesn't appear to be working.
To clarify, what I mean is that when I use glfwWindowShouldClose(window) anywhere in my project, any call to an LWJGL function results in an NPE, even functions that have nothing to do with it:
Exception in thread "thingy" java.lang.NullPointerException
at org.lwjgl.system.Checks.check(Checks.java:98)
at org.lwjgl.glfw.GLFW.glfwSwapBuffers(GLFW.java:4206)
at main.Window.render(main.kt:39)
at main.Window.run(main.kt:15)
at java.lang.Thread.run(Thread.java:745)
The code I used for this example of the error is here:
class Window: Runnable {
private val thread = Thread(this, "thingy")
private val window: Long
override fun run() {
while (true) {
update()
render()
}
}
init { thread.start(); window = init() }
private fun init(): Long {
if (!glfwInit()) System.err.println("Couldn't initialize GLFW.")
glfwWindowHint(GLFW_RESIZABLE, 1)
val window = glfwCreateWindow(800, 600, "thingy", NULL, NULL)
if (window == NULL) System.err.println("Couldn't create a window.")
val vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor())
glfwSetWindowPos(window, 100, 100)
glfwMakeContextCurrent(window)
glfwShowWindow(window)
return window
}
private fun update() { glfwPollEvents() }
private fun render() { glfwSwapBuffers(window) }
}
If I remove the function call and replace it with false in the while statement, it works fine. Is it possible that the instance of my loop itself is causing problems, and the only way it doesn't throw an exception is if the loop never happens (false)?
You are missing some important calls, such as GL.createCapabilities()
I'd strongly suggest you to start from the HelloWord you find here
Ps: if you use kotlin, I have a lib that can give you a ready scenario in a couple of lines
with(glfw) {
init()
windowHint { context.version = "3.3"; profile = "core"; }
}
GlfwWindow(windowSize, title).apply { makeContextCurrent(); show(); }
GL.createCapabilities()