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
|
package assignment.week2.mastermind
|
||||||
|
|
||||||
data class Evaluation(val rightPosition: Int, val wrongPosition: Int)
|
|
||||||
|
|
||||||
enum class Match {
|
enum class Match {
|
||||||
RIGHT_POSITION,
|
RIGHT_POSITION,
|
||||||
@ -13,31 +11,57 @@ fun evaluateGuess(secret: String, guess: String): Evaluation {
|
|||||||
val secretMatches = createMatches(secret)
|
val secretMatches = createMatches(secret)
|
||||||
|
|
||||||
for ((index, guessChar) in guess.withIndex()) {
|
for ((index, guessChar) in guess.withIndex()) {
|
||||||
if (secretMatches[index].char == guessChar) {
|
val secretMatch = secretMatches[index]
|
||||||
if (secretMatches[index].match == Match.WRONG_POSITION) {
|
if (secretMatch.char == guessChar) {
|
||||||
for ((index, secretChar) in secret.drop(index + 1).withIndex()) {
|
handleMatch(secretMatches, index)
|
||||||
if (secretChar == guessChar) {
|
|
||||||
secretMatches[index].match = Match.WRONG_POSITION
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secretMatches[index].match = Match.RIGHT_POSITION
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for ((index, secretChar) in secret.withIndex()) {
|
handleNotMatch(secretMatches, guessChar)
|
||||||
if (secretMatches[index].match == null && secretChar == guessChar) {
|
|
||||||
secretMatches[index].match = Match.WRONG_POSITION
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Evaluation(
|
return Evaluation(
|
||||||
secretMatches.filter { it.match == Match.RIGHT_POSITION }.size,
|
secretMatches.countMatch(Match.RIGHT_POSITION),
|
||||||
secretMatches.filter { it.match == Match.WRONG_POSITION }.size
|
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
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -11,8 +11,8 @@ fun main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun playMastermind(
|
fun playMastermind(
|
||||||
differentLetters: Boolean,
|
differentLetters: Boolean,
|
||||||
secret: String = generateSecret(differentLetters)
|
secret: String = generateSecret(differentLetters)
|
||||||
) {
|
) {
|
||||||
var evaluation: Evaluation
|
var evaluation: Evaluation
|
||||||
|
|
||||||
@ -20,17 +20,21 @@ fun playMastermind(
|
|||||||
print("Your guess: ")
|
print("Your guess: ")
|
||||||
var guess = readLine()!!
|
var guess = readLine()!!
|
||||||
while (hasErrorsInInput(guess)) {
|
while (hasErrorsInInput(guess)) {
|
||||||
println("Incorrect input: $guess. " +
|
println(
|
||||||
"It should consist of $CODE_LENGTH characters from $ALPHABET. " +
|
"Incorrect input: $guess. " +
|
||||||
"Please try again.")
|
"It should consist of $CODE_LENGTH characters from $ALPHABET. " +
|
||||||
|
"Please try again."
|
||||||
|
)
|
||||||
guess = readLine()!!
|
guess = readLine()!!
|
||||||
}
|
}
|
||||||
evaluation = evaluateGuess(secret, guess)
|
evaluation = evaluateGuess(secret, guess)
|
||||||
if (evaluation.isComplete()) {
|
if (evaluation.isComplete()) {
|
||||||
println("The guess is correct!")
|
println("The guess is correct!")
|
||||||
} else {
|
} else {
|
||||||
println("Right positions: ${evaluation.rightPosition}; " +
|
println(
|
||||||
"wrong positions: ${evaluation.wrongPosition}.")
|
"Right positions: ${evaluation.rightPosition}; " +
|
||||||
|
"wrong positions: ${evaluation.wrongPosition}."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (!evaluation.isComplete())
|
} while (!evaluation.isComplete())
|
||||||
|
Reference in New Issue
Block a user