Implementing Flood Fill Algorithm in Kotlin - kotlin

import java.util.Queue
import java.util.LinkedList
fun explore(row: Int, column: Int) {
val length1 = minefield.size
val length2 = minefield[0].size
if (displayedMinefield[row][column] == "/") return
val queue: Queue<Int> = LinkedList<Int>()
queue.add(listOf(row, column))
while (!queue.isEmpty()) {
val (i, j) = queue.first
queue.removeFirst()
if (i < 0 || i >= length1 || j < 0 || j >= length2) {
continue
} else {
if (checkIfMinesAround(i, j)) {
displayedMinefield[i][j] = minefield[i][j]
} else {
displayedMinefield[i][j] = "/"
}
queue.add(listOf(i + 1, j))
queue.add(listOf(i - 1, j))
queue.add(listOf(i, j + 1))
queue.add(listOf(i, j - 1))
}
}
}
I'm trying to implement the flood fill algorithm to recreate minesweeper. Essentially, this is how this part of the game works:
There is a minefield like the following:
│123456789│
—│—————————│
1│.........│
2│.........│
3│.........│
4│.........│
5│.........│
6│.........│
7│.........│
8│.........│
9│.........│
—│—————————│
If a player chooses to explore a cell, there are 3 different possibilities:
A. They explore a mine and lose (this part is easy)
B. If the chosen cell is empty but there are mines around it, only the chosen cell is explored
C. If there aren't any mines around it (and it's empty), the current cell should be marked with a "/." However, all the cells around it should be explored automatically as well (applying the same rules). In addition, if any of those cells are in the situation, meaning they also have no mines around them, all of their surrounding cells should be explored automatically.
So, it's a recursive process until the conditions aren't met anymore. The code above is what I have so far for the flood fill algorithm. I need help with adding to it. I already have a function that checks if there are mines around. So, I just need to perfect this function. Note: minefield is a mutable list that contains all the actual information, displayedMinefield is what is shown to the user.

Related

Slice() nested for loop values i and j Kotlin

