Skip to content

Commit

Permalink
Fix warmup (#167)
Browse files Browse the repository at this point in the history
* Add theory, fix first several lessons

* Finish with fixes for warm up

* Fix detekt

* Fix tests
  • Loading branch information
nbirillo authored Dec 13, 2023
1 parent a16153f commit 58db8c8
Show file tree
Hide file tree
Showing 231 changed files with 5,511 additions and 775 deletions.
2 changes: 1 addition & 1 deletion Chat/askFirstQuestion/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 722717686
id: 468192544
2 changes: 1 addition & 1 deletion Chat/askSecondQuestion/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 1229098139
id: 692295510
2 changes: 1 addition & 1 deletion Chat/chatIntro/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 643359210
id: 619115895
2 changes: 1 addition & 1 deletion Chat/completeTheProject/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 843781288
id: 949232906
2 changes: 1 addition & 1 deletion Chat/lesson-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 1874291146
id: 734671394
4 changes: 4 additions & 0 deletions Introduction/lesson-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: framework
is_template_based: false
content:
- welcome
1 change: 1 addition & 0 deletions Introduction/lesson-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 350072480
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package jetbrains.kotlin.course.welcome

fun main() {
// Write your solution here
}
5 changes: 5 additions & 0 deletions Introduction/welcome/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: theory
custom_name: Kotlin Onboarding - Welcome!
files:
- name: src/main/kotlin/jetbrains/kotlin/course/welcome/Main.kt
visible: true
1 change: 1 addition & 0 deletions Introduction/welcome/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 309464317
20 changes: 20 additions & 0 deletions Introduction/welcome/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Hello! Welcome to the Kotlin course.
This course is designed for novices in Kotlin
and focuses on the basic concepts of the Kotlin language.

Each lesson of the course is built in the form of a project:
step by step, by completing different small tasks,
you will get a finished small project in the end.
At the end of each lesson, an additional similar project will be offered:
it includes all the topics of the lesson but is not divided into small tasks.

All topics will be accompanied by links to [the official Kotlin documentation](https://kotlinlang.org/docs/home.html),
which you can read later.

Note, this course **does not provide the detailed explanation** of the basic concepts
like variables, it only shows how to use the concepts in Kotlin and may remind you of their definitions.

Please join the course chat on Discord using [the link](https://discord.gg/pN3kfttB).
There, you can ask questions, interact with instructors, and connect with your fellow students.

Let's go!
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package jetbrains.kotlin.course.mastermind.advanced

fun getGameRules(wordLength: Int, maxAttemptsCount: Int, secretExample: String) =
"Welcome to the game! $newLineSymbol" +
newLineSymbol +
"Two people play this game: one chooses a word (a sequence of letters), " +
"the other guesses it. In this version, the computer chooses the word: " +
"a sequence of $wordLength letters (for example, $secretExample). " +
"The user has several attempts to guess it (the max number is $maxAttemptsCount). " +
"For each attempt, the number of complete matches (letter and position) " +
"and partial matches (letter only) is reported. $newLineSymbol" +
newLineSymbol +
"For example, with $secretExample as the hidden word, the BCDF guess will " +
"give 1 full match (C) and 1 partial match (B)."

fun countPartialMatches(secret: String, guess: String): Int {
val matches = minOf(
secret.filter { it in guess }.length,
guess.filter { it in secret }.length,
)
return matches - countExactMatches(guess, secret)
}

fun countExactMatches(secret: String, guess: String): Int =
guess.filterIndexed { index, letter -> letter == secret[index] }.length

fun generateSecret(wordLength: Int, alphabet: String) =
List(wordLength) { alphabet.random() }.joinToString("")

fun isComplete(secret: String, guess: String) = secret == guess

fun printRoundResults(secret: String, guess: String) {
val fullMatches = countExactMatches(secret, guess)
val partialMatches = countPartialMatches(secret, guess)
println("Your guess has $fullMatches full matches and $partialMatches partial matches.")
}

fun isWon(complete: Boolean, attempts: Int, maxAttemptsCount: Int) = complete && attempts <= maxAttemptsCount

fun isLost(complete: Boolean, attempts: Int, maxAttemptsCount: Int) = !complete && attempts > maxAttemptsCount

fun isCorrectInput(userInput: String, wordLength: Int, alphabet: String): Boolean {
if (userInput.length != wordLength) {
println("The length of your guess should be $wordLength! Try again!")
return false
}
val notAlphabetSymbols = userInput.filter { it !in alphabet }
if (notAlphabetSymbols.isNotEmpty()) {
println("All symbols in your guess should be from the alphabet: $alphabet! Try again!")
return false
}
return true
}

fun safeUserInput(wordLength: Int, alphabet: String): String {
var guess: String
var isCorrect: Boolean
do {
println("Please input your guess. It should be of length $wordLength, and each symbol should be from the alphabet: $alphabet.")
guess = safeReadLine()
isCorrect = isCorrectInput(guess, wordLength, alphabet)
} while(!isCorrect)
return guess
}

fun playGame(secret: String, wordLength: Int, maxAttemptsCount: Int, alphabet: String) {
var complete: Boolean
var attempts = 0
do {
println("Please input your guess. It should be of length $wordLength.")
val guess = safeUserInput(wordLength, alphabet)
printRoundResults(secret, guess)
complete = isComplete(secret, guess)
attempts++
if (isLost(complete, attempts, maxAttemptsCount)) {
println("Sorry, you lost! :( My word is $secret")
break
} else if (isWon(complete, attempts, maxAttemptsCount)) {
println("Congratulations! You guessed it!")
}
} while (!complete)
}

fun main() {
val wordLength = 4
val maxAttemptsCount = 3
val secretExample = "ACEB"
val alphabet = "ABCDEFGH"
println(getGameRules(wordLength, maxAttemptsCount, secretExample))
playGame(generateSecret(wordLength, alphabet), wordLength, maxAttemptsCount, alphabet)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package jetbrains.kotlin.course.mastermind.advanced

fun safeReadLine() = readlnOrNull() ?: error("Your input is incorrect, sorry")

val newLineSymbol: String = System.lineSeparator()
15 changes: 15 additions & 0 deletions MastermindAdvanced/CompleteTheProject/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type: edu
custom_name: Mastermind Advanced - Finish The Game
files:
- name: src/main/kotlin/jetbrains/kotlin/course/mastermind/advanced/Main.kt
visible: true
- name: src/main/kotlin/jetbrains/kotlin/course/mastermind/advanced/Util.kt
visible: false
- name: test/MainClass.kt
visible: false
- name: test/MastermindTestUtil.kt
visible: false
- name: test/Methods.kt
visible: false
- name: test/Tests.kt
visible: false
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 2109256460
26 changes: 26 additions & 0 deletions MastermindAdvanced/CompleteTheProject/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
It's time to apply implemented functions and finish the game!

### Task

Replace `safeReadLine` function inside the `playGame` function with implemented
on the previous step `safeUserInput` function.
Since the `safeUserInput` function requires `alphabet: String` argument, don't forget update the signature of
the `playGame` function.

<div class="hint" title="Push me to see the new signature of the playGame function">

The signature of the function is:
```kotlin
fun playGame(secret: String, wordLength: Int, maxAttemptsCount: Int, alphabet: String): Unit
```
</div>

Finally, don't forget to use the `alphabet` argument inside the main function when you call the `playGame` function.

Good luck!

<div class="hint" title="Push me to see the final version of the game">

![The game's example](../../utils/src/main/resources/images/part1/warmup/game.gif "The game's example")

</div>
18 changes: 18 additions & 0 deletions MastermindAdvanced/CompleteTheProject/test/MainClass.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import org.jetbrains.academy.test.system.core.models.classes.TestClass

internal val mainClass = TestClass(
classPackage = "jetbrains.kotlin.course.mastermind.advanced",
customMethods = listOf(
isCompleteMethod,
countExactMatchesMethod,
countPartialMatchesMethod,
isWinMethod,
isLostMethod,
generateSecretMethod,
getGameRulesMethod,
printRoundResultsMethod,
isCorrectInputMethod,
safeUserInputMethod,
playGameMethod
),
)
23 changes: 23 additions & 0 deletions MastermindAdvanced/CompleteTheProject/test/MastermindTestUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import util.Util

internal const val SECRET = "ABCD"
internal const val WORD_LENGTH = 4
internal const val ALPHABET = "ABCDEFG"

data class GameStep(
val attempt: String,
val positions: Int,
val letters: Int
) {
companion object {
private const val welcomeMessage = "Please input your guess. It should be of length $WORD_LENGTH."
}

fun imitateGameProcess() = "$welcomeMessage${Util.newLineSeparator}Your guess has $positions full matches, and $letters partial matches."
}

enum class UserInputCorrectness(val message: String, val isCorrect: Boolean) {
CORRECT("", true),
INCORRECT_LENGTH("The length of your guess should be $WORD_LENGTH! Try again!", false),
INCORRECT_ALPHABET("All symbols in your guess should be from the alphabet: $ALPHABET! Try again!", false)
}
110 changes: 110 additions & 0 deletions MastermindAdvanced/CompleteTheProject/test/Methods.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import org.jetbrains.academy.test.system.core.models.TestKotlinType
import org.jetbrains.academy.test.system.core.models.method.TestMethod
import org.jetbrains.academy.test.system.core.models.variable.TestVariable

internal val isCompleteMethod = TestMethod(
"isComplete",
TestKotlinType("Boolean"),
listOf(
TestVariable("secret", "String"),
TestVariable("guess", "String"),
),
)

internal val isCorrectInputMethod = TestMethod(
"isCorrectInput",
TestKotlinType("Boolean"),
listOf(
TestVariable("userInput", "String"),
TestVariable("wordLength", "Int"),
TestVariable("alphabet", "String"),
),
)

internal val safeUserInputMethod = TestMethod(
"safeUserInput",
TestKotlinType("String"),
listOf(
TestVariable("wordLength", "Int"),
TestVariable("alphabet", "String"),
),
)

internal val countExactMatchesMethod = TestMethod(
"countExactMatches",
TestKotlinType("Int"),
listOf(
TestVariable("secret", "String"),
TestVariable("guess", "String"),
),
)

internal val countPartialMatchesMethod = TestMethod(
"countPartialMatches",
TestKotlinType("Int"),
listOf(
TestVariable("secret", "String"),
TestVariable("guess", "String"),
),
)

internal val isWinMethod = TestMethod(
"isWon",
TestKotlinType("Boolean"),
listOf(
TestVariable("complete", "Boolean"),
TestVariable("attempts", "Int"),
TestVariable("maxAttemptsCount", "Int"),
),
)

internal val isLostMethod = TestMethod(
"isLost",
TestKotlinType("Boolean"),
listOf(
TestVariable("complete", "Boolean"),
TestVariable("attempts", "Int"),
TestVariable("maxAttemptsCount", "Int"),
),
)

internal val generateSecretMethod = TestMethod(
"generateSecret",
TestKotlinType("String"),
listOf(
TestVariable("wordLength", "Int"),
TestVariable("alphabet", "String"),
),
)

internal val playGameMethod = TestMethod(
"playGame",
TestKotlinType("Unit"),
listOf(
TestVariable("secret", "String"),
TestVariable("wordLength", "Int"),
TestVariable("maxAttemptsCount", "Int"),
TestVariable("alphabet", "String"),
),
"Void",
)

internal val getGameRulesMethod = TestMethod(
"getGameRules",
TestKotlinType("String"),
listOf(
TestVariable("wordLength", "Int"),
TestVariable("maxAttemptsCount", "Int"),
TestVariable("secretExample", "String"),
),
)

internal val printRoundResultsMethod = TestMethod(
"printRoundResults",
TestKotlinType("Unit"),
listOf(
TestVariable("secret", "String"),
TestVariable("guess", "String"),
),
"Void",
)
Loading

0 comments on commit 58db8c8

Please sign in to comment.