There is a reason for not changing any sort of collection while iterating through it, even if is it not part of Collection, StringBuilder clearly is a sort of collection, since it has append and deleteAt functions.
If you have a string that is 0123456789, 0 is in index 0, 5 is in index 5. But if we remove let's say 3, then everything else after it, now has a different index. We have 012456789, and if you count, you can see that 5 will not have index 4, and so on. That means that your procedure will not only remove things it shouldn't, but if it wants to remove index 9, well, that no longer exists, hence, index out of bounds.
There are probably other ways of doing it than this, that are much more efficient and easy to understand, but I've tried to keep the same idea as you had in your example code.
val newSecret = StringBuilder(secret)
val newGuess = StringBuilder(guess)
secret.withIndex()
.filter { guess.length >= it.index + 1 //in case that guess is shorter than secret (if you know that they are the same length, this part of the predicate can be removed
&& it.value == guess[it.index] }
.map { it.index }
.reversed() //we want to delete from end to start, to avoid what we discussed above
.forEach {
newSecret.deleteCharAt(it)
newGuess.deleteCharAt(it)
}
In the above procedure, if secret and guess are:
val secret = "bar1bar2x5"
val guess = "foo1foo3y5"
Then newSecret and newGuess will be:
newSecret -> barbar2x
newGuess -> foofoo3y