import java.io.File interface NextRepetitionsRepository { fun read(): Repetitions? fun write(repetitions: Repetitions) } class FileNextRepetitionsRepository: NextRepetitionsRepository { private val store = File("next_repetitions.txt") override fun read(): Repetitions? { if (!store.exists()) return null val content = store.readLines() val firstRound = content.getOrNull(0)?.toIntOrNull() ?: return null val secondRound = content.getOrNull(1)?.toIntOrNull() ?: return null return Repetitions( firstRound = firstRound, secondRound = secondRound, ) } override fun write(repetitions: Repetitions) { if (!store.exists()) store.createNewFile() store.writeText("${repetitions.firstRound}\n"+ "${repetitions.secondRound}") } } data class Repetitions(val firstRound: Int, val secondRound: Int) class WorkoutManager { fun nextRepetitions( firstRoundDone: Int, secondRoundDone: Int, thirdRoundDone: Int, repetitions: Repetitions, ): Repetitions = when { firstRoundDone < repetitions.firstRound -> { // Could not do enough push-ups in the first round repetitions.copy( firstRound = repetitions.firstRound - 1, secondRound = repetitions.secondRound - 1 ) } secondRoundDone < repetitions.secondRound -> { // Could not do enough push-ups in the second round repetitions.copy( secondRound = repetitions.secondRound - 1 ) } thirdRoundDone > repetitions.firstRound -> { // The third round is above the first round, // so we increase the repetitions for both rounds repetitions.copy( firstRound = repetitions.firstRound + 1, secondRound = repetitions.secondRound + 1, ) } thirdRoundDone > repetitions.secondRound -> { // The third round is below the first round, // but above the second round, so we increase // the repetitions for the second round repetitions.copy( secondRound = repetitions.secondRound + 1, ) } else -> repetitions } } class WorkoutInteractor( val manager: WorkoutManager, val nextRepetitionsRepository: NextRepetitionsRepository ) { fun start() { println("Hello, I am your push-ups workout assistant!") val repetitions = nextRepetitionsRepository.read() ?: Repetitions(5, 5) println("Now do ${repetitions.firstRound} push-ups") val firstRoundDone = getValidIntInput( "How many push-ups did you do?" ) println("Now rest for 1 minute") Thread.sleep(1000 * 60) println("Now do ${repetitions.secondRound} push-ups") val secondRoundDone = getValidIntInput( "How many push-ups did you do?" ) println("Now rest for 1 minute") Thread.sleep(1000 * 60) println("Now do as many push-ups as you can!") val thirdRoundDone = getValidIntInput( "How many push-ups did you do?" ) val next = manager.nextRepetitions( firstRoundDone = firstRoundDone, secondRoundDone = secondRoundDone, thirdRoundDone = thirdRoundDone, repetitions = repetitions, ) nextRepetitionsRepository.write(next) println("Your next repetitions will be: "+ "${next.firstRound} and ${next.secondRound}") } private fun getValidIntInput(prompt: String): Int { while (true) { println(prompt) val input = readlnOrNull()?.toIntOrNull() if (input != null && input >= 0) { return input } println("Please enter a valid number.") } } } fun main() { val interactor = WorkoutInteractor( manager = WorkoutManager(), nextRepetitionsRepository = FileNextRepetitionsRepository(), ) interactor.start() }
The author:
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.