I'm wanting to slice a range which I can do in Javascfript but am struggling in kotlin.
my current code is:
internal class blah {
fun longestPalindrome(s: String): String {
var longestP = ""
for (i in 0..s.length) {
for (j in 1..s.length) {
var subS = s.slice(i, j)
if (subS === subS.split("").reversed().joinToString("") && subS.length > longestP.length) {
longestP = subS
}
}
}
return longestP
}
and the error I get is:
Type mismatch.
Required:
IntRange
Found:
Int
Is there a way around this keeping most of the code I have?
As the error message says, slice wants an IntRange, not two Ints. So, pass it a range:
var subS = s.slice(i..j)
By the way, there are some bugs in your code:
You need to iterate up to the length minus 1 since the range starts at 0. But the easier way is to grab the indices range directly: for (i in s.indices)
I assume j should be i or bigger, not 1 or bigger, or you'll be checking some inverted Strings redundantly. It should look like for (j in i until s.length).
You need to use == instead of ===. The second operator is for referential equality, which will always be false for two computed Strings, even if they are identical.
I know this is probably just practice, but even with the above fixes, this code will fail if the String contains any multi-code-unit code points or any grapheme clusters. The proper way to do this would be by turning the String into a list of grapheme clusters and then performing the algorithm, but this is fairly complicated and should probably rely on some String processing code library.
class Solution {
fun longestPalindrome(s: String): String {
var longestPal = ""
for (i in 0 until s.length) {
for (j in i + 1..s.length) {
val substring = s.substring(i, j)
if (substring == substring.reversed() && substring.length > longestPal.length) {
longestPal = substring
}
}
}
return longestPal
}
}
This code is now functioning but unfortunately is not optimized enough to get through all test cases.

Removing a loop to make code run faster (Kotlin) (Big O)

I'm trying a leetcode challenge and am struggling to pass the challenge due to the speed of my code:
class Solution {
fun longestPalindrome(s: String): String {
var longestPal = ""
var substring = ""
for (i in 0..s.length) {
for (j in i + 1..s.length) {
substring = s.substring(i, j)
if (substring == substring.reversed() && substring.length > longestPal.length) {
longestPal = substring
}
}
}
return longestPal
}
}
I'm a newb and not familiar with Big O notation.
I imagine if I could use just one loop I would be able to speed this code up significantly but am not sure how I would go about this.
(Not saying this is the best approach, but that is a start)
Palindromes can only be found between two same letters. So one idea is to go through the string once, and keep track of letter indexes. When you encounter a letter you already saw before, and the difference in indexes is longer than the current longest palindrome, you check for a palindrome:
fun longestPal(s: String): String {
val letters = mutableMapOf<Char, MutableList<Int>>()
var longest = ""
s.indices.forEach { index ->
val indicesForCurrentChar = letters[s[index]] ?: mutableListOf()
for (i in indicesForCurrentChar) {
if ((index - i) < longest.length) break // (1) won't be the longest anyway
val sub = s.substring(i, index + 1)
if (sub == sub.reversed()) longest = sub
}
indicesForCurrentChar.add(index)
letters[s[index]] = indicesForCurrentChar
}
return longest
}
What is costly here is the palindrome check itself (sub == sub.reversed). But the check in (1) should contain it (think of a string which is the repetition of the same letter).
I would be curious to know what other suggest online.
Your code runs in O(n^3) time, a loop within a loop within a loop, because that reversed() call iterates up to the size of the input string. You can look up Manacher's algorithm for an explanation of how to do it in linear time (O(n)), no nested iteration at all.

for loop with two indices in Kotlin

It's possible to use for loop with double indices in Java, e.g:
for (int j = 0, k = myArray.length - 1; j < myArray.length; j++, k--)
To iterate myArray elements from the first element using j and from the last element using k simultaneously without using inner loop. How can we do this in Kotlin without using inner loop.
Kotlin doesn't provide a way to permit what you attempt to do.
Because I imagine your case is purely for exemple, I purpose you two solutions:
1. The good old way
The most optimized for the exemple you give.
for (i in a.indices) {
val j = a.size - 1 - i
println("($i, $j)")
}
(0, 3)(1, 2)(2, 1)(3, 0)
See code snippet on play.kotlinlang.org
2. The .zip() way
Can be usefull on some contexts, the zip method combine two lists of the same size on one list of Tuples which can be used after directly.
val indices = a.indices;
for (i in indices.zip(indices.reversed())) {
println(i)
}
(0, 3)(1, 2)(2, 1)(3, 0)
See code snippet on play.kotlinlang.org
You don't need an inner loop. Just create an additional variable inside for loop.
for(j in myArray.indices) {
val k = myArray.size - 1 - j
// Use j and k here
}
Or alternatively,
var k = myArray.size - 1
for(j in myArray.indices) {
// Use j and k here
k--
}
generateSequence() is powerful alternative for complex loops. Not so fast as pure for/while loop but very flexible and easy.
generateSequence(
0 to myArray.size - 1 // initial values
) {
it.first + 1 to it.second - 1 // new values after each iteration
}.takeWhile {
it.first < myArray.size // limit
}.forEach { (j, k) ->
println("$j $k")
}
And yes, it's good idea to not iterate second variable but calculate it from first (if applicable), as suggested in other answers.

How to setup for each loop in Kotlin to avoid out of bounds exception

In java I got this construction
for (let i = 0; i < x.length-1; I++
And here to avoid outOfBoundsException we are using x.length-1 but how to do the same thing in Kotlin? I got this code so far
x.forEachIndexed { index, _ ->
output.add((x[index+1]-x[index])*10)
}
And it crashes on the last element when we call x[index+1] so I need to handle the last element somehow
Input list
var x = doubleArrayOf(0.0, 0.23, 0.46, 0.69, 0.92, 1.15, 1.38, 1.61)
For a classic Java for loop you got two options in Kotlin.
One would be something like this.
val x = listOf(1,2,3,4)
for (i in 0 .. x.lastIndex){
// ...
}
Using .. you basically go from 0 up to ( and including) the number coresponding to the second item, in this case the last index of the list.( so from 0 <= i <= x.lastIndex)
The second option is using until
val x = listOf(1,2,3,4)
for (i in 0 until x.size){
// ...
}
This is similar to the previous approach, except the fact that until is not inclusive with the last element.(so from 0 <= i < x.size ).
What you probably need is something like this
val x = listOf(1,2,3,4)
for (i in 0 .. x.lastIndex -1){
// ...
}
or alternative, using until, like this
val x = listOf(1,2,3,4)
for (i in 0 until x.size-1){
// ...
}
This should probably avoid the IndexOut of bounds error, since you go just until the second to last item index.
Feel free to ask more if something is not clear.
This is also a great read if you want to learn more about ranges. https://kotlinlang.org/docs/ranges.html#progression
You already have an answer, but this is another option. If you would use a normal list, you would have access to zipWithNext(), and then you don't need to worry about any index, and you can just do:
list.zipWithNext { current, next ->
output.add((next - current)*10)
}
As mentioned by k314159, we can also do asList() to have direct access to zipWithNext and other list methods, without many drawbacks.
array.asList().zipWithNext { current, next ->
output.add(next - current)
}

kotlin intProgression not iterating?

Sorry this seems very basic but I'm missing something
I have a method signature override
fun doSomeWork (range: IntProgression, j: Int): List<Cell>{
I want to iterate the range whatever it is (could be up or down say 1 to 4 or 4 down to 1). The range itself seems to work, so on my 4 down to 1 example
println (range.first.toString() + " to " + range.last.toString() + ", step = " + range.step)
prints "4 to 1, step = 1"
but I can't seem to iterate the range ? I've tried a few things
for (i in range) {
println ("range: $i)"
}
and then
for (i in range.first until range.last step range.step){
println ("Loop de loop $i")
}
(although writing this question I noticed it is step 1 not -1 which may be the issue here ? but as I want to be able to pass in a range of either direction I haven't checked)
and then
range.forEach { println ("range foreach") }
none of them print anything, but they don't throw an error so any code after that runs through properly.
Can anyone point out why I'm failing to do this entry level task ?!
So you want an IntProgression from 4 to 1 with step -1, i.e. IntProgression.fromClosedRange(4, 1, -1) or better yet: 4.downTo(1). While you wrote your question you already realised the step... but the starting point isn't 1 then, but rather 4 ;-) With the downTo such problems will not arise, as the function takes care of the direction and it's also more readable then.
Note also that you can simply use reversed to reverse a progression:
range.reversed()
and either use it in a for-loop or with .forEach, etc.
So:
val range = IntProgression.fromClosedRange(1, 4, 1)
range.forEach(::print) // prints: 1234
range.reversed().forEach(::print) // prints: 4321
The forEach method can be used to iterate through the IntProgression. The it can be used to get the value or index.
fun doSomeWork (range: IntProgression) {
range.forEach {
println(it)
}
}
Invoking the above method:-
ClassName().doSomeWork(IntProgression.fromClosedRange(1,10, 1))
val range= IntProgression.fromClosedRange(1, 4, 1)
for (i in range)
println(i) // out put 1234
for (i in range.reversed())
println(i)//out put 4321
use
IntProgression.fromClosedRange(start, end, step)
for reverse range
IntProgression.reversed()
more details refer Ranges