Mastermind game in Kotlin I am trying to create an evaluator in Kotlin for the Mastermind game which compares two strings and tells how many letters and letters on the right position they share. 

I was hoping to get some comments on how I can improve the code below in any way. Many thanks in advance!

fun String.masterCompare(otherString:String): Pair&lt;Int, Int&gt;? {

    // If the two strings are not equal in size, return null
    if (length != otherString.length)
        return null

    var letters : Int = 0  // The number of letters the two strings have in common
    var positions: Int = 0 // The number of shared letters that are in the same index
    var other = otherString // A mutable string copy of the argument string

    // Get number of shared indexes (positions)
    for ((index, c) in withIndex()){
        if (c == otherString[index]) {
            positions++
        }
    }

    // Check if a char in this string exists in the other. If so, increment letters and delete the char from the other string (so that it's not rechecked)
    for (c in toList()){
        if (other.contains(c)){
            letters++
            other = other.replace(c.toString(), "")
        }
    }

    return letters to positions
}

fun main(args: Array&lt;String&gt;) {
    println("ABCD".masterCompare("AFCH"))    // 2,2
    println("AAAA".masterCompare("AFCH"))    // 1,1
    println("ABCD".masterCompare("ABCD"))    // 4,4
    println("ABCD".masterCompare("DCBA"))    // 4,0
    println("ABCDP".masterCompare("DCBA"))   // null
}
You could go for a more functional (rather than imperative) approach.

Such as:

fun String.masterCompare(otherString: String): Pair&lt;Int, Int&gt;? =
        when {
            length != otherString.length -&gt; null
            else -&gt; {
                // this part is really easy
                val commonAtSameIndex = zip(otherString).count {
                    (one, another) -&gt; one == another
                }

                /* calculates the frequency map of characters in a given string.
                 * not the best solution in terms of performance - if you were to expect
                 * really large strings, you might be better off keeping the imperative approach.
                 * possibly with a bitmask instead of reassigning the mutable string. */
                fun String.toFrequency() = groupBy { it }
                        .mapValues { it.value.size }
                        .toMap()

                val thisFrequencyMap = toFrequency()
                val otherFrequencyMap = otherString.toFrequency()

                val commonOverall = thisFrequencyMap
                        .map { (letter, count) -&gt;
                            min(count, otherFrequencyMap[letter] ?: 0)
                        }
                        .sum()
                commonOverall to commonAtSameIndex
            }
        }


I would also suggest avoiding nulls out of principle, and possibly returning (0, 0) if strings aren't of the same length.

If you do need to differentiate between this case and strings of the same length that don't share any characters, I'd consider coming up with dedicated types instead of a nullable Pair, which is too generic (and makes it easy to confuse which field stands for what). 

Eg. the result type might be:

sealed class MasterComparisonResult {
    object DifferentLength : MasterComparisonResult()

    data class SameLength(val commonAtSameIndex: Int, val commonOverall: Int) : MasterComparisonResult()
}


And then the function returns a MasterComparisonResult instance.

Here's a version that combines the functional way - in my opinion much clearer - of calculating the number of identical characters in the same positions with the loop that calculates the other value.

A bit array is used for better performance.

fun String.masterCompare(otherString: String): Pair&lt;Int, Int&gt;? =
        when {
            length != otherString.length -&gt; null
            else -&gt; {
                // this part is really easy
                val commonAtSameIndex = zip(otherString).count {
                    (one, another) -&gt; one == another
                }

                var commonOverall = 0
                val countedAlready = BooleanArray(length)   

                /* this is yet another detail: there's no need for toList() allocation.
                 * you can iterate over this (String) straight away. */
                for (c in this) {
                    /* find the first occurrence of the c character in otherString
                     * that wasn't counted already */
                    val index = countedAlready
                            .asSequence()
                            .withIndex()
                            .filterNot { it.value }
                            .indexOfFirst { otherString[it.index] == c }
                    if (index &gt;= 0) {
                        countedAlready[index] = true
                        commonOverall++
                    }
                }
                commonOverall to commonAtSameIndex
            }
        }