Refacor Mastermind and implement functional style
This commit is contained in:
3
src/assignment/week2/mastermind/Common.kt
Normal file
3
src/assignment/week2/mastermind/Common.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package assignment.week2.mastermind
|
||||
|
||||
data class Evaluation(val rightPosition: Int, val wrongPosition: Int)
|
@ -1,6 +1,4 @@
|
||||
package mastermind
|
||||
|
||||
data class Evaluation(val rightPosition: Int, val wrongPosition: Int)
|
||||
package assignment.week2.mastermind
|
||||
|
||||
enum class Match {
|
||||
RIGHT_POSITION,
|
||||
@ -13,31 +11,57 @@ fun evaluateGuess(secret: String, guess: String): Evaluation {
|
||||
val secretMatches = createMatches(secret)
|
||||
|
||||
for ((index, guessChar) in guess.withIndex()) {
|
||||
if (secretMatches[index].char == guessChar) {
|
||||
if (secretMatches[index].match == Match.WRONG_POSITION) {
|
||||
for ((index, secretChar) in secret.drop(index + 1).withIndex()) {
|
||||
if (secretChar == guessChar) {
|
||||
secretMatches[index].match = Match.WRONG_POSITION
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
secretMatches[index].match = Match.RIGHT_POSITION
|
||||
val secretMatch = secretMatches[index]
|
||||
if (secretMatch.char == guessChar) {
|
||||
handleMatch(secretMatches, index)
|
||||
continue
|
||||
}
|
||||
for ((index, secretChar) in secret.withIndex()) {
|
||||
if (secretMatches[index].match == null && secretChar == guessChar) {
|
||||
secretMatches[index].match = Match.WRONG_POSITION
|
||||
break
|
||||
}
|
||||
}
|
||||
handleNotMatch(secretMatches, guessChar)
|
||||
}
|
||||
|
||||
return Evaluation(
|
||||
secretMatches.filter { it.match == Match.RIGHT_POSITION }.size,
|
||||
secretMatches.filter { it.match == Match.WRONG_POSITION }.size
|
||||
secretMatches.countMatch(Match.RIGHT_POSITION),
|
||||
secretMatches.countMatch(Match.WRONG_POSITION)
|
||||
)
|
||||
}
|
||||
|
||||
fun createMatches(secret: String): List<CharMatch> = secret.map { CharMatch(it, null) }
|
||||
private fun handleNotMatch(
|
||||
secretMatches: List<CharMatch>,
|
||||
guessChar: Char
|
||||
) {
|
||||
for (secretMatch in secretMatches) {
|
||||
if (secretMatch.match == null && secretMatch.char == guessChar) {
|
||||
secretMatch.match = Match.WRONG_POSITION
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMatch(secretMatches: List<CharMatch>, index: Int) {
|
||||
val secretMatch = secretMatches[index]
|
||||
if (secretMatch.match == Match.WRONG_POSITION) {
|
||||
moveWrongPosition(
|
||||
secretMatches.drop(index + 1).map { it.char },
|
||||
secretMatch.char,
|
||||
secretMatches
|
||||
)
|
||||
}
|
||||
secretMatch.match = Match.RIGHT_POSITION
|
||||
}
|
||||
|
||||
private fun List<CharMatch>.countMatch(match: Match): Int = filter { it.match == match }.size
|
||||
|
||||
private fun moveWrongPosition(
|
||||
chars: List<Char>,
|
||||
guessChar: Char,
|
||||
secretMatches: List<CharMatch>
|
||||
) {
|
||||
for ((index, secretChar) in chars.withIndex()) {
|
||||
if (secretChar == guessChar) {
|
||||
secretMatches[index].match = Match.WRONG_POSITION
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createMatches(secret: String): List<CharMatch> = secret.map { CharMatch(it, null) }
|
||||
|
22
src/assignment/week2/mastermind/evaluateGuessFunctional.kt
Normal file
22
src/assignment/week2/mastermind/evaluateGuessFunctional.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package assignment.week2.mastermind
|
||||
|
||||
fun evaluateGuessFunctional(secret: String, guess: String): Evaluation {
|
||||
val rightPositions = secret.zip(guess).count { (sChar, gChar) -> sChar == gChar }
|
||||
|
||||
val commonLetters = "ABCDEF".sumOf { ch ->
|
||||
secret.count { it == ch }.coerceAtMost(guess.count { it == ch })
|
||||
}
|
||||
return Evaluation(rightPositions, commonLetters - rightPositions)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val result = Evaluation(rightPosition = 1, wrongPosition = 1)
|
||||
evaluateGuessFunctional("BCDF", "ACEB") eq result
|
||||
evaluateGuessFunctional("AAAF", "ABCA") eq result
|
||||
evaluateGuessFunctional("ABCA", "AAAF") eq result
|
||||
}
|
||||
|
||||
private infix fun <T> T.eq(other: T) {
|
||||
if (this != other) throw AssertionError("Expected $this to equal $other")
|
||||
println("OK")
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package mastermind
|
||||
package assignment.week2.mastermind
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -11,8 +11,8 @@ fun main() {
|
||||
}
|
||||
|
||||
fun playMastermind(
|
||||
differentLetters: Boolean,
|
||||
secret: String = generateSecret(differentLetters)
|
||||
differentLetters: Boolean,
|
||||
secret: String = generateSecret(differentLetters)
|
||||
) {
|
||||
var evaluation: Evaluation
|
||||
|
||||
@ -20,17 +20,21 @@ fun playMastermind(
|
||||
print("Your guess: ")
|
||||
var guess = readLine()!!
|
||||
while (hasErrorsInInput(guess)) {
|
||||
println("Incorrect input: $guess. " +
|
||||
"It should consist of $CODE_LENGTH characters from $ALPHABET. " +
|
||||
"Please try again.")
|
||||
println(
|
||||
"Incorrect input: $guess. " +
|
||||
"It should consist of $CODE_LENGTH characters from $ALPHABET. " +
|
||||
"Please try again."
|
||||
)
|
||||
guess = readLine()!!
|
||||
}
|
||||
evaluation = evaluateGuess(secret, guess)
|
||||
if (evaluation.isComplete()) {
|
||||
println("The guess is correct!")
|
||||
} else {
|
||||
println("Right positions: ${evaluation.rightPosition}; " +
|
||||
"wrong positions: ${evaluation.wrongPosition}.")
|
||||
println(
|
||||
"Right positions: ${evaluation.rightPosition}; " +
|
||||
"wrong positions: ${evaluation.wrongPosition}."
|
||||
)
|
||||
}
|
||||
|
||||
} while (!evaluation.isComplete())
|
||||
|
Reference in New Issue
Block a user