From 63ee10495c11d4a3128f761f10e758cbb297526e Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 11:43:25 +0200 Subject: [PATCH 01/12] first commit: main and gitignore --- .gitignore | 3 +++ src/main/kotlin/Main.kt | 7 +++++++ src/test/kotlin/com/hmf/GameRoundTests.kt | 4 ++++ 3 files changed, 14 insertions(+) create mode 100644 .gitignore create mode 100644 src/main/kotlin/Main.kt create mode 100644 src/test/kotlin/com/hmf/GameRoundTests.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..069266f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +libs/ +out/ diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt new file mode 100644 index 0000000..f2a59b6 --- /dev/null +++ b/src/main/kotlin/Main.kt @@ -0,0 +1,7 @@ +fun main(args: Array) { + println("Hello World!") + + // Try adding program arguments via Run/Debug configuration. + // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html. + println("Program arguments: ${args.joinToString()}") +} \ No newline at end of file diff --git a/src/test/kotlin/com/hmf/GameRoundTests.kt b/src/test/kotlin/com/hmf/GameRoundTests.kt new file mode 100644 index 0000000..800ffc8 --- /dev/null +++ b/src/test/kotlin/com/hmf/GameRoundTests.kt @@ -0,0 +1,4 @@ +package com.hmf + +class GameRoundTests { +} \ No newline at end of file From b5d4a23ca77052a9092cc02eb202f0d57d9d9a7b Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:00:42 +0200 Subject: [PATCH 02/12] sketching out the first unit-test --- src/main/kotlin/com/hmf/Element.kt | 5 +++++ src/main/kotlin/com/hmf/GameRound.kt | 7 +++++++ src/main/kotlin/com/hmf/Outcome.kt | 5 +++++ src/test/kotlin/com/hmf/GameRoundTests.kt | 12 ++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 src/main/kotlin/com/hmf/Element.kt create mode 100644 src/main/kotlin/com/hmf/GameRound.kt create mode 100644 src/main/kotlin/com/hmf/Outcome.kt diff --git a/src/main/kotlin/com/hmf/Element.kt b/src/main/kotlin/com/hmf/Element.kt new file mode 100644 index 0000000..7838eda --- /dev/null +++ b/src/main/kotlin/com/hmf/Element.kt @@ -0,0 +1,5 @@ +package com.hmf + +enum class Element(val idx: Int){ + NONE(-1), ROCK(0), PAPER(1), SCISSORS(2) +} diff --git a/src/main/kotlin/com/hmf/GameRound.kt b/src/main/kotlin/com/hmf/GameRound.kt new file mode 100644 index 0000000..05cac40 --- /dev/null +++ b/src/main/kotlin/com/hmf/GameRound.kt @@ -0,0 +1,7 @@ +package com.hmf + +class GameRound { + fun getOutcome(player: Element, opponent: Element): Outcome { + return Outcome.DRAW + } +} diff --git a/src/main/kotlin/com/hmf/Outcome.kt b/src/main/kotlin/com/hmf/Outcome.kt new file mode 100644 index 0000000..7790ffb --- /dev/null +++ b/src/main/kotlin/com/hmf/Outcome.kt @@ -0,0 +1,5 @@ +package com.hmf + +enum class Outcome(val points: Int) { + PLAYER_LOST(-1), DRAW(0), PLAYER_WON(1) +} diff --git a/src/test/kotlin/com/hmf/GameRoundTests.kt b/src/test/kotlin/com/hmf/GameRoundTests.kt index 800ffc8..e5d6fbb 100644 --- a/src/test/kotlin/com/hmf/GameRoundTests.kt +++ b/src/test/kotlin/com/hmf/GameRoundTests.kt @@ -1,4 +1,16 @@ package com.hmf +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + class GameRoundTests { + + @Test + fun TestSingleRound(){ + + val round = GameRound() + val outcome0 = round.getOutcome(Element.ROCK, Element.ROCK) + assertEquals(outcome0, Outcome.DRAW) + + } } \ No newline at end of file From e7a07b6005b429dd013c802248a2e6fddbe5e87f Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:03:56 +0200 Subject: [PATCH 03/12] unit-test for game rules --- src/main/kotlin/com/hmf/GameRound.kt | 9 ++++++++- src/test/kotlin/com/hmf/GameRoundTests.kt | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/hmf/GameRound.kt b/src/main/kotlin/com/hmf/GameRound.kt index 05cac40..591ef81 100644 --- a/src/main/kotlin/com/hmf/GameRound.kt +++ b/src/main/kotlin/com/hmf/GameRound.kt @@ -1,7 +1,14 @@ package com.hmf class GameRound { + + private val rules: Array> = arrayOf( + arrayOf(Outcome.DRAW, Outcome.PLAYER_LOST, Outcome.PLAYER_WON), // we can also use shortArrayOf or doubleArrayOf... + arrayOf(Outcome.PLAYER_WON, Outcome.DRAW, Outcome.PLAYER_LOST), + arrayOf(Outcome.PLAYER_LOST, Outcome.PLAYER_WON, Outcome.DRAW) + ) + fun getOutcome(player: Element, opponent: Element): Outcome { - return Outcome.DRAW + return rules[player.idx][opponent.idx] } } diff --git a/src/test/kotlin/com/hmf/GameRoundTests.kt b/src/test/kotlin/com/hmf/GameRoundTests.kt index e5d6fbb..71f45e9 100644 --- a/src/test/kotlin/com/hmf/GameRoundTests.kt +++ b/src/test/kotlin/com/hmf/GameRoundTests.kt @@ -7,10 +7,14 @@ class GameRoundTests { @Test fun TestSingleRound(){ - val round = GameRound() - val outcome0 = round.getOutcome(Element.ROCK, Element.ROCK) + val outcome0 = round.getOutcome(player=Element.ROCK, opponent=Element.ROCK) assertEquals(outcome0, Outcome.DRAW) + val outcome1 = round.getOutcome(player=Element.ROCK, opponent=Element.PAPER) + assertEquals(outcome1, Outcome.PLAYER_LOST) + + val outcome2 = round.getOutcome(player=Element.ROCK, opponent=Element.SCISSORS) + assertEquals(outcome2, Outcome.PLAYER_WON) } } \ No newline at end of file From 50cc797e67ad39eb7230803cf604b117802b6bdf Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:17:06 +0200 Subject: [PATCH 04/12] trivial test for the main game class --- src/main/kotlin/com/hmf/Game.kt | 18 ++++++++++++++++++ src/main/kotlin/com/hmf/GameResult.kt | 3 +++ .../com/hmf/{GameRound.kt => GameRules.kt} | 2 +- src/main/kotlin/com/hmf/ICanPlay.kt | 2 ++ .../{GameRoundTests.kt => GameRulesTests.kt} | 4 ++-- src/test/kotlin/com/hmf/GameTests.kt | 18 ++++++++++++++++++ 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/com/hmf/Game.kt create mode 100644 src/main/kotlin/com/hmf/GameResult.kt rename src/main/kotlin/com/hmf/{GameRound.kt => GameRules.kt} (96%) create mode 100644 src/main/kotlin/com/hmf/ICanPlay.kt rename src/test/kotlin/com/hmf/{GameRoundTests.kt => GameRulesTests.kt} (90%) create mode 100644 src/test/kotlin/com/hmf/GameTests.kt diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt new file mode 100644 index 0000000..97da82a --- /dev/null +++ b/src/main/kotlin/com/hmf/Game.kt @@ -0,0 +1,18 @@ +package com.hmf + +class Game { + + private var played:Int = 0; + private var won:Int = 0; + private var drawn:Int = 0; + + fun playRound(playerHand: Element) { + + } + + fun getStats(): GameResult { + return GameResult(roundsPlayed=played,roundsWon=won,roundsDrawn=drawn) + } + + +} diff --git a/src/main/kotlin/com/hmf/GameResult.kt b/src/main/kotlin/com/hmf/GameResult.kt new file mode 100644 index 0000000..c5f36e2 --- /dev/null +++ b/src/main/kotlin/com/hmf/GameResult.kt @@ -0,0 +1,3 @@ +package com.hmf + +data class GameResult(val roundsPlayed:Int, val roundsWon: Int, val roundsDrawn: Int) { } diff --git a/src/main/kotlin/com/hmf/GameRound.kt b/src/main/kotlin/com/hmf/GameRules.kt similarity index 96% rename from src/main/kotlin/com/hmf/GameRound.kt rename to src/main/kotlin/com/hmf/GameRules.kt index 591ef81..2104860 100644 --- a/src/main/kotlin/com/hmf/GameRound.kt +++ b/src/main/kotlin/com/hmf/GameRules.kt @@ -1,6 +1,6 @@ package com.hmf -class GameRound { +class GameRules { private val rules: Array> = arrayOf( arrayOf(Outcome.DRAW, Outcome.PLAYER_LOST, Outcome.PLAYER_WON), // we can also use shortArrayOf or doubleArrayOf... diff --git a/src/main/kotlin/com/hmf/ICanPlay.kt b/src/main/kotlin/com/hmf/ICanPlay.kt new file mode 100644 index 0000000..3c5276e --- /dev/null +++ b/src/main/kotlin/com/hmf/ICanPlay.kt @@ -0,0 +1,2 @@ +package com.hmf + diff --git a/src/test/kotlin/com/hmf/GameRoundTests.kt b/src/test/kotlin/com/hmf/GameRulesTests.kt similarity index 90% rename from src/test/kotlin/com/hmf/GameRoundTests.kt rename to src/test/kotlin/com/hmf/GameRulesTests.kt index 71f45e9..fd8f1df 100644 --- a/src/test/kotlin/com/hmf/GameRoundTests.kt +++ b/src/test/kotlin/com/hmf/GameRulesTests.kt @@ -3,11 +3,11 @@ package com.hmf import org.junit.jupiter.api.Test import kotlin.test.assertEquals -class GameRoundTests { +class GameRulesTests { @Test fun TestSingleRound(){ - val round = GameRound() + val round = GameRules() val outcome0 = round.getOutcome(player=Element.ROCK, opponent=Element.ROCK) assertEquals(outcome0, Outcome.DRAW) diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt new file mode 100644 index 0000000..fd98d94 --- /dev/null +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -0,0 +1,18 @@ +package com.hmf + +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class GameTests { + + @Test + fun TestStatsForGameNotPlayed(){ + val game = Game() + val result = game.getStats() + assertEquals(result.roundsPlayed, 0) + assertEquals(result.roundsWon, 0) + assertEquals(result.roundsDrawn, 0) + } + + +} \ No newline at end of file From 33fa0a6941059d716c4cf311dd29ad8a4dc2d1f2 Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:25:59 +0200 Subject: [PATCH 05/12] sketching out test for multiround game --- src/main/kotlin/com/hmf/ICanPlay.kt | 3 +++ src/test/kotlin/com/hmf/GameTests.kt | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/kotlin/com/hmf/ICanPlay.kt b/src/main/kotlin/com/hmf/ICanPlay.kt index 3c5276e..ee5dfe0 100644 --- a/src/main/kotlin/com/hmf/ICanPlay.kt +++ b/src/main/kotlin/com/hmf/ICanPlay.kt @@ -1,2 +1,5 @@ package com.hmf +interface ICanPlay { + fun play(): Element +} \ No newline at end of file diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt index fd98d94..a16bf8b 100644 --- a/src/test/kotlin/com/hmf/GameTests.kt +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -3,6 +3,12 @@ package com.hmf import org.junit.jupiter.api.Test import kotlin.test.assertEquals +class StubOpponent : ICanPlay { + override fun play(): Element { + TODO("Not yet implemented") + } +} + class GameTests { @Test @@ -14,5 +20,14 @@ class GameTests { assertEquals(result.roundsDrawn, 0) } + @Test + fun TestStatsForMultiplePlayedGameRounds(){ + val game = Game() + val result = game.getStats() + assertEquals(result.roundsPlayed, 0) + assertEquals(result.roundsWon, 0) + assertEquals(result.roundsDrawn, 0) + } + } \ No newline at end of file From fb1fe96200ffe5a7a8f0094788fd41944f721ceb Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:39:46 +0200 Subject: [PATCH 06/12] multiround game test done, can inject opponent type/instance --- src/main/kotlin/com/hmf/Game.kt | 24 ++++++++++++++++++++++-- src/test/kotlin/com/hmf/GameTests.kt | 17 +++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt index 97da82a..2cb8ff7 100644 --- a/src/main/kotlin/com/hmf/Game.kt +++ b/src/main/kotlin/com/hmf/Game.kt @@ -1,13 +1,33 @@ package com.hmf -class Game { +class Game { + val opponent: Opponent + + constructor(opponent:Opponent){ + this.opponent = opponent + } private var played:Int = 0; private var won:Int = 0; private var drawn:Int = 0; + private val rules = GameRules() fun playRound(playerHand: Element) { - + val opponentHand = opponent.play() + when(rules.getOutcome(player = playerHand, opponent=opponentHand)){ + Outcome.PLAYER_WON -> { + println("You won! ${playerHand.toString()} beats ${opponentHand.toString()}") + won+=1 + } + Outcome.PLAYER_LOST -> { + println("You lost! ${playerHand.toString()} looses to ${opponentHand.toString()}") + } + Outcome.DRAW -> { + println("It is a draw! Computer played ${opponentHand.toString()} as well.") + drawn+=1 + } + } + played+=1 } fun getStats(): GameResult { diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt index a16bf8b..650b17d 100644 --- a/src/test/kotlin/com/hmf/GameTests.kt +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -5,7 +5,7 @@ import kotlin.test.assertEquals class StubOpponent : ICanPlay { override fun play(): Element { - TODO("Not yet implemented") + return Element.ROCK; } } @@ -13,7 +13,8 @@ class GameTests { @Test fun TestStatsForGameNotPlayed(){ - val game = Game() + val opponent = StubOpponent() + val game = Game(opponent) val result = game.getStats() assertEquals(result.roundsPlayed, 0) assertEquals(result.roundsWon, 0) @@ -22,11 +23,15 @@ class GameTests { @Test fun TestStatsForMultiplePlayedGameRounds(){ - val game = Game() + val opponent = StubOpponent() + val game = Game(opponent) + game.playRound(playerHand=Element.SCISSORS) + game.playRound(playerHand=Element.ROCK) + game.playRound(playerHand=Element.PAPER) val result = game.getStats() - assertEquals(result.roundsPlayed, 0) - assertEquals(result.roundsWon, 0) - assertEquals(result.roundsDrawn, 0) + assertEquals(result.roundsPlayed, 3) + assertEquals(result.roundsWon, 1) + assertEquals(result.roundsDrawn, 1) } From 73aad6e2cf68bbc92456be34bc33018fc959c2d3 Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 12:53:27 +0200 Subject: [PATCH 07/12] inject outputter into a game class to avoid spam in the unit-test --- src/main/kotlin/com/hmf/Game.kt | 24 +++++++++------------- src/main/kotlin/com/hmf/ICanPrint.kt | 5 +++++ src/main/kotlin/com/hmf/StdOutOutputter.kt | 14 +++++++++++++ src/test/kotlin/com/hmf/GameTests.kt | 16 +++++++++------ 4 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 src/main/kotlin/com/hmf/ICanPrint.kt create mode 100644 src/main/kotlin/com/hmf/StdOutOutputter.kt diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt index 2cb8ff7..3fd6613 100644 --- a/src/main/kotlin/com/hmf/Game.kt +++ b/src/main/kotlin/com/hmf/Game.kt @@ -1,11 +1,13 @@ package com.hmf -class Game { +class Game { val opponent: Opponent + val outputter: Outputter - constructor(opponent:Opponent){ + constructor(opponent:Opponent,outputter:Outputter){ this.opponent = opponent + this.outputter = outputter } private var played:Int = 0; private var won:Int = 0; @@ -14,18 +16,12 @@ class Game { fun playRound(playerHand: Element) { val opponentHand = opponent.play() - when(rules.getOutcome(player = playerHand, opponent=opponentHand)){ - Outcome.PLAYER_WON -> { - println("You won! ${playerHand.toString()} beats ${opponentHand.toString()}") - won+=1 - } - Outcome.PLAYER_LOST -> { - println("You lost! ${playerHand.toString()} looses to ${opponentHand.toString()}") - } - Outcome.DRAW -> { - println("It is a draw! Computer played ${opponentHand.toString()} as well.") - drawn+=1 - } + val outcome = rules.getOutcome(player = playerHand, opponent=opponentHand) + outputter.printOutcome(roundOutcome=outcome, player = playerHand, opponent = opponentHand) + when(outcome){ + Outcome.PLAYER_WON -> won+=1 + Outcome.DRAW -> drawn+=1 + Outcome.PLAYER_LOST -> Unit } played+=1 } diff --git a/src/main/kotlin/com/hmf/ICanPrint.kt b/src/main/kotlin/com/hmf/ICanPrint.kt new file mode 100644 index 0000000..6ab8b4b --- /dev/null +++ b/src/main/kotlin/com/hmf/ICanPrint.kt @@ -0,0 +1,5 @@ +package com.hmf + +interface ICanPrint { + fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) +} diff --git a/src/main/kotlin/com/hmf/StdOutOutputter.kt b/src/main/kotlin/com/hmf/StdOutOutputter.kt new file mode 100644 index 0000000..17b7d05 --- /dev/null +++ b/src/main/kotlin/com/hmf/StdOutOutputter.kt @@ -0,0 +1,14 @@ +package com.hmf + +class StdOutOutputter : ICanPrint { + override fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) { + when(roundOutcome){ + Outcome.PLAYER_LOST -> + println("You lost! ${player.toString()} looses to ${opponent.toString()}") + Outcome.PLAYER_WON -> + println("You won! ${player.toString()} beats ${opponent.toString()}") + Outcome.DRAW -> + println("It is a draw! Computer played ${opponent.toString()} as well.") + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt index 650b17d..c10ae00 100644 --- a/src/test/kotlin/com/hmf/GameTests.kt +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -3,18 +3,23 @@ package com.hmf import org.junit.jupiter.api.Test import kotlin.test.assertEquals -class StubOpponent : ICanPlay { +class StubOpponent(val element: Element) : ICanPlay { override fun play(): Element { - return Element.ROCK; + return element; } } +class StubOutputter : ICanPrint { + override fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) {} +} class GameTests { + val alwaysRockOpponent = StubOpponent(Element.ROCK) + val outputter = StubOutputter() + @Test fun TestStatsForGameNotPlayed(){ - val opponent = StubOpponent() - val game = Game(opponent) + val game = Game(alwaysRockOpponent,outputter) val result = game.getStats() assertEquals(result.roundsPlayed, 0) assertEquals(result.roundsWon, 0) @@ -23,8 +28,7 @@ class GameTests { @Test fun TestStatsForMultiplePlayedGameRounds(){ - val opponent = StubOpponent() - val game = Game(opponent) + val game = Game(alwaysRockOpponent,outputter) game.playRound(playerHand=Element.SCISSORS) game.playRound(playerHand=Element.ROCK) game.playRound(playerHand=Element.PAPER) From a1ee0a461b7c616387ee15002568400eea500e59 Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 13:19:45 +0200 Subject: [PATCH 08/12] add cli interface to the game, extra test --- src/main/kotlin/Main.kt | 13 ++++---- src/main/kotlin/com/hmf/Computer.kt | 7 +++++ src/main/kotlin/com/hmf/Game.kt | 35 ++++++++++++++++++++-- src/main/kotlin/com/hmf/ICanPrint.kt | 1 + src/main/kotlin/com/hmf/StdOutOutputter.kt | 7 +++++ src/test/kotlin/com/hmf/GameTests.kt | 29 +++++++++++++----- 6 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/com/hmf/Computer.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index f2a59b6..2527432 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,7 +1,10 @@ -fun main(args: Array) { - println("Hello World!") +import com.hmf.Computer +import com.hmf.Game +import com.hmf.StdOutOutputter - // Try adding program arguments via Run/Debug configuration. - // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html. - println("Program arguments: ${args.joinToString()}") +fun main(args: Array) { + val opponent = Computer() + val outputter = StdOutOutputter() + val game = Game(opponent, outputter) + game.play() } \ No newline at end of file diff --git a/src/main/kotlin/com/hmf/Computer.kt b/src/main/kotlin/com/hmf/Computer.kt new file mode 100644 index 0000000..d1ecb17 --- /dev/null +++ b/src/main/kotlin/com/hmf/Computer.kt @@ -0,0 +1,7 @@ +package com.hmf + +class Computer :ICanPlay { + override fun play():Element{ + return Element.values().random(); + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt index 3fd6613..83aa46a 100644 --- a/src/main/kotlin/com/hmf/Game.kt +++ b/src/main/kotlin/com/hmf/Game.kt @@ -1,14 +1,18 @@ package com.hmf +import java.util.Scanner + class Game { - val opponent: Opponent - val outputter: Outputter + private val scanner = Scanner(System.`in`) + private val opponent: Opponent + private val outputter: Outputter constructor(opponent:Opponent,outputter:Outputter){ this.opponent = opponent this.outputter = outputter } + private var played:Int = 0; private var won:Int = 0; private var drawn:Int = 0; @@ -26,9 +30,34 @@ class Game { played+=1 } + + fun play(){ + var stopPlaying = false + while (!stopPlaying) { + var userInput = Element.NONE + print("Choose your input:\n'0' for ROCK\n'1' for PAPER\n'2' for SCISSORS\n'x' to stop\n -> ") + when (scanner.next().single()) { + '0' -> userInput = Element.ROCK + '1' -> userInput = Element.PAPER + '2' -> userInput = Element.SCISSORS + 'x' -> { + stopPlaying = true + } + else -> { + println("Invalid input, fat fingers? Try again!") + continue + } + } + if (stopPlaying){ + outputter.printStats(getStats()) + break + } + playRound(userInput) + } + } + fun getStats(): GameResult { return GameResult(roundsPlayed=played,roundsWon=won,roundsDrawn=drawn) } - } diff --git a/src/main/kotlin/com/hmf/ICanPrint.kt b/src/main/kotlin/com/hmf/ICanPrint.kt index 6ab8b4b..6634900 100644 --- a/src/main/kotlin/com/hmf/ICanPrint.kt +++ b/src/main/kotlin/com/hmf/ICanPrint.kt @@ -2,4 +2,5 @@ package com.hmf interface ICanPrint { fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) + fun printStats(stats:GameResult) } diff --git a/src/main/kotlin/com/hmf/StdOutOutputter.kt b/src/main/kotlin/com/hmf/StdOutOutputter.kt index 17b7d05..e67b8c3 100644 --- a/src/main/kotlin/com/hmf/StdOutOutputter.kt +++ b/src/main/kotlin/com/hmf/StdOutOutputter.kt @@ -11,4 +11,11 @@ class StdOutOutputter : ICanPrint { println("It is a draw! Computer played ${opponent.toString()} as well.") } } + + override fun printStats(stats:GameResult) { + + println("Rounds played: ${stats.roundsPlayed}") + println("Rounds won: ${stats.roundsWon}") + println("Rounds drawn: ${stats.roundsDrawn}") + } } \ No newline at end of file diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt index c10ae00..b43fa0f 100644 --- a/src/test/kotlin/com/hmf/GameTests.kt +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -10,6 +10,7 @@ class StubOpponent(val element: Element) : ICanPlay { } class StubOutputter : ICanPrint { override fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) {} + override fun printStats(stats: GameResult) {} } class GameTests { @@ -28,14 +29,26 @@ class GameTests { @Test fun TestStatsForMultiplePlayedGameRounds(){ - val game = Game(alwaysRockOpponent,outputter) - game.playRound(playerHand=Element.SCISSORS) - game.playRound(playerHand=Element.ROCK) - game.playRound(playerHand=Element.PAPER) - val result = game.getStats() - assertEquals(result.roundsPlayed, 3) - assertEquals(result.roundsWon, 1) - assertEquals(result.roundsDrawn, 1) + run { + val game = Game(alwaysRockOpponent,outputter) + game.playRound(playerHand=Element.SCISSORS) + game.playRound(playerHand=Element.ROCK) + game.playRound(playerHand=Element.PAPER) + val result = game.getStats() + assertEquals(result.roundsPlayed, 3) + assertEquals(result.roundsWon, 1) + assertEquals(result.roundsDrawn, 1) + } + run { + val game = Game(alwaysRockOpponent,outputter) + game.playRound(playerHand=Element.PAPER) + game.playRound(playerHand=Element.PAPER) + game.playRound(playerHand=Element.PAPER) + val result = game.getStats() + assertEquals(result.roundsPlayed, 3) + assertEquals(result.roundsWon, 3) + assertEquals(result.roundsDrawn, 0) + } } From 1eab47e1db879a321cd394152ba4b92226a0c47d Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 13:22:38 +0200 Subject: [PATCH 09/12] give better names to interfaces --- src/main/kotlin/com/hmf/Computer.kt | 2 +- src/main/kotlin/com/hmf/Game.kt | 2 +- src/main/kotlin/com/hmf/{ICanPlay.kt => IOpponent.kt} | 2 +- src/main/kotlin/com/hmf/{ICanPrint.kt => IOutputter.kt} | 2 +- src/main/kotlin/com/hmf/StdOutOutputter.kt | 2 +- src/test/kotlin/com/hmf/GameTests.kt | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) rename src/main/kotlin/com/hmf/{ICanPlay.kt => IOpponent.kt} (66%) rename src/main/kotlin/com/hmf/{ICanPrint.kt => IOutputter.kt} (85%) diff --git a/src/main/kotlin/com/hmf/Computer.kt b/src/main/kotlin/com/hmf/Computer.kt index d1ecb17..4ac35ef 100644 --- a/src/main/kotlin/com/hmf/Computer.kt +++ b/src/main/kotlin/com/hmf/Computer.kt @@ -1,6 +1,6 @@ package com.hmf -class Computer :ICanPlay { +class Computer :IOpponent { override fun play():Element{ return Element.values().random(); } diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt index 83aa46a..1202426 100644 --- a/src/main/kotlin/com/hmf/Game.kt +++ b/src/main/kotlin/com/hmf/Game.kt @@ -2,7 +2,7 @@ package com.hmf import java.util.Scanner -class Game { +class Game { private val scanner = Scanner(System.`in`) private val opponent: Opponent diff --git a/src/main/kotlin/com/hmf/ICanPlay.kt b/src/main/kotlin/com/hmf/IOpponent.kt similarity index 66% rename from src/main/kotlin/com/hmf/ICanPlay.kt rename to src/main/kotlin/com/hmf/IOpponent.kt index ee5dfe0..a0b7c0a 100644 --- a/src/main/kotlin/com/hmf/ICanPlay.kt +++ b/src/main/kotlin/com/hmf/IOpponent.kt @@ -1,5 +1,5 @@ package com.hmf -interface ICanPlay { +interface IOpponent { fun play(): Element } \ No newline at end of file diff --git a/src/main/kotlin/com/hmf/ICanPrint.kt b/src/main/kotlin/com/hmf/IOutputter.kt similarity index 85% rename from src/main/kotlin/com/hmf/ICanPrint.kt rename to src/main/kotlin/com/hmf/IOutputter.kt index 6634900..602b37b 100644 --- a/src/main/kotlin/com/hmf/ICanPrint.kt +++ b/src/main/kotlin/com/hmf/IOutputter.kt @@ -1,6 +1,6 @@ package com.hmf -interface ICanPrint { +interface IOutputter { fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) fun printStats(stats:GameResult) } diff --git a/src/main/kotlin/com/hmf/StdOutOutputter.kt b/src/main/kotlin/com/hmf/StdOutOutputter.kt index e67b8c3..ebc82e9 100644 --- a/src/main/kotlin/com/hmf/StdOutOutputter.kt +++ b/src/main/kotlin/com/hmf/StdOutOutputter.kt @@ -1,6 +1,6 @@ package com.hmf -class StdOutOutputter : ICanPrint { +class StdOutOutputter : IOutputter { override fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) { when(roundOutcome){ Outcome.PLAYER_LOST -> diff --git a/src/test/kotlin/com/hmf/GameTests.kt b/src/test/kotlin/com/hmf/GameTests.kt index b43fa0f..f761433 100644 --- a/src/test/kotlin/com/hmf/GameTests.kt +++ b/src/test/kotlin/com/hmf/GameTests.kt @@ -3,12 +3,12 @@ package com.hmf import org.junit.jupiter.api.Test import kotlin.test.assertEquals -class StubOpponent(val element: Element) : ICanPlay { +class StubOpponent(val element: Element) : IOpponent { override fun play(): Element { return element; } } -class StubOutputter : ICanPrint { +class StubOutputter : IOutputter { override fun printOutcome(roundOutcome: Outcome, player: Element, opponent: Element) {} override fun printStats(stats: GameResult) {} } From 1696c605f2ecea0961feec70e3418b8d4660c30f Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 13:46:56 +0200 Subject: [PATCH 10/12] bug fix, removed buggy enum elem and refactored play method of Game class --- src/main/kotlin/com/hmf/Element.kt | 2 +- src/main/kotlin/com/hmf/Game.kt | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/hmf/Element.kt b/src/main/kotlin/com/hmf/Element.kt index 7838eda..b1ba12b 100644 --- a/src/main/kotlin/com/hmf/Element.kt +++ b/src/main/kotlin/com/hmf/Element.kt @@ -1,5 +1,5 @@ package com.hmf enum class Element(val idx: Int){ - NONE(-1), ROCK(0), PAPER(1), SCISSORS(2) + ROCK(0), PAPER(1), SCISSORS(2) } diff --git a/src/main/kotlin/com/hmf/Game.kt b/src/main/kotlin/com/hmf/Game.kt index 1202426..0844995 100644 --- a/src/main/kotlin/com/hmf/Game.kt +++ b/src/main/kotlin/com/hmf/Game.kt @@ -34,24 +34,20 @@ class Game { fun play(){ var stopPlaying = false while (!stopPlaying) { - var userInput = Element.NONE print("Choose your input:\n'0' for ROCK\n'1' for PAPER\n'2' for SCISSORS\n'x' to stop\n -> ") - when (scanner.next().single()) { - '0' -> userInput = Element.ROCK - '1' -> userInput = Element.PAPER - '2' -> userInput = Element.SCISSORS + val userInput = when (scanner.next().single()) { + '0' -> Element.ROCK + '1' -> Element.PAPER + '2' -> Element.SCISSORS 'x' -> { - stopPlaying = true + outputter.printStats(getStats()) + break } else -> { println("Invalid input, fat fingers? Try again!") continue } } - if (stopPlaying){ - outputter.printStats(getStats()) - break - } playRound(userInput) } } From 566b6e902a842f1f46c65fcf9793a2269d799c2f Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 14:46:54 +0200 Subject: [PATCH 11/12] clean up --- src/main/kotlin/com/hmf/GameRules.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/hmf/GameRules.kt b/src/main/kotlin/com/hmf/GameRules.kt index 2104860..9c7bf56 100644 --- a/src/main/kotlin/com/hmf/GameRules.kt +++ b/src/main/kotlin/com/hmf/GameRules.kt @@ -3,7 +3,7 @@ package com.hmf class GameRules { private val rules: Array> = arrayOf( - arrayOf(Outcome.DRAW, Outcome.PLAYER_LOST, Outcome.PLAYER_WON), // we can also use shortArrayOf or doubleArrayOf... + arrayOf(Outcome.DRAW, Outcome.PLAYER_LOST, Outcome.PLAYER_WON), arrayOf(Outcome.PLAYER_WON, Outcome.DRAW, Outcome.PLAYER_LOST), arrayOf(Outcome.PLAYER_LOST, Outcome.PLAYER_WON, Outcome.DRAW) ) From 3451e7a61af187f63a9c9cf423174a99236478da Mon Sep 17 00:00:00 2001 From: Vlad Sergeev Date: Mon, 25 Sep 2023 14:52:25 +0200 Subject: [PATCH 12/12] a bit of protection against index out of bounds issues --- src/main/kotlin/com/hmf/GameRules.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/com/hmf/GameRules.kt b/src/main/kotlin/com/hmf/GameRules.kt index 9c7bf56..94cdf96 100644 --- a/src/main/kotlin/com/hmf/GameRules.kt +++ b/src/main/kotlin/com/hmf/GameRules.kt @@ -9,6 +9,8 @@ class GameRules { ) fun getOutcome(player: Element, opponent: Element): Outcome { + require(player.idx in 0..2) + require(opponent.idx in 0..2) return rules[player.idx][opponent.idx] } }