From 533fe6bf42643b1109813819c0a0135b64a3a2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 18:18:36 +0900 Subject: [PATCH 01/49] =?UTF-8?q?=20:=20=EB=AC=B8=EC=9E=90=EC=97=B4?= =?UTF-8?q?=20=EA=B3=84=EC=82=B0=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/StringCalculator.kt | 89 +++++++++++++++++++++++ src/test/kotlin/PersonKoTest.kt | 28 ++++++++ src/test/kotlin/StringCalculatorTest.kt | 95 +++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 src/main/kotlin/StringCalculator.kt create mode 100644 src/test/kotlin/PersonKoTest.kt create mode 100644 src/test/kotlin/StringCalculatorTest.kt diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt new file mode 100644 index 0000000000..b251c53f8c --- /dev/null +++ b/src/main/kotlin/StringCalculator.kt @@ -0,0 +1,89 @@ +import java.util.LinkedList +import java.util.Queue + +class StringCalculator { + + enum class Operator(val sign: Char) { + PLUS('+'), + MINUS('-'), + MULTIPLY('*'), + DIVIDE('/'); + } + + fun calculate(input: String): Int { + + if (input.isNullOrEmpty()) { + throw IllegalArgumentException() + } + + var data = input.replace(" ", "") + val sortedPriorityList = priorityIndexes(data) + val queue = createOperandAndOperatorQueue(data, sortedPriorityList) + + var result: Int = Integer.parseInt(queue.poll()) + + if (queue.size % 2 != 0) { + throw IllegalStateException() + } + + while (!queue.isEmpty()) { + val operator = queue.poll() + val operand = queue.poll() + + when (operator.first()) { + Operator.PLUS.sign -> result += Integer.parseInt(operand) + Operator.MINUS.sign -> result -= Integer.parseInt(operand) + Operator.MULTIPLY.sign -> result *= Integer.parseInt(operand) + Operator.DIVIDE.sign -> result /= Integer.parseInt(operand) + } + } + + return result + } + + private fun verifyOperator(data: String) { + // 80 ~ 89 제외한 나머지 + for (c in data) { + for (operator in Operator.values()) { + if (c == operator.sign) { + continue + } + } + if (c < 80.toChar() || c > 89.toChar()) { + throw IllegalArgumentException() + } + } + } + + private fun priorityIndexes(data: String): List> { + val priorityList = mutableListOf>() + + for (operator in Operator.values()) { + val index = data.indexOfFirst { c -> c == operator.sign } + if (index > -1) { + val pair: Pair = Pair(operator.sign, index) + priorityList.add(pair) + } + } + + return priorityList.sortedBy { pair -> pair.second } + } + + private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { + + var temp = data + val queue = LinkedList() + + for (pair in sortedPriorityList) { + val operand = temp.substringBefore(pair.first.toString()) + if (!operand.isNullOrEmpty()) { + queue.add(operand) + queue.add(pair.first.toString()) + temp = temp.substringAfter(pair.first.toString()) + } + } + + queue.add(temp) + return queue + } +} diff --git a/src/test/kotlin/PersonKoTest.kt b/src/test/kotlin/PersonKoTest.kt new file mode 100644 index 0000000000..9ace9d4db6 --- /dev/null +++ b/src/test/kotlin/PersonKoTest.kt @@ -0,0 +1,28 @@ +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.shouldBe + +class PersonKoTest : StringSpec({ + "이름 붙인 인자" { + val person = Person(name = "이정환", age = 31, nickname = "열정환") + person.name shouldBe "이정환" + person.age shouldBe 31 + person.nickname shouldBe "열정환" + } + + "널 타입" { + val person = Person(name = "이정환", age = 31, null) + person.nickname.shouldBeNull() + } + + "기본 인자" { + val person = Person(name = "이정환", age = 31) + person.name shouldBe person.nickname + } + + "데이터 클래스" { + val person1 = Person("이정환", 31) + val person2 = Person("이정환", 31) + person1 shouldBe person2 + } +}) diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/StringCalculatorTest.kt new file mode 100644 index 0000000000..8b74040aea --- /dev/null +++ b/src/test/kotlin/StringCalculatorTest.kt @@ -0,0 +1,95 @@ +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class StringCalculatorTest { + + @Test + fun `문자열 자르기`() { + + val input = "1234-5678-9000" + + val substringBefore = input.substringBefore("-") + val substringAfter = input.substringAfter("-") + + assertThat(substringBefore).isEqualTo("1234") + assertThat(substringAfter).isEqualTo("5678-9000") + } + + @Test + fun `인덱스 가져오기`() { + + var input = "2 + 3 * 4 / 2" + input = input.replace(" ", "") + val index = input.indexOfFirst { c -> c == StringCalculator.Operator.PLUS.sign } + assertThat(index).isEqualTo(1) + } + + @Test + fun `덧셈`() { + val input = "2 + 3" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(5) + } + + @Test + fun `뺄셈`() { + + val input = "3 - 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(1) + } + + @Test + fun `곱셈`() { + + val input = "2 * 4" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(8) + } + + @Test + fun `나눗셈`() { + + val input = "4 / 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(2) + } + + @ParameterizedTest + @ValueSource(strings = ["", " "]) + fun `입력값이 null 이거나 빈 공백문자 일경우`(input: String) { + + val stringCalculator = StringCalculator() + + assertThrows { + stringCalculator.calculate(input) + } + } + + @Test + fun `사칙연산 기호가 아닌경우`() { + + val input = "2 ! 3 * 4 / 2" + val stringCalculator = StringCalculator() + assertThrows { + stringCalculator.calculate(input) + } + } + + @Test + fun `사칙연산 기능 구현`() { + + val input = "2 + 3 * 4 / 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + + assertThat(result).isEqualTo(10) + } +} From 3e9696799a92442b4194a4cca0982910dc245bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 19:58:35 +0900 Subject: [PATCH 02/49] =?UTF-8?q?=20:=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81(Operator=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Operator.kt | 29 +++++++++++++++++++++++++ src/main/kotlin/StringCalculator.kt | 28 ++++++++++-------------- src/test/kotlin/StringCalculatorTest.kt | 2 +- 3 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/Operator.kt diff --git a/src/main/kotlin/Operator.kt b/src/main/kotlin/Operator.kt new file mode 100644 index 0000000000..e49a6faafe --- /dev/null +++ b/src/main/kotlin/Operator.kt @@ -0,0 +1,29 @@ +enum class Operator(val sign: Char) { + PLUS('+') { + override fun calculate(a: Int, b: Int): Int = a + b + }, + MINUS('-') { + override fun calculate(a: Int, b: Int): Int = a - b + }, + MULTIPLY('*') { + override fun calculate(a: Int, b: Int): Int = a * b + }, + DIVIDE('/') { + override fun calculate(a: Int, b: Int): Int = a / b + }; + + abstract fun calculate(a: Int, b: Int): Int + + fun equals(sign: Char): Boolean = this.sign == sign + + companion object { + operator fun invoke(sign: Char): Operator { + for (operator in Operator.values()) { + if (operator.sign == sign) { + return operator + } + } + throw IllegalArgumentException() + } + } +} diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt index b251c53f8c..053c9600b7 100644 --- a/src/main/kotlin/StringCalculator.kt +++ b/src/main/kotlin/StringCalculator.kt @@ -3,13 +3,6 @@ import java.util.Queue class StringCalculator { - enum class Operator(val sign: Char) { - PLUS('+'), - MINUS('-'), - MULTIPLY('*'), - DIVIDE('/'); - } - fun calculate(input: String): Int { if (input.isNullOrEmpty()) { @@ -17,6 +10,7 @@ class StringCalculator { } var data = input.replace(" ", "") + verifyOperator(data) val sortedPriorityList = priorityIndexes(data) val queue = createOperandAndOperatorQueue(data, sortedPriorityList) @@ -30,11 +24,11 @@ class StringCalculator { val operator = queue.poll() val operand = queue.poll() - when (operator.first()) { - Operator.PLUS.sign -> result += Integer.parseInt(operand) - Operator.MINUS.sign -> result -= Integer.parseInt(operand) - Operator.MULTIPLY.sign -> result *= Integer.parseInt(operand) - Operator.DIVIDE.sign -> result /= Integer.parseInt(operand) + result = when (Operator(operator.first())) { + Operator.PLUS -> Operator.PLUS.calculate(result, Integer.parseInt(operand)) + Operator.MINUS -> Operator.MINUS.calculate(result, Integer.parseInt(operand)) + Operator.MULTIPLY -> Operator.MULTIPLY.calculate(result, Integer.parseInt(operand)) + Operator.DIVIDE -> Operator.DIVIDE.calculate(result, Integer.parseInt(operand)) } } @@ -42,14 +36,14 @@ class StringCalculator { } private fun verifyOperator(data: String) { - // 80 ~ 89 제외한 나머지 for (c in data) { + var isOperator = false for (operator in Operator.values()) { - if (c == operator.sign) { - continue + if (operator.equals(c)) { + isOperator = true } } - if (c < 80.toChar() || c > 89.toChar()) { + if (!isOperator && (c < 48.toChar() || c > 57.toChar())) { throw IllegalArgumentException() } } @@ -59,7 +53,7 @@ class StringCalculator { val priorityList = mutableListOf>() for (operator in Operator.values()) { - val index = data.indexOfFirst { c -> c == operator.sign } + val index = data.indexOfFirst { c -> operator.equals(c) } if (index > -1) { val pair: Pair = Pair(operator.sign, index) priorityList.add(pair) diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/StringCalculatorTest.kt index 8b74040aea..41a6f77acf 100644 --- a/src/test/kotlin/StringCalculatorTest.kt +++ b/src/test/kotlin/StringCalculatorTest.kt @@ -23,7 +23,7 @@ class StringCalculatorTest { var input = "2 + 3 * 4 / 2" input = input.replace(" ", "") - val index = input.indexOfFirst { c -> c == StringCalculator.Operator.PLUS.sign } + val index = input.indexOfFirst { c -> Operator.PLUS.equals(c) } assertThat(index).isEqualTo(1) } From 34561c36ccb8d174cc4b9d9d2759e3371bc7d83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 20:02:19 +0900 Subject: [PATCH 03/49] =?UTF-8?q?=20:=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/StringCalculator.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt index 053c9600b7..f24b553c25 100644 --- a/src/main/kotlin/StringCalculator.kt +++ b/src/main/kotlin/StringCalculator.kt @@ -24,12 +24,8 @@ class StringCalculator { val operator = queue.poll() val operand = queue.poll() - result = when (Operator(operator.first())) { - Operator.PLUS -> Operator.PLUS.calculate(result, Integer.parseInt(operand)) - Operator.MINUS -> Operator.MINUS.calculate(result, Integer.parseInt(operand)) - Operator.MULTIPLY -> Operator.MULTIPLY.calculate(result, Integer.parseInt(operand)) - Operator.DIVIDE -> Operator.DIVIDE.calculate(result, Integer.parseInt(operand)) - } + val o = Operator(operator.first()) + result = o.calculate(result, Integer.parseInt(operand)) } return result From 7459316169826ac7dbea92d3b58b30e70caeb1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 20:50:11 +0900 Subject: [PATCH 04/49] =?UTF-8?q?=20:=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81,=20?= =?UTF-8?q?=ED=91=9C=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/.gitkeep | 0 src/main/kotlin/StringCalculator.kt | 79 ------------------- src/main/kotlin/calculator/Expression.kt | 46 +++++++++++ src/main/kotlin/{ => calculator}/Operator.kt | 2 + .../kotlin/calculator/StringCalculator.kt | 50 ++++++++++++ src/test/kotlin/.gitkeep | 0 .../{ => calculator}/StringCalculatorTest.kt | 8 +- 7 files changed, 103 insertions(+), 82 deletions(-) delete mode 100644 src/main/kotlin/.gitkeep delete mode 100644 src/main/kotlin/StringCalculator.kt create mode 100644 src/main/kotlin/calculator/Expression.kt rename src/main/kotlin/{ => calculator}/Operator.kt (97%) create mode 100644 src/main/kotlin/calculator/StringCalculator.kt delete mode 100644 src/test/kotlin/.gitkeep rename src/test/kotlin/{ => calculator}/StringCalculatorTest.kt (93%) diff --git a/src/main/kotlin/.gitkeep b/src/main/kotlin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt deleted file mode 100644 index f24b553c25..0000000000 --- a/src/main/kotlin/StringCalculator.kt +++ /dev/null @@ -1,79 +0,0 @@ -import java.util.LinkedList -import java.util.Queue - -class StringCalculator { - - fun calculate(input: String): Int { - - if (input.isNullOrEmpty()) { - throw IllegalArgumentException() - } - - var data = input.replace(" ", "") - verifyOperator(data) - val sortedPriorityList = priorityIndexes(data) - val queue = createOperandAndOperatorQueue(data, sortedPriorityList) - - var result: Int = Integer.parseInt(queue.poll()) - - if (queue.size % 2 != 0) { - throw IllegalStateException() - } - - while (!queue.isEmpty()) { - val operator = queue.poll() - val operand = queue.poll() - - val o = Operator(operator.first()) - result = o.calculate(result, Integer.parseInt(operand)) - } - - return result - } - - private fun verifyOperator(data: String) { - for (c in data) { - var isOperator = false - for (operator in Operator.values()) { - if (operator.equals(c)) { - isOperator = true - } - } - if (!isOperator && (c < 48.toChar() || c > 57.toChar())) { - throw IllegalArgumentException() - } - } - } - - private fun priorityIndexes(data: String): List> { - val priorityList = mutableListOf>() - - for (operator in Operator.values()) { - val index = data.indexOfFirst { c -> operator.equals(c) } - if (index > -1) { - val pair: Pair = Pair(operator.sign, index) - priorityList.add(pair) - } - } - - return priorityList.sortedBy { pair -> pair.second } - } - - private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { - - var temp = data - val queue = LinkedList() - - for (pair in sortedPriorityList) { - val operand = temp.substringBefore(pair.first.toString()) - if (!operand.isNullOrEmpty()) { - queue.add(operand) - queue.add(pair.first.toString()) - temp = temp.substringAfter(pair.first.toString()) - } - } - - queue.add(temp) - return queue - } -} diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt new file mode 100644 index 0000000000..af4d342ecf --- /dev/null +++ b/src/main/kotlin/calculator/Expression.kt @@ -0,0 +1,46 @@ +package calculator + +import java.util.LinkedList +import java.util.Queue + +class Expression( + val input: String +) { + + fun apply(): Queue { + val sortedPriorityList = priorityIndexes(input) + return createOperandAndOperatorQueue(input, sortedPriorityList) + } + + private fun priorityIndexes(data: String): List> { + val priorityList = mutableListOf>() + + for (operator in Operator.values()) { + val index = data.indexOfFirst { c -> operator.equals(c) } + if (index > -1) { + val pair: Pair = Pair(operator.sign, index) + priorityList.add(pair) + } + } + + return priorityList.sortedBy { pair -> pair.second } + } + + private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { + + var temp = data + val queue = LinkedList() + + for (pair in sortedPriorityList) { + val operand = temp.substringBefore(pair.first.toString()) + if (!operand.isNullOrEmpty()) { + queue.add(operand) + queue.add(pair.first.toString()) + temp = temp.substringAfter(pair.first.toString()) + } + } + + queue.add(temp) + return queue + } +} diff --git a/src/main/kotlin/Operator.kt b/src/main/kotlin/calculator/Operator.kt similarity index 97% rename from src/main/kotlin/Operator.kt rename to src/main/kotlin/calculator/Operator.kt index e49a6faafe..66ad3fd0fb 100644 --- a/src/main/kotlin/Operator.kt +++ b/src/main/kotlin/calculator/Operator.kt @@ -1,3 +1,5 @@ +package calculator + enum class Operator(val sign: Char) { PLUS('+') { override fun calculate(a: Int, b: Int): Int = a + b diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt new file mode 100644 index 0000000000..d883dc778f --- /dev/null +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -0,0 +1,50 @@ +package calculator + +class StringCalculator { + + fun calculate(input: String): Int { + + if (input.isNullOrEmpty()) { + throw IllegalArgumentException() + } + + var data = input.replace(" ", "") + verifyOperator(data) + + val expression = Expression(data) + val queue = expression.apply() + + var result: Int = Integer.parseInt(queue.poll()) + + if (queue.size % 2 != 0) { + throw IllegalStateException() + } + + while (!queue.isEmpty()) { + val operator = queue.poll() + val operand = queue.poll() + + val o = Operator(operator.first()) + result = o.calculate(result, Integer.parseInt(operand)) + } + + return result + } + + private fun verifyOperator(data: String) { + // 2 * 3 + 1 - 1 = 7 중 피연산자 4, 연사자 3, 연사자로 스플릿한다면 피연산자는 4개나와야함 + val splitData = data.split("+", "-", "*", "/") + + if (splitData.size != data.length - (data.length / 2)) { + throw IllegalArgumentException() + } + + for (c in splitData) { + try { + Integer.parseInt(c) + } catch (e: NumberFormatException) { + throw IllegalArgumentException() + } + } + } +} diff --git a/src/test/kotlin/.gitkeep b/src/test/kotlin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt similarity index 93% rename from src/test/kotlin/StringCalculatorTest.kt rename to src/test/kotlin/calculator/StringCalculatorTest.kt index 41a6f77acf..93c1c45939 100644 --- a/src/test/kotlin/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -1,3 +1,5 @@ +package calculator + import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -73,10 +75,10 @@ class StringCalculatorTest { } } - @Test - fun `사칙연산 기호가 아닌경우`() { + @ParameterizedTest + @ValueSource(strings = ["2 ! 3 * 4 / 2", "23 * 22A * 1"]) + fun `사칙연산 기호가 아닌경우`(input: String) { - val input = "2 ! 3 * 4 / 2" val stringCalculator = StringCalculator() assertThrows { stringCalculator.calculate(input) From cf15a54967bd255e622bf84c7602885dd527ff86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Wed, 9 Nov 2022 00:59:38 +0900 Subject: [PATCH 05/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Expression.kt | 43 +++++++++++-------- src/main/kotlin/calculator/Num.kt | 14 ++++++ src/main/kotlin/calculator/Operator.kt | 21 ++++----- .../kotlin/calculator/StringCalculator.kt | 24 ++++------- .../kotlin/calculator/StringCalculatorTest.kt | 12 +++--- 5 files changed, 62 insertions(+), 52 deletions(-) create mode 100644 src/main/kotlin/calculator/Num.kt diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt index af4d342ecf..5349ac851f 100644 --- a/src/main/kotlin/calculator/Expression.kt +++ b/src/main/kotlin/calculator/Expression.kt @@ -8,36 +8,43 @@ class Expression( ) { fun apply(): Queue { - val sortedPriorityList = priorityIndexes(input) - return createOperandAndOperatorQueue(input, sortedPriorityList) + val queue = createOperandAndOperatorQueue(input) + if (queue.size % 2 == 0) throw IllegalArgumentException() + return queue } - private fun priorityIndexes(data: String): List> { - val priorityList = mutableListOf>() + private fun priorityIndexes(data: String): List { + val priorityList = mutableListOf() - for (operator in Operator.values()) { - val index = data.indexOfFirst { c -> operator.equals(c) } - if (index > -1) { - val pair: Pair = Pair(operator.sign, index) - priorityList.add(pair) + for (c in data) { + if (isOperatorLetter(c)) { + priorityList.add(c) } } - return priorityList.sortedBy { pair -> pair.second } + return priorityList + } + + private fun isOperatorLetter(c: Char): Boolean { + for (operator in Operator.values()) { + if (operator.isSame(c)) { + return true + } + } + return false } - private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { + private fun createOperandAndOperatorQueue(data: String): Queue { var temp = data + val sortedPriorityList = priorityIndexes(data) val queue = LinkedList() - for (pair in sortedPriorityList) { - val operand = temp.substringBefore(pair.first.toString()) - if (!operand.isNullOrEmpty()) { - queue.add(operand) - queue.add(pair.first.toString()) - temp = temp.substringAfter(pair.first.toString()) - } + for (operator in sortedPriorityList) { + val operand = temp.substringBefore(operator.toString()) + queue.add(operand) + queue.add(operator.toString()) + temp = temp.substringAfter(operator.toString()) } queue.add(temp) diff --git a/src/main/kotlin/calculator/Num.kt b/src/main/kotlin/calculator/Num.kt new file mode 100644 index 0000000000..fd2a916ce3 --- /dev/null +++ b/src/main/kotlin/calculator/Num.kt @@ -0,0 +1,14 @@ +package calculator + +data class Num(var value: Int) { + + constructor(value: String) : this(Integer.parseInt(value)) + + fun add(number: Num) = Num(this.value + number.value) + + fun sub(number: Num) = Num(this.value - number.value) + + fun multiply(number: Num) = Num(this.value * number.value) + + fun divide(number: Num) = Num(this.value / number.value) +} diff --git a/src/main/kotlin/calculator/Operator.kt b/src/main/kotlin/calculator/Operator.kt index 66ad3fd0fb..d147bb5c45 100644 --- a/src/main/kotlin/calculator/Operator.kt +++ b/src/main/kotlin/calculator/Operator.kt @@ -1,31 +1,26 @@ package calculator -enum class Operator(val sign: Char) { +enum class Operator(private val sign: Char) { PLUS('+') { - override fun calculate(a: Int, b: Int): Int = a + b + override fun calculate(a: Num, b: Num): Num = a.add(b) }, MINUS('-') { - override fun calculate(a: Int, b: Int): Int = a - b + override fun calculate(a: Num, b: Num): Num = a.sub(b) }, MULTIPLY('*') { - override fun calculate(a: Int, b: Int): Int = a * b + override fun calculate(a: Num, b: Num): Num = a.multiply(b) }, DIVIDE('/') { - override fun calculate(a: Int, b: Int): Int = a / b + override fun calculate(a: Num, b: Num): Num = a.divide(b) }; - abstract fun calculate(a: Int, b: Int): Int + abstract fun calculate(a: Num, b: Num): Num - fun equals(sign: Char): Boolean = this.sign == sign + fun isSame(sign: Char): Boolean = this.sign == sign companion object { operator fun invoke(sign: Char): Operator { - for (operator in Operator.values()) { - if (operator.sign == sign) { - return operator - } - } - throw IllegalArgumentException() + return values().first { o -> o.isSame(sign) } } } } diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt index d883dc778f..760be04360 100644 --- a/src/main/kotlin/calculator/StringCalculator.kt +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -2,37 +2,31 @@ package calculator class StringCalculator { - fun calculate(input: String): Int { + fun calculate(input: String): Num { - if (input.isNullOrEmpty()) { - throw IllegalArgumentException() - } - - var data = input.replace(" ", "") + val data = removeSpace(input) verifyOperator(data) val expression = Expression(data) val queue = expression.apply() - var result: Int = Integer.parseInt(queue.poll()) - - if (queue.size % 2 != 0) { - throw IllegalStateException() - } + var result = Num(queue.poll()) - while (!queue.isEmpty()) { + while (queue.isNotEmpty()) { val operator = queue.poll() val operand = queue.poll() - val o = Operator(operator.first()) - result = o.calculate(result, Integer.parseInt(operand)) + result = o.calculate(result, Num(operand)) } return result } + private fun removeSpace(input: String): String { + return input.replace(" ", "") + } + private fun verifyOperator(data: String) { - // 2 * 3 + 1 - 1 = 7 중 피연산자 4, 연사자 3, 연사자로 스플릿한다면 피연산자는 4개나와야함 val splitData = data.split("+", "-", "*", "/") if (splitData.size != data.length - (data.length / 2)) { diff --git a/src/test/kotlin/calculator/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt index 93c1c45939..e9ca3b8612 100644 --- a/src/test/kotlin/calculator/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -25,7 +25,7 @@ class StringCalculatorTest { var input = "2 + 3 * 4 / 2" input = input.replace(" ", "") - val index = input.indexOfFirst { c -> Operator.PLUS.equals(c) } + val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } assertThat(index).isEqualTo(1) } @@ -34,7 +34,7 @@ class StringCalculatorTest { val input = "2 + 3" val stringCalculator = StringCalculator() val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(5) + assertThat(result).isEqualTo(Num(5)) } @Test @@ -43,7 +43,7 @@ class StringCalculatorTest { val input = "3 - 2" val stringCalculator = StringCalculator() val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(1) + assertThat(result).isEqualTo(Num(1)) } @Test @@ -52,7 +52,7 @@ class StringCalculatorTest { val input = "2 * 4" val stringCalculator = StringCalculator() val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(8) + assertThat(result).isEqualTo(Num(8)) } @Test @@ -61,7 +61,7 @@ class StringCalculatorTest { val input = "4 / 2" val stringCalculator = StringCalculator() val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(2) + assertThat(result).isEqualTo(Num(2)) } @ParameterizedTest @@ -92,6 +92,6 @@ class StringCalculatorTest { val stringCalculator = StringCalculator() val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(10) + assertThat(result).isEqualTo(Num(10)) } } From ab71f37b77f7dd4e72247a6ab1c5fa5888d7db77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 12 Nov 2022 14:49:54 +0900 Subject: [PATCH 06/49] =?UTF-8?q?=20:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 3 +++ src/main/kotlin/racing/domain/CarFactory.kt | 10 +++++++ src/main/kotlin/racing/domain/Cars.kt | 27 +++++++++++++++++++ .../kotlin/racing/domain/RandomGenerator.kt | 8 ++++++ src/test/kotlin/racing/RacingGameTest.kt | 20 ++++++++++++++ src/test/kotlin/racing/RandomGeneratorTest.kt | 15 +++++++++++ 6 files changed, 83 insertions(+) create mode 100644 src/main/kotlin/racing/domain/Car.kt create mode 100644 src/main/kotlin/racing/domain/CarFactory.kt create mode 100644 src/main/kotlin/racing/domain/Cars.kt create mode 100644 src/main/kotlin/racing/domain/RandomGenerator.kt create mode 100644 src/test/kotlin/racing/RacingGameTest.kt create mode 100644 src/test/kotlin/racing/RandomGeneratorTest.kt diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt new file mode 100644 index 0000000000..510aa44f86 --- /dev/null +++ b/src/main/kotlin/racing/domain/Car.kt @@ -0,0 +1,3 @@ +package racing.domain + +data class Car(val name: String) diff --git a/src/main/kotlin/racing/domain/CarFactory.kt b/src/main/kotlin/racing/domain/CarFactory.kt new file mode 100644 index 0000000000..6c8dab7711 --- /dev/null +++ b/src/main/kotlin/racing/domain/CarFactory.kt @@ -0,0 +1,10 @@ +package racing.domain + +class CarFactory { + + companion object { + fun create(count: Int): Cars { + return Cars(count) + } + } +} diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt new file mode 100644 index 0000000000..fd98a73f22 --- /dev/null +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -0,0 +1,27 @@ +package racing.domain + +import java.util.stream.Collectors.toList +import java.util.stream.IntStream +import kotlin.streams.toList + +class Cars(count: Int, var index: Int = 0) : Iterator { + + private val list: List + + init { + list = IntStream.range(0, count) + .mapToObj { + Car(it.toString()) + }.collect(toList()) + } + + override fun hasNext(): Boolean { + return list.size > index + } + + override fun next(): Car { + return list[index++] + } + + fun count() = list.size +} diff --git a/src/main/kotlin/racing/domain/RandomGenerator.kt b/src/main/kotlin/racing/domain/RandomGenerator.kt new file mode 100644 index 0000000000..ea14764c50 --- /dev/null +++ b/src/main/kotlin/racing/domain/RandomGenerator.kt @@ -0,0 +1,8 @@ +package racing.domain + +class RandomGenerator { + + companion object { + fun generate(): Int = (1..9).random() + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt new file mode 100644 index 0000000000..4579dff3e7 --- /dev/null +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -0,0 +1,20 @@ +package racing + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import racing.domain.CarFactory +import racing.domain.Cars + +class RacingGameTest { + + @Test + fun `자동차 생성`() { + val cars: Cars = CarFactory.create(3) + assertThat(cars.count()).isEqualTo(3) + } + + @Test + fun `레이싱 결과`() { + ㅣ + } +} diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt new file mode 100644 index 0000000000..1124e0a555 --- /dev/null +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -0,0 +1,15 @@ +package racing + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import racing.domain.RandomGenerator + +class RandomGeneratorTest { + + @Test + fun `랜덤숫자 발행 테스트`() { + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThan(0) + assertThat(randomNumber).isLessThan(10) + } +} From 400f6b21ff4a8ddde5a92a85588e3e05bfc58fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 12 Nov 2022 16:00:14 +0900 Subject: [PATCH 07/49] =?UTF-8?q?=20:=20racing=20game=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../racing/application/RacingGameService.kt | 11 +++++++ src/main/kotlin/racing/domain/Car.kt | 12 ++++++- src/main/kotlin/racing/domain/Cars.kt | 22 +++++++------ src/main/kotlin/racing/domain/RacingGame.kt | 28 +++++++++++++++++ .../kotlin/racing/domain/ResultStatistics.kt | 14 +++++++++ src/main/kotlin/racing/domain/Route.kt | 3 ++ src/main/kotlin/racing/domain/Routes.kt | 13 ++++++++ src/main/kotlin/racing/ui/InputView.kt | 8 +++++ src/main/kotlin/racing/ui/ResultView.kt | 19 ++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 31 +++++++++++++++++-- src/test/kotlin/racing/RandomGeneratorTest.kt | 4 +-- 11 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/racing/application/RacingGameService.kt create mode 100644 src/main/kotlin/racing/domain/RacingGame.kt create mode 100644 src/main/kotlin/racing/domain/ResultStatistics.kt create mode 100644 src/main/kotlin/racing/domain/Route.kt create mode 100644 src/main/kotlin/racing/domain/Routes.kt create mode 100644 src/main/kotlin/racing/ui/InputView.kt create mode 100644 src/main/kotlin/racing/ui/ResultView.kt diff --git a/src/main/kotlin/racing/application/RacingGameService.kt b/src/main/kotlin/racing/application/RacingGameService.kt new file mode 100644 index 0000000000..a303b10de7 --- /dev/null +++ b/src/main/kotlin/racing/application/RacingGameService.kt @@ -0,0 +1,11 @@ +package racing.application + +import racing.domain.RacingGame + +class RacingGameService { + + fun main() { + val racingGame = RacingGame() + racingGame.start() + } +} diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 510aa44f86..bcd78e76d7 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,3 +1,13 @@ package racing.domain -data class Car(val name: String) +data class Car(val name: String) { + + private val routes = Routes() + fun move(num: Int) { + when (num) { + in 4..9 -> routes.add() + } + } + + fun routes() = routes +} diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index fd98a73f22..6a2e45c978 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,10 +1,9 @@ package racing.domain -import java.util.stream.Collectors.toList import java.util.stream.IntStream import kotlin.streams.toList -class Cars(count: Int, var index: Int = 0) : Iterator { +class Cars(count: Int) : Iterable { private val list: List @@ -12,16 +11,19 @@ class Cars(count: Int, var index: Int = 0) : Iterator { list = IntStream.range(0, count) .mapToObj { Car(it.toString()) - }.collect(toList()) + }.toList() } - override fun hasNext(): Boolean { - return list.size > index - } - - override fun next(): Car { - return list[index++] - } + // override fun hasNext(): Boolean { + // return list.size > index + // } + // + // override fun next(): Car { + // return list[index++] + // } fun count() = list.size + override fun iterator(): Iterator { + return list.iterator() + } } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt new file mode 100644 index 0000000000..3560aff779 --- /dev/null +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -0,0 +1,28 @@ +package racing.domain + +import racing.ui.InputView +import racing.ui.ResultView + +class RacingGame { + + fun start() { + + ResultView.requireCarsCount() + val cars = Cars(InputView.inputNumber()) + + ResultView.requireNumberOfGames() + var count = InputView.inputNumber() + + while (count-- > 0) { + turn(cars) + } + + ResultView.printGameResult(ResultStatistics(cars).toResult()) + } + + fun turn(cars: Cars) { + for (car in cars) { + car.move(RandomGenerator.generate()) + } + } +} diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt new file mode 100644 index 0000000000..02108d8c87 --- /dev/null +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -0,0 +1,14 @@ +package racing.domain + +import kotlin.streams.asSequence + +class ResultStatistics(private val cars: Cars) { + + fun toResult(): String { + val stringBuilder = StringBuilder() + for (car in cars) { + stringBuilder.appendLine(car.routes().stream().map { "-" }.asSequence().joinToString("")) + } + return stringBuilder.toString() + } +} diff --git a/src/main/kotlin/racing/domain/Route.kt b/src/main/kotlin/racing/domain/Route.kt new file mode 100644 index 0000000000..69bdc95d03 --- /dev/null +++ b/src/main/kotlin/racing/domain/Route.kt @@ -0,0 +1,3 @@ +package racing.domain + +class Route() diff --git a/src/main/kotlin/racing/domain/Routes.kt b/src/main/kotlin/racing/domain/Routes.kt new file mode 100644 index 0000000000..c9fd56ec0c --- /dev/null +++ b/src/main/kotlin/racing/domain/Routes.kt @@ -0,0 +1,13 @@ +package racing.domain + +class Routes { + + private val list = mutableListOf() + + fun add() { + list.add(Route()) + } + + fun stream() = list.stream() + fun size() = list.size +} diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt new file mode 100644 index 0000000000..e73ed43f53 --- /dev/null +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -0,0 +1,8 @@ +package racing.ui + +class InputView { + + companion object { + fun inputNumber() = readLine()!!.toInt() + } +} diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt new file mode 100644 index 0000000000..0850bfd21c --- /dev/null +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -0,0 +1,19 @@ +package racing.ui + +class ResultView { + + companion object { + fun requireCarsCount() { + println("자동차 대수는 몇 대인가요?") + } + + fun requireNumberOfGames() { + println("시도할 횟수는 몇 회인가요?") + } + + fun printGameResult(result: String) { + println("실행결과") + println(result) + } + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4579dff3e7..85181f66fd 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -2,8 +2,11 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import racing.domain.CarFactory import racing.domain.Cars +import racing.domain.ResultStatistics class RacingGameTest { @@ -13,8 +16,32 @@ class RacingGameTest { assertThat(cars.count()).isEqualTo(3) } + @ParameterizedTest + @ValueSource(ints = [4, 9]) + fun `자동차 이동`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars) { + car.move(num) + assertThat(car.routes().size()).isEqualTo(1) + } + } + + @ParameterizedTest + @ValueSource(ints = [0, 3]) + fun `자동차 이동실패`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars) { + car.move(num) + assertThat(car.routes().size()).isEqualTo(0) + } + } + @Test - fun `레이싱 결과`() { - ㅣ + fun `실행결과 출력`() { + val cars: Cars = CarFactory.create(1) + for (car in cars) { + car.move(4) + } + assertThat(ResultStatistics(cars).toResult()).isEqualTo("-\n") } } diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index 1124e0a555..4f85a7a4db 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -9,7 +9,7 @@ class RandomGeneratorTest { @Test fun `랜덤숫자 발행 테스트`() { val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThan(0) - assertThat(randomNumber).isLessThan(10) + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) } } From 76b3eed60b712b6b04fbd03871d9b8976d58af0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 18:18:36 +0900 Subject: [PATCH 08/49] =?UTF-8?q?=20:=20=EB=AC=B8=EC=9E=90=EC=97=B4?= =?UTF-8?q?=20=EA=B3=84=EC=82=B0=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/StringCalculator.kt | 89 +++++++++++++++++++++++ src/test/kotlin/StringCalculatorTest.kt | 95 +++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 src/main/kotlin/StringCalculator.kt create mode 100644 src/test/kotlin/StringCalculatorTest.kt diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt new file mode 100644 index 0000000000..b251c53f8c --- /dev/null +++ b/src/main/kotlin/StringCalculator.kt @@ -0,0 +1,89 @@ +import java.util.LinkedList +import java.util.Queue + +class StringCalculator { + + enum class Operator(val sign: Char) { + PLUS('+'), + MINUS('-'), + MULTIPLY('*'), + DIVIDE('/'); + } + + fun calculate(input: String): Int { + + if (input.isNullOrEmpty()) { + throw IllegalArgumentException() + } + + var data = input.replace(" ", "") + val sortedPriorityList = priorityIndexes(data) + val queue = createOperandAndOperatorQueue(data, sortedPriorityList) + + var result: Int = Integer.parseInt(queue.poll()) + + if (queue.size % 2 != 0) { + throw IllegalStateException() + } + + while (!queue.isEmpty()) { + val operator = queue.poll() + val operand = queue.poll() + + when (operator.first()) { + Operator.PLUS.sign -> result += Integer.parseInt(operand) + Operator.MINUS.sign -> result -= Integer.parseInt(operand) + Operator.MULTIPLY.sign -> result *= Integer.parseInt(operand) + Operator.DIVIDE.sign -> result /= Integer.parseInt(operand) + } + } + + return result + } + + private fun verifyOperator(data: String) { + // 80 ~ 89 제외한 나머지 + for (c in data) { + for (operator in Operator.values()) { + if (c == operator.sign) { + continue + } + } + if (c < 80.toChar() || c > 89.toChar()) { + throw IllegalArgumentException() + } + } + } + + private fun priorityIndexes(data: String): List> { + val priorityList = mutableListOf>() + + for (operator in Operator.values()) { + val index = data.indexOfFirst { c -> c == operator.sign } + if (index > -1) { + val pair: Pair = Pair(operator.sign, index) + priorityList.add(pair) + } + } + + return priorityList.sortedBy { pair -> pair.second } + } + + private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { + + var temp = data + val queue = LinkedList() + + for (pair in sortedPriorityList) { + val operand = temp.substringBefore(pair.first.toString()) + if (!operand.isNullOrEmpty()) { + queue.add(operand) + queue.add(pair.first.toString()) + temp = temp.substringAfter(pair.first.toString()) + } + } + + queue.add(temp) + return queue + } +} diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/StringCalculatorTest.kt new file mode 100644 index 0000000000..8b74040aea --- /dev/null +++ b/src/test/kotlin/StringCalculatorTest.kt @@ -0,0 +1,95 @@ +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class StringCalculatorTest { + + @Test + fun `문자열 자르기`() { + + val input = "1234-5678-9000" + + val substringBefore = input.substringBefore("-") + val substringAfter = input.substringAfter("-") + + assertThat(substringBefore).isEqualTo("1234") + assertThat(substringAfter).isEqualTo("5678-9000") + } + + @Test + fun `인덱스 가져오기`() { + + var input = "2 + 3 * 4 / 2" + input = input.replace(" ", "") + val index = input.indexOfFirst { c -> c == StringCalculator.Operator.PLUS.sign } + assertThat(index).isEqualTo(1) + } + + @Test + fun `덧셈`() { + val input = "2 + 3" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(5) + } + + @Test + fun `뺄셈`() { + + val input = "3 - 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(1) + } + + @Test + fun `곱셈`() { + + val input = "2 * 4" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(8) + } + + @Test + fun `나눗셈`() { + + val input = "4 / 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + assertThat(result).isEqualTo(2) + } + + @ParameterizedTest + @ValueSource(strings = ["", " "]) + fun `입력값이 null 이거나 빈 공백문자 일경우`(input: String) { + + val stringCalculator = StringCalculator() + + assertThrows { + stringCalculator.calculate(input) + } + } + + @Test + fun `사칙연산 기호가 아닌경우`() { + + val input = "2 ! 3 * 4 / 2" + val stringCalculator = StringCalculator() + assertThrows { + stringCalculator.calculate(input) + } + } + + @Test + fun `사칙연산 기능 구현`() { + + val input = "2 + 3 * 4 / 2" + val stringCalculator = StringCalculator() + val result = stringCalculator.calculate(input) + + assertThat(result).isEqualTo(10) + } +} From 61eca99161abb2476f1050635dfdfe75602b5b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 19:58:35 +0900 Subject: [PATCH 09/49] =?UTF-8?q?=20:=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81(Operator=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Operator.kt | 29 +++++++++++++++++++++++++ src/main/kotlin/StringCalculator.kt | 28 ++++++++++-------------- src/test/kotlin/StringCalculatorTest.kt | 2 +- 3 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/Operator.kt diff --git a/src/main/kotlin/Operator.kt b/src/main/kotlin/Operator.kt new file mode 100644 index 0000000000..e49a6faafe --- /dev/null +++ b/src/main/kotlin/Operator.kt @@ -0,0 +1,29 @@ +enum class Operator(val sign: Char) { + PLUS('+') { + override fun calculate(a: Int, b: Int): Int = a + b + }, + MINUS('-') { + override fun calculate(a: Int, b: Int): Int = a - b + }, + MULTIPLY('*') { + override fun calculate(a: Int, b: Int): Int = a * b + }, + DIVIDE('/') { + override fun calculate(a: Int, b: Int): Int = a / b + }; + + abstract fun calculate(a: Int, b: Int): Int + + fun equals(sign: Char): Boolean = this.sign == sign + + companion object { + operator fun invoke(sign: Char): Operator { + for (operator in Operator.values()) { + if (operator.sign == sign) { + return operator + } + } + throw IllegalArgumentException() + } + } +} diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt index b251c53f8c..053c9600b7 100644 --- a/src/main/kotlin/StringCalculator.kt +++ b/src/main/kotlin/StringCalculator.kt @@ -3,13 +3,6 @@ import java.util.Queue class StringCalculator { - enum class Operator(val sign: Char) { - PLUS('+'), - MINUS('-'), - MULTIPLY('*'), - DIVIDE('/'); - } - fun calculate(input: String): Int { if (input.isNullOrEmpty()) { @@ -17,6 +10,7 @@ class StringCalculator { } var data = input.replace(" ", "") + verifyOperator(data) val sortedPriorityList = priorityIndexes(data) val queue = createOperandAndOperatorQueue(data, sortedPriorityList) @@ -30,11 +24,11 @@ class StringCalculator { val operator = queue.poll() val operand = queue.poll() - when (operator.first()) { - Operator.PLUS.sign -> result += Integer.parseInt(operand) - Operator.MINUS.sign -> result -= Integer.parseInt(operand) - Operator.MULTIPLY.sign -> result *= Integer.parseInt(operand) - Operator.DIVIDE.sign -> result /= Integer.parseInt(operand) + result = when (Operator(operator.first())) { + Operator.PLUS -> Operator.PLUS.calculate(result, Integer.parseInt(operand)) + Operator.MINUS -> Operator.MINUS.calculate(result, Integer.parseInt(operand)) + Operator.MULTIPLY -> Operator.MULTIPLY.calculate(result, Integer.parseInt(operand)) + Operator.DIVIDE -> Operator.DIVIDE.calculate(result, Integer.parseInt(operand)) } } @@ -42,14 +36,14 @@ class StringCalculator { } private fun verifyOperator(data: String) { - // 80 ~ 89 제외한 나머지 for (c in data) { + var isOperator = false for (operator in Operator.values()) { - if (c == operator.sign) { - continue + if (operator.equals(c)) { + isOperator = true } } - if (c < 80.toChar() || c > 89.toChar()) { + if (!isOperator && (c < 48.toChar() || c > 57.toChar())) { throw IllegalArgumentException() } } @@ -59,7 +53,7 @@ class StringCalculator { val priorityList = mutableListOf>() for (operator in Operator.values()) { - val index = data.indexOfFirst { c -> c == operator.sign } + val index = data.indexOfFirst { c -> operator.equals(c) } if (index > -1) { val pair: Pair = Pair(operator.sign, index) priorityList.add(pair) diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/StringCalculatorTest.kt index 8b74040aea..41a6f77acf 100644 --- a/src/test/kotlin/StringCalculatorTest.kt +++ b/src/test/kotlin/StringCalculatorTest.kt @@ -23,7 +23,7 @@ class StringCalculatorTest { var input = "2 + 3 * 4 / 2" input = input.replace(" ", "") - val index = input.indexOfFirst { c -> c == StringCalculator.Operator.PLUS.sign } + val index = input.indexOfFirst { c -> Operator.PLUS.equals(c) } assertThat(index).isEqualTo(1) } From 2f8da7497dec9e2ba64260c9bf540c050b1b644e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 20:02:19 +0900 Subject: [PATCH 10/49] =?UTF-8?q?=20:=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/StringCalculator.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt index 053c9600b7..f24b553c25 100644 --- a/src/main/kotlin/StringCalculator.kt +++ b/src/main/kotlin/StringCalculator.kt @@ -24,12 +24,8 @@ class StringCalculator { val operator = queue.poll() val operand = queue.poll() - result = when (Operator(operator.first())) { - Operator.PLUS -> Operator.PLUS.calculate(result, Integer.parseInt(operand)) - Operator.MINUS -> Operator.MINUS.calculate(result, Integer.parseInt(operand)) - Operator.MULTIPLY -> Operator.MULTIPLY.calculate(result, Integer.parseInt(operand)) - Operator.DIVIDE -> Operator.DIVIDE.calculate(result, Integer.parseInt(operand)) - } + val o = Operator(operator.first()) + result = o.calculate(result, Integer.parseInt(operand)) } return result From 34bf39a1d817e5ade8aa49cefb7cf63922722011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 12 Nov 2022 14:49:54 +0900 Subject: [PATCH 11/49] =?UTF-8?q?=20:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 3 +++ src/main/kotlin/racing/domain/CarFactory.kt | 10 +++++++ src/main/kotlin/racing/domain/Cars.kt | 27 +++++++++++++++++++ .../kotlin/racing/domain/RandomGenerator.kt | 8 ++++++ src/test/kotlin/racing/RacingGameTest.kt | 20 ++++++++++++++ src/test/kotlin/racing/RandomGeneratorTest.kt | 15 +++++++++++ 6 files changed, 83 insertions(+) create mode 100644 src/main/kotlin/racing/domain/Car.kt create mode 100644 src/main/kotlin/racing/domain/CarFactory.kt create mode 100644 src/main/kotlin/racing/domain/Cars.kt create mode 100644 src/main/kotlin/racing/domain/RandomGenerator.kt create mode 100644 src/test/kotlin/racing/RacingGameTest.kt create mode 100644 src/test/kotlin/racing/RandomGeneratorTest.kt diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt new file mode 100644 index 0000000000..510aa44f86 --- /dev/null +++ b/src/main/kotlin/racing/domain/Car.kt @@ -0,0 +1,3 @@ +package racing.domain + +data class Car(val name: String) diff --git a/src/main/kotlin/racing/domain/CarFactory.kt b/src/main/kotlin/racing/domain/CarFactory.kt new file mode 100644 index 0000000000..6c8dab7711 --- /dev/null +++ b/src/main/kotlin/racing/domain/CarFactory.kt @@ -0,0 +1,10 @@ +package racing.domain + +class CarFactory { + + companion object { + fun create(count: Int): Cars { + return Cars(count) + } + } +} diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt new file mode 100644 index 0000000000..fd98a73f22 --- /dev/null +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -0,0 +1,27 @@ +package racing.domain + +import java.util.stream.Collectors.toList +import java.util.stream.IntStream +import kotlin.streams.toList + +class Cars(count: Int, var index: Int = 0) : Iterator { + + private val list: List + + init { + list = IntStream.range(0, count) + .mapToObj { + Car(it.toString()) + }.collect(toList()) + } + + override fun hasNext(): Boolean { + return list.size > index + } + + override fun next(): Car { + return list[index++] + } + + fun count() = list.size +} diff --git a/src/main/kotlin/racing/domain/RandomGenerator.kt b/src/main/kotlin/racing/domain/RandomGenerator.kt new file mode 100644 index 0000000000..ea14764c50 --- /dev/null +++ b/src/main/kotlin/racing/domain/RandomGenerator.kt @@ -0,0 +1,8 @@ +package racing.domain + +class RandomGenerator { + + companion object { + fun generate(): Int = (1..9).random() + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt new file mode 100644 index 0000000000..4579dff3e7 --- /dev/null +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -0,0 +1,20 @@ +package racing + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import racing.domain.CarFactory +import racing.domain.Cars + +class RacingGameTest { + + @Test + fun `자동차 생성`() { + val cars: Cars = CarFactory.create(3) + assertThat(cars.count()).isEqualTo(3) + } + + @Test + fun `레이싱 결과`() { + ㅣ + } +} diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt new file mode 100644 index 0000000000..1124e0a555 --- /dev/null +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -0,0 +1,15 @@ +package racing + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import racing.domain.RandomGenerator + +class RandomGeneratorTest { + + @Test + fun `랜덤숫자 발행 테스트`() { + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThan(0) + assertThat(randomNumber).isLessThan(10) + } +} From c06f4b7a8a29d74ad5d4d8d18fa2a0ba771221a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 12 Nov 2022 16:00:14 +0900 Subject: [PATCH 12/49] =?UTF-8?q?=20:=20racing=20game=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../racing/application/RacingGameService.kt | 11 +++++++ src/main/kotlin/racing/domain/Car.kt | 12 ++++++- src/main/kotlin/racing/domain/Cars.kt | 22 +++++++------ src/main/kotlin/racing/domain/RacingGame.kt | 28 +++++++++++++++++ .../kotlin/racing/domain/ResultStatistics.kt | 14 +++++++++ src/main/kotlin/racing/domain/Route.kt | 3 ++ src/main/kotlin/racing/domain/Routes.kt | 13 ++++++++ src/main/kotlin/racing/ui/InputView.kt | 8 +++++ src/main/kotlin/racing/ui/ResultView.kt | 19 ++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 31 +++++++++++++++++-- src/test/kotlin/racing/RandomGeneratorTest.kt | 4 +-- 11 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/racing/application/RacingGameService.kt create mode 100644 src/main/kotlin/racing/domain/RacingGame.kt create mode 100644 src/main/kotlin/racing/domain/ResultStatistics.kt create mode 100644 src/main/kotlin/racing/domain/Route.kt create mode 100644 src/main/kotlin/racing/domain/Routes.kt create mode 100644 src/main/kotlin/racing/ui/InputView.kt create mode 100644 src/main/kotlin/racing/ui/ResultView.kt diff --git a/src/main/kotlin/racing/application/RacingGameService.kt b/src/main/kotlin/racing/application/RacingGameService.kt new file mode 100644 index 0000000000..a303b10de7 --- /dev/null +++ b/src/main/kotlin/racing/application/RacingGameService.kt @@ -0,0 +1,11 @@ +package racing.application + +import racing.domain.RacingGame + +class RacingGameService { + + fun main() { + val racingGame = RacingGame() + racingGame.start() + } +} diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 510aa44f86..bcd78e76d7 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,3 +1,13 @@ package racing.domain -data class Car(val name: String) +data class Car(val name: String) { + + private val routes = Routes() + fun move(num: Int) { + when (num) { + in 4..9 -> routes.add() + } + } + + fun routes() = routes +} diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index fd98a73f22..6a2e45c978 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,10 +1,9 @@ package racing.domain -import java.util.stream.Collectors.toList import java.util.stream.IntStream import kotlin.streams.toList -class Cars(count: Int, var index: Int = 0) : Iterator { +class Cars(count: Int) : Iterable { private val list: List @@ -12,16 +11,19 @@ class Cars(count: Int, var index: Int = 0) : Iterator { list = IntStream.range(0, count) .mapToObj { Car(it.toString()) - }.collect(toList()) + }.toList() } - override fun hasNext(): Boolean { - return list.size > index - } - - override fun next(): Car { - return list[index++] - } + // override fun hasNext(): Boolean { + // return list.size > index + // } + // + // override fun next(): Car { + // return list[index++] + // } fun count() = list.size + override fun iterator(): Iterator { + return list.iterator() + } } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt new file mode 100644 index 0000000000..3560aff779 --- /dev/null +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -0,0 +1,28 @@ +package racing.domain + +import racing.ui.InputView +import racing.ui.ResultView + +class RacingGame { + + fun start() { + + ResultView.requireCarsCount() + val cars = Cars(InputView.inputNumber()) + + ResultView.requireNumberOfGames() + var count = InputView.inputNumber() + + while (count-- > 0) { + turn(cars) + } + + ResultView.printGameResult(ResultStatistics(cars).toResult()) + } + + fun turn(cars: Cars) { + for (car in cars) { + car.move(RandomGenerator.generate()) + } + } +} diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt new file mode 100644 index 0000000000..02108d8c87 --- /dev/null +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -0,0 +1,14 @@ +package racing.domain + +import kotlin.streams.asSequence + +class ResultStatistics(private val cars: Cars) { + + fun toResult(): String { + val stringBuilder = StringBuilder() + for (car in cars) { + stringBuilder.appendLine(car.routes().stream().map { "-" }.asSequence().joinToString("")) + } + return stringBuilder.toString() + } +} diff --git a/src/main/kotlin/racing/domain/Route.kt b/src/main/kotlin/racing/domain/Route.kt new file mode 100644 index 0000000000..69bdc95d03 --- /dev/null +++ b/src/main/kotlin/racing/domain/Route.kt @@ -0,0 +1,3 @@ +package racing.domain + +class Route() diff --git a/src/main/kotlin/racing/domain/Routes.kt b/src/main/kotlin/racing/domain/Routes.kt new file mode 100644 index 0000000000..c9fd56ec0c --- /dev/null +++ b/src/main/kotlin/racing/domain/Routes.kt @@ -0,0 +1,13 @@ +package racing.domain + +class Routes { + + private val list = mutableListOf() + + fun add() { + list.add(Route()) + } + + fun stream() = list.stream() + fun size() = list.size +} diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt new file mode 100644 index 0000000000..e73ed43f53 --- /dev/null +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -0,0 +1,8 @@ +package racing.ui + +class InputView { + + companion object { + fun inputNumber() = readLine()!!.toInt() + } +} diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt new file mode 100644 index 0000000000..0850bfd21c --- /dev/null +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -0,0 +1,19 @@ +package racing.ui + +class ResultView { + + companion object { + fun requireCarsCount() { + println("자동차 대수는 몇 대인가요?") + } + + fun requireNumberOfGames() { + println("시도할 횟수는 몇 회인가요?") + } + + fun printGameResult(result: String) { + println("실행결과") + println(result) + } + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4579dff3e7..85181f66fd 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -2,8 +2,11 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import racing.domain.CarFactory import racing.domain.Cars +import racing.domain.ResultStatistics class RacingGameTest { @@ -13,8 +16,32 @@ class RacingGameTest { assertThat(cars.count()).isEqualTo(3) } + @ParameterizedTest + @ValueSource(ints = [4, 9]) + fun `자동차 이동`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars) { + car.move(num) + assertThat(car.routes().size()).isEqualTo(1) + } + } + + @ParameterizedTest + @ValueSource(ints = [0, 3]) + fun `자동차 이동실패`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars) { + car.move(num) + assertThat(car.routes().size()).isEqualTo(0) + } + } + @Test - fun `레이싱 결과`() { - ㅣ + fun `실행결과 출력`() { + val cars: Cars = CarFactory.create(1) + for (car in cars) { + car.move(4) + } + assertThat(ResultStatistics(cars).toResult()).isEqualTo("-\n") } } diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index 1124e0a555..4f85a7a4db 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -9,7 +9,7 @@ class RandomGeneratorTest { @Test fun `랜덤숫자 발행 테스트`() { val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThan(0) - assertThat(randomNumber).isLessThan(10) + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) } } From 187496c1992fb756bad133afa005f8b65b29a789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Wed, 16 Nov 2022 23:29:42 +0900 Subject: [PATCH 13/49] =?UTF-8?q?[step2]=20:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Expression.kt | 54 ++++++++++--------- src/main/kotlin/calculator/Num.kt | 2 +- src/main/kotlin/calculator/Operator.kt | 6 +++ .../kotlin/calculator/StringCalculator.kt | 36 +++---------- src/test/kotlin/calculator/ExpressionTest.kt | 22 ++++++++ .../kotlin/calculator/StringCalculatorTest.kt | 31 ++--------- src/test/kotlin/calculator/StringTest.kt | 28 ++++++++++ 7 files changed, 97 insertions(+), 82 deletions(-) create mode 100644 src/test/kotlin/calculator/ExpressionTest.kt create mode 100644 src/test/kotlin/calculator/StringTest.kt diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt index 5349ac851f..266cbf6dfc 100644 --- a/src/main/kotlin/calculator/Expression.kt +++ b/src/main/kotlin/calculator/Expression.kt @@ -4,50 +4,52 @@ import java.util.LinkedList import java.util.Queue class Expression( - val input: String + private var _mathematical: String ) { - fun apply(): Queue { - val queue = createOperandAndOperatorQueue(input) - if (queue.size % 2 == 0) throw IllegalArgumentException() - return queue - } + private val mathematical: String + get() = _mathematical - private fun priorityIndexes(data: String): List { - val priorityList = mutableListOf() + init { + _mathematical = _mathematical.replace(" ", "") + verifyMathematical(_mathematical) + } - for (c in data) { - if (isOperatorLetter(c)) { - priorityList.add(c) - } - } + fun compute(): Queue { + return polynomial(mathematical) + } - return priorityList + private fun priorityIndexes(data: String): List { + return data.filter { c -> isOperatorLetter(c) }.toList() } private fun isOperatorLetter(c: Char): Boolean { - for (operator in Operator.values()) { - if (operator.isSame(c)) { - return true - } - } - return false + return Operator.exist(c) } - private fun createOperandAndOperatorQueue(data: String): Queue { + private fun polynomial(mathematical: String): Queue { - var temp = data - val sortedPriorityList = priorityIndexes(data) + var newMathematical = mathematical + val sortedPriorityList = priorityIndexes(mathematical) val queue = LinkedList() for (operator in sortedPriorityList) { - val operand = temp.substringBefore(operator.toString()) + val operand = newMathematical.substringBefore(operator.toString()) queue.add(operand) queue.add(operator.toString()) - temp = temp.substringAfter(operator.toString()) + newMathematical = newMathematical.substringAfter(operator.toString()) } - queue.add(temp) + queue.add(newMathematical) + if (queue.size % 2 == 0) throw IllegalArgumentException() return queue } + + private fun verifyMathematical(mathematical: String) { + val splitData = mathematical.split(*Operator.list().toTypedArray()) + + if (splitData.size != mathematical.length - (mathematical.length / 2)) { + throw IllegalArgumentException() + } + } } diff --git a/src/main/kotlin/calculator/Num.kt b/src/main/kotlin/calculator/Num.kt index fd2a916ce3..6240f6ed32 100644 --- a/src/main/kotlin/calculator/Num.kt +++ b/src/main/kotlin/calculator/Num.kt @@ -2,7 +2,7 @@ package calculator data class Num(var value: Int) { - constructor(value: String) : this(Integer.parseInt(value)) + constructor(value: String) : this(value.toIntOrNull() ?: throw IllegalArgumentException()) fun add(number: Num) = Num(this.value + number.value) diff --git a/src/main/kotlin/calculator/Operator.kt b/src/main/kotlin/calculator/Operator.kt index d147bb5c45..c6d2b63309 100644 --- a/src/main/kotlin/calculator/Operator.kt +++ b/src/main/kotlin/calculator/Operator.kt @@ -22,5 +22,11 @@ enum class Operator(private val sign: Char) { operator fun invoke(sign: Char): Operator { return values().first { o -> o.isSame(sign) } } + + fun exist(sign: Char): Boolean { + return values().any { o -> o.isSame(sign) } + } + + fun list(): List = values().map { it -> it.sign.toString() }.toList() } } diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt index 760be04360..880f0d6d9d 100644 --- a/src/main/kotlin/calculator/StringCalculator.kt +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -2,43 +2,21 @@ package calculator class StringCalculator { - fun calculate(input: String): Num { + fun calculate(mathematical: String): Num { - val data = removeSpace(input) - verifyOperator(data) - - val expression = Expression(data) - val queue = expression.apply() + val expression = Expression(mathematical) + val queue = expression.compute() var result = Num(queue.poll()) while (queue.isNotEmpty()) { - val operator = queue.poll() - val operand = queue.poll() - val o = Operator(operator.first()) - result = o.calculate(result, Num(operand)) + val operator = Operator(queue.poll().first()) + val second = Num(queue.poll()) + result = calculate(result, second, operator) } return result } - private fun removeSpace(input: String): String { - return input.replace(" ", "") - } - - private fun verifyOperator(data: String) { - val splitData = data.split("+", "-", "*", "/") - - if (splitData.size != data.length - (data.length / 2)) { - throw IllegalArgumentException() - } - - for (c in splitData) { - try { - Integer.parseInt(c) - } catch (e: NumberFormatException) { - throw IllegalArgumentException() - } - } - } + private fun calculate(first: Num, second: Num, operator: Operator) = operator.calculate(first, second) } diff --git a/src/test/kotlin/calculator/ExpressionTest.kt b/src/test/kotlin/calculator/ExpressionTest.kt new file mode 100644 index 0000000000..79a769a87f --- /dev/null +++ b/src/test/kotlin/calculator/ExpressionTest.kt @@ -0,0 +1,22 @@ +package calculator + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +class ExpressionTest { + + @Test + fun `수식을 계산하기 쉽게 문자 Queue로 반환한다`() { + val expression = Expression("2 * 3 / 3 + 1") + val queue = expression.compute() + assertThat(queue.size).isEqualTo(7) + } + + @Test + fun `잘못된 수식을 문자 Queue로 반환한다`() { + assertThrows { + Expression("2 * 3 / 3 ! 1") + } + } +} diff --git a/src/test/kotlin/calculator/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt index e9ca3b8612..590d68e278 100644 --- a/src/test/kotlin/calculator/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -8,27 +8,6 @@ import org.junit.jupiter.params.provider.ValueSource class StringCalculatorTest { - @Test - fun `문자열 자르기`() { - - val input = "1234-5678-9000" - - val substringBefore = input.substringBefore("-") - val substringAfter = input.substringAfter("-") - - assertThat(substringBefore).isEqualTo("1234") - assertThat(substringAfter).isEqualTo("5678-9000") - } - - @Test - fun `인덱스 가져오기`() { - - var input = "2 + 3 * 4 / 2" - input = input.replace(" ", "") - val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } - assertThat(index).isEqualTo(1) - } - @Test fun `덧셈`() { val input = "2 + 3" @@ -77,20 +56,20 @@ class StringCalculatorTest { @ParameterizedTest @ValueSource(strings = ["2 ! 3 * 4 / 2", "23 * 22A * 1"]) - fun `사칙연산 기호가 아닌경우`(input: String) { + fun `사칙연산 기호가 아닌경우`(mathematical: String) { val stringCalculator = StringCalculator() assertThrows { - stringCalculator.calculate(input) + stringCalculator.calculate(mathematical) } } @Test - fun `사칙연산 기능 구현`() { + fun `사칙연산을 실행한다`() { - val input = "2 + 3 * 4 / 2" + val mathematical = "2 + 3 * 4 / 2" val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) + val result = stringCalculator.calculate(mathematical) assertThat(result).isEqualTo(Num(10)) } diff --git a/src/test/kotlin/calculator/StringTest.kt b/src/test/kotlin/calculator/StringTest.kt new file mode 100644 index 0000000000..f7477f9fd8 --- /dev/null +++ b/src/test/kotlin/calculator/StringTest.kt @@ -0,0 +1,28 @@ +package calculator + +import org.assertj.core.api.AssertionsForInterfaceTypes +import org.junit.jupiter.api.Test + +class StringTest { + + @Test + fun `문자열 자르기`() { + + val input = "1234-5678-9000" + + val substringBefore = input.substringBefore("-") + val substringAfter = input.substringAfter("-") + + AssertionsForInterfaceTypes.assertThat(substringBefore).isEqualTo("1234") + AssertionsForInterfaceTypes.assertThat(substringAfter).isEqualTo("5678-9000") + } + + @Test + fun `인덱스 가져오기`() { + + var input = "2 + 3 * 4 / 2" + input = input.replace(" ", "") + val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } + AssertionsForInterfaceTypes.assertThat(index).isEqualTo(1) + } +} From bb0eff800ca569d0953909f9ba302a65e9e88ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Wed, 16 Nov 2022 23:43:45 +0900 Subject: [PATCH 14/49] =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20RE?= =?UTF-8?q?ADME.md=EC=97=90=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d49f3cfc8..0b13227357 100644 --- a/README.md +++ b/README.md @@ -1 +1,8 @@ -# kotlin-racingcar \ No newline at end of file +# kotlin-racingcar + +- [] 자동차 생성 + - [] 자동차는 4~9 범위 사이일때 움직일 수 있다. + - [] 자동차는 0~3 범위 사이에는 움직일 수 없다. +- [] 무작위 값은 0~9 범위 사이이다. +- [] 클라이언트로부터 값을 입력받을 수 있다. +- [] 실행결과를 출력한다. \ No newline at end of file From ebe9a9a2bfa581d8c4a1692b09589b63ab651795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Thu, 17 Nov 2022 00:00:12 +0900 Subject: [PATCH 15/49] =?UTF-8?q?[feat]:=20step3=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++------ src/main/kotlin/racing/domain/Car.kt | 14 +++++++++----- src/main/kotlin/racing/domain/Cars.kt | 8 -------- src/main/kotlin/racing/domain/RacingGame.kt | 4 ++-- .../kotlin/racing/domain/ResultStatistics.kt | 16 ++++++++++++++-- src/main/kotlin/racing/domain/Route.kt | 3 --- src/main/kotlin/racing/domain/Routes.kt | 13 ------------- src/test/kotlin/racing/RacingGameTest.kt | 4 ++-- 8 files changed, 33 insertions(+), 41 deletions(-) delete mode 100644 src/main/kotlin/racing/domain/Route.kt delete mode 100644 src/main/kotlin/racing/domain/Routes.kt diff --git a/README.md b/README.md index 0b13227357..64924a267d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # kotlin-racingcar -- [] 자동차 생성 - - [] 자동차는 4~9 범위 사이일때 움직일 수 있다. - - [] 자동차는 0~3 범위 사이에는 움직일 수 없다. -- [] 무작위 값은 0~9 범위 사이이다. -- [] 클라이언트로부터 값을 입력받을 수 있다. -- [] 실행결과를 출력한다. \ No newline at end of file +- [o] 자동차 생성 + - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. + - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. +- [o] 무작위 값은 0~9 범위 사이이다. +- [o] 클라이언트로부터 값을 입력받을 수 있다. +- [o] 실행결과를 출력한다. \ No newline at end of file diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index bcd78e76d7..2a10b2d35c 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,13 +1,17 @@ package racing.domain -data class Car(val name: String) { +data class Car(val name: String, private var _position: Int = 0) { + + val position: Int + get() = _position - private val routes = Routes() fun move(num: Int) { - when (num) { - in 4..9 -> routes.add() + if (num >= FORWARD_MOVE) { + _position++ } } - fun routes() = routes + companion object { + const val FORWARD_MOVE: Int = 4 + } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 6a2e45c978..f307ddfb4f 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -14,14 +14,6 @@ class Cars(count: Int) : Iterable { }.toList() } - // override fun hasNext(): Boolean { - // return list.size > index - // } - // - // override fun next(): Car { - // return list[index++] - // } - fun count() = list.size override fun iterator(): Iterator { return list.iterator() diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 3560aff779..5afe8ddae8 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -14,13 +14,13 @@ class RacingGame { var count = InputView.inputNumber() while (count-- > 0) { - turn(cars) + race(cars) } ResultView.printGameResult(ResultStatistics(cars).toResult()) } - fun turn(cars: Cars) { + private fun race(cars: Cars) { for (car in cars) { car.move(RandomGenerator.generate()) } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index 02108d8c87..785e84e6a6 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -1,14 +1,26 @@ package racing.domain -import kotlin.streams.asSequence +import java.util.stream.IntStream +import kotlin.streams.toList class ResultStatistics(private val cars: Cars) { fun toResult(): String { val stringBuilder = StringBuilder() for (car in cars) { - stringBuilder.appendLine(car.routes().stream().map { "-" }.asSequence().joinToString("")) + stringBuilder.appendLine(toMark(car)) } return stringBuilder.toString() } + + private fun toMark(car: Car): String { + return IntStream.range(0, car.position) + .mapToObj { MARK } + .toList() + .joinToString { "" } + } + + companion object { + const val MARK: String = "-" + } } diff --git a/src/main/kotlin/racing/domain/Route.kt b/src/main/kotlin/racing/domain/Route.kt deleted file mode 100644 index 69bdc95d03..0000000000 --- a/src/main/kotlin/racing/domain/Route.kt +++ /dev/null @@ -1,3 +0,0 @@ -package racing.domain - -class Route() diff --git a/src/main/kotlin/racing/domain/Routes.kt b/src/main/kotlin/racing/domain/Routes.kt deleted file mode 100644 index c9fd56ec0c..0000000000 --- a/src/main/kotlin/racing/domain/Routes.kt +++ /dev/null @@ -1,13 +0,0 @@ -package racing.domain - -class Routes { - - private val list = mutableListOf() - - fun add() { - list.add(Route()) - } - - fun stream() = list.stream() - fun size() = list.size -} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 85181f66fd..b4a54fd4c5 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -22,7 +22,7 @@ class RacingGameTest { val cars: Cars = CarFactory.create(3) for (car in cars) { car.move(num) - assertThat(car.routes().size()).isEqualTo(1) + assertThat(car.position).isEqualTo(1) } } @@ -32,7 +32,7 @@ class RacingGameTest { val cars: Cars = CarFactory.create(3) for (car in cars) { car.move(num) - assertThat(car.routes().size()).isEqualTo(0) + assertThat(car.position).isEqualTo(0) } } From 02059601c0d9daefca0d160aa3931062835dfbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Thu, 17 Nov 2022 23:58:11 +0900 Subject: [PATCH 16/49] =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 2 +- src/main/kotlin/racing/domain/Cars.kt | 20 +++++----- src/main/kotlin/racing/domain/RacingGame.kt | 12 +++--- .../kotlin/racing/domain/ResultStatistics.kt | 10 +---- src/main/kotlin/racing/ui/InputView.kt | 11 ++++++ src/main/kotlin/racing/ui/ResultView.kt | 8 ---- src/test/kotlin/racing/CarTest.kt | 37 +++++++++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 30 +-------------- src/test/kotlin/racing/RandomGeneratorTest.kt | 8 ++-- 9 files changed, 71 insertions(+), 67 deletions(-) create mode 100644 src/test/kotlin/racing/CarTest.kt diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 2a10b2d35c..574af157d7 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,6 +1,6 @@ package racing.domain -data class Car(val name: String, private var _position: Int = 0) { +class Car(private var _position: Int = 0) { val position: Int get() = _position diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index f307ddfb4f..dc786eb6a4 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,21 +1,19 @@ package racing.domain -import java.util.stream.IntStream -import kotlin.streams.toList - -class Cars(count: Int) : Iterable { +class Cars(count: Int) { private val list: List init { - list = IntStream.range(0, count) - .mapToObj { - Car(it.toString()) - }.toList() + list = List(count) { + Car() + } } fun count() = list.size - override fun iterator(): Iterator { - return list.iterator() - } + + fun list() = list + // override fun iterator(): Iterator { + // return list.iterator() + // } } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 5afe8ddae8..a2361fddeb 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -7,13 +7,11 @@ class RacingGame { fun start() { - ResultView.requireCarsCount() - val cars = Cars(InputView.inputNumber()) + val carCount = InputView.requireCarsCount() + val cars = CarFactory.create(carCount) + var numberOfGames = InputView.requireNumberOfGames() - ResultView.requireNumberOfGames() - var count = InputView.inputNumber() - - while (count-- > 0) { + while (numberOfGames-- > 0) { race(cars) } @@ -21,7 +19,7 @@ class RacingGame { } private fun race(cars: Cars) { - for (car in cars) { + for (car in cars.list()) { car.move(RandomGenerator.generate()) } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index 785e84e6a6..87d0d32035 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -1,23 +1,17 @@ package racing.domain -import java.util.stream.IntStream -import kotlin.streams.toList - class ResultStatistics(private val cars: Cars) { fun toResult(): String { val stringBuilder = StringBuilder() - for (car in cars) { + for (car in cars.list()) { stringBuilder.appendLine(toMark(car)) } return stringBuilder.toString() } private fun toMark(car: Car): String { - return IntStream.range(0, car.position) - .mapToObj { MARK } - .toList() - .joinToString { "" } + return MARK.repeat(car.position) } companion object { diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt index e73ed43f53..445370b62e 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -3,6 +3,17 @@ package racing.ui class InputView { companion object { + + fun requireCarsCount(): Int { + println("자동차 대수는 몇 대인가요?") + return inputNumber() + } + + fun requireNumberOfGames(): Int { + println("시도할 횟수는 몇 회인가요?") + return inputNumber() + } + fun inputNumber() = readLine()!!.toInt() } } diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 0850bfd21c..f323d39590 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -3,14 +3,6 @@ package racing.ui class ResultView { companion object { - fun requireCarsCount() { - println("자동차 대수는 몇 대인가요?") - } - - fun requireNumberOfGames() { - println("시도할 횟수는 몇 회인가요?") - } - fun printGameResult(result: String) { println("실행결과") println(result) diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt new file mode 100644 index 0000000000..e2f6a9cc1f --- /dev/null +++ b/src/test/kotlin/racing/CarTest.kt @@ -0,0 +1,37 @@ +package racing + +import org.assertj.core.api.AssertionsForInterfaceTypes +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource +import racing.domain.CarFactory +import racing.domain.Cars + +class CarTest { + + @Test + fun `자동차 생성`() { + val cars: Cars = CarFactory.create(3) + AssertionsForInterfaceTypes.assertThat(cars.count()).isEqualTo(3) + } + + @ParameterizedTest + @ValueSource(ints = [4, 9]) + fun `자동차 이동`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars.list()) { + car.move(num) + AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) + } + } + + @ParameterizedTest + @ValueSource(ints = [0, 3]) + fun `자동차 이동실패`(num: Int) { + val cars: Cars = CarFactory.create(3) + for (car in cars.list()) { + car.move(num) + AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) + } + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index b4a54fd4c5..b48a889a8b 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -2,44 +2,16 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import racing.domain.CarFactory import racing.domain.Cars import racing.domain.ResultStatistics class RacingGameTest { - @Test - fun `자동차 생성`() { - val cars: Cars = CarFactory.create(3) - assertThat(cars.count()).isEqualTo(3) - } - - @ParameterizedTest - @ValueSource(ints = [4, 9]) - fun `자동차 이동`(num: Int) { - val cars: Cars = CarFactory.create(3) - for (car in cars) { - car.move(num) - assertThat(car.position).isEqualTo(1) - } - } - - @ParameterizedTest - @ValueSource(ints = [0, 3]) - fun `자동차 이동실패`(num: Int) { - val cars: Cars = CarFactory.create(3) - for (car in cars) { - car.move(num) - assertThat(car.position).isEqualTo(0) - } - } - @Test fun `실행결과 출력`() { val cars: Cars = CarFactory.create(1) - for (car in cars) { + for (car in cars.list()) { car.move(4) } assertThat(ResultStatistics(cars).toResult()).isEqualTo("-\n") diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index 4f85a7a4db..1573a9f189 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -8,8 +8,10 @@ class RandomGeneratorTest { @Test fun `랜덤숫자 발행 테스트`() { - val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThanOrEqualTo(0) - assertThat(randomNumber).isLessThanOrEqualTo(9) + for (i in 1..9) { + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) + } } } From 1a5e1deaa4454bbfba5010a9493d0fba16d889f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Fri, 18 Nov 2022 00:09:49 +0900 Subject: [PATCH 17/49] =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 8 ++++---- src/main/kotlin/racing/domain/Cars.kt | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 574af157d7..e187c38527 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,13 +1,13 @@ package racing.domain -class Car(private var _position: Int = 0) { +class Car(position: Int = 0) { - val position: Int - get() = _position + var position = position + private set fun move(num: Int) { if (num >= FORWARD_MOVE) { - _position++ + position++ } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index dc786eb6a4..eca89f0b2a 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -13,7 +13,4 @@ class Cars(count: Int) { fun count() = list.size fun list() = list - // override fun iterator(): Iterator { - // return list.iterator() - // } } From 61c89f50a4a30360afebd52e1377dc1b33a17187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:35:57 +0900 Subject: [PATCH 18/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 1 + src/main/kotlin/racing/domain/Cars.kt | 10 ++++++++-- src/main/kotlin/racing/domain/RacingGame.kt | 10 +++------- src/main/kotlin/racing/domain/RandomGenerator.kt | 2 +- src/main/kotlin/racing/domain/ResultStatistics.kt | 6 +----- src/main/kotlin/racing/ui/InputView.kt | 2 +- src/test/kotlin/racing/CarTest.kt | 4 ++-- src/test/kotlin/racing/RacingGameTest.kt | 6 +++--- src/test/kotlin/racing/RandomGeneratorTest.kt | 12 +++++------- 9 files changed, 25 insertions(+), 28 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fe25d72722..9c2551a8b3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,7 @@ repositories { dependencies { testImplementation("org.junit.jupiter", "junit-jupiter", "5.8.2") + testImplementation("org.junit.jupiter", "junit-jupiter-engine", "5.8.2") testImplementation("org.assertj", "assertj-core", "3.22.0") testImplementation("io.kotest", "kotest-runner-junit5", "5.2.3") } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index eca89f0b2a..7a7ce34e94 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,6 +1,6 @@ package racing.domain -class Cars(count: Int) { +class Cars(count: Int) : Iterable { private val list: List @@ -12,5 +12,11 @@ class Cars(count: Int) { fun count() = list.size - fun list() = list + fun race(movable: () -> Int) { + list.forEach { + car -> + car.move(movable.invoke()) + } + } + override fun iterator(): Iterator = list.iterator() } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index a2361fddeb..22a73c2d95 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -12,15 +12,11 @@ class RacingGame { var numberOfGames = InputView.requireNumberOfGames() while (numberOfGames-- > 0) { - race(cars) + cars.race { + RandomGenerator.generate() + } } ResultView.printGameResult(ResultStatistics(cars).toResult()) } - - private fun race(cars: Cars) { - for (car in cars.list()) { - car.move(RandomGenerator.generate()) - } - } } diff --git a/src/main/kotlin/racing/domain/RandomGenerator.kt b/src/main/kotlin/racing/domain/RandomGenerator.kt index ea14764c50..9a9946e7bd 100644 --- a/src/main/kotlin/racing/domain/RandomGenerator.kt +++ b/src/main/kotlin/racing/domain/RandomGenerator.kt @@ -3,6 +3,6 @@ package racing.domain class RandomGenerator { companion object { - fun generate(): Int = (1..9).random() + fun generate(): Int = (0..9).random() } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index 87d0d32035..d219320c28 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -3,11 +3,7 @@ package racing.domain class ResultStatistics(private val cars: Cars) { fun toResult(): String { - val stringBuilder = StringBuilder() - for (car in cars.list()) { - stringBuilder.appendLine(toMark(car)) - } - return stringBuilder.toString() + return cars.map { toMark(it) }.joinToString(separator = System.lineSeparator()) } private fun toMark(car: Car): String { diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt index 445370b62e..ae2f84ef99 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -14,6 +14,6 @@ class InputView { return inputNumber() } - fun inputNumber() = readLine()!!.toInt() + private fun inputNumber() = readln().toInt() } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index e2f6a9cc1f..353b35322f 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -19,7 +19,7 @@ class CarTest { @ValueSource(ints = [4, 9]) fun `자동차 이동`(num: Int) { val cars: Cars = CarFactory.create(3) - for (car in cars.list()) { + for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) } @@ -29,7 +29,7 @@ class CarTest { @ValueSource(ints = [0, 3]) fun `자동차 이동실패`(num: Int) { val cars: Cars = CarFactory.create(3) - for (car in cars.list()) { + for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index b48a889a8b..09d2fcba1a 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -10,10 +10,10 @@ class RacingGameTest { @Test fun `실행결과 출력`() { - val cars: Cars = CarFactory.create(1) - for (car in cars.list()) { + val cars: Cars = CarFactory.create(2) + for (car in cars) { car.move(4) } - assertThat(ResultStatistics(cars).toResult()).isEqualTo("-\n") + assertThat(ResultStatistics(cars).toResult()).isEqualTo("-${System.lineSeparator()}-") } } diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index 1573a9f189..c33cc0ad7f 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -1,17 +1,15 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat -import org.junit.jupiter.api.Test +import org.junit.jupiter.api.RepeatedTest import racing.domain.RandomGenerator class RandomGeneratorTest { - @Test + @RepeatedTest(value = 5) fun `랜덤숫자 발행 테스트`() { - for (i in 1..9) { - val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThanOrEqualTo(0) - assertThat(randomNumber).isLessThanOrEqualTo(9) - } + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) } } From 9ca62d4d308883fd7a85a10e735006caef14f0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:41:17 +0900 Subject: [PATCH 19/49] =?UTF-8?q?=20:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20README.md=EC=97=90=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 64924a267d..d124634a36 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # kotlin-racingcar - [o] 자동차 생성 - - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. + - [] 자동차에 이름을 부여할 수 있다. + - [] 자동차의 이름은 5글자를 초과할 수 없다. + - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. +- [o] 자동차의 움직임 + - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. + - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. - [o] 클라이언트로부터 값을 입력받을 수 있다. -- [o] 실행결과를 출력한다. \ No newline at end of file +- [o] 실행결과를 출력한다. + - [] 매 횟수마다 출력한다. + - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. + - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From 20eacb86d6bf5a08f2deb33ce1ecc3d67cb90073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:42:17 +0900 Subject: [PATCH 20/49] =?UTF-8?q?=20:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d124634a36..c694347bd1 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. -- [o] 클라이언트로부터 값을 입력받을 수 있다. -- [o] 실행결과를 출력한다. +- [] 클라이언트로부터 값을 입력받을 수 있다. + - [] 자동차의 이름은 쉼표(,)로 구분할 수 있다. + +- [] 실행결과를 출력한다. - [] 매 횟수마다 출력한다. - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From 8dfbb0c2dbb1b54bbfef606767e1b0cee6f38d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:50:23 +0900 Subject: [PATCH 21/49] =?UTF-8?q?=20:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=EC=97=90=20=EC=9D=B4=EB=A6=84=20=EB=B6=80=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/domain/Car.kt | 2 +- src/main/kotlin/racing/domain/CarFactory.kt | 4 ++-- src/main/kotlin/racing/domain/Cars.kt | 10 +++++++--- src/main/kotlin/racing/domain/RacingGame.kt | 4 ++-- src/main/kotlin/racing/ui/InputView.kt | 12 +++++++----- src/test/kotlin/racing/CarTest.kt | 11 +++++++---- src/test/kotlin/racing/RacingGameTest.kt | 3 ++- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c694347bd1..6b1d9ebe18 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # kotlin-racingcar - [o] 자동차 생성 - - [] 자동차에 이름을 부여할 수 있다. + - [o] 자동차에 이름을 부여할 수 있다. - [] 자동차의 이름은 5글자를 초과할 수 없다. - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. - [o] 자동차의 움직임 diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index e187c38527..a6ced45378 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,6 +1,6 @@ package racing.domain -class Car(position: Int = 0) { +class Car(name: String, position: Int = 0) { var position = position private set diff --git a/src/main/kotlin/racing/domain/CarFactory.kt b/src/main/kotlin/racing/domain/CarFactory.kt index 6c8dab7711..0d6f69d203 100644 --- a/src/main/kotlin/racing/domain/CarFactory.kt +++ b/src/main/kotlin/racing/domain/CarFactory.kt @@ -3,8 +3,8 @@ package racing.domain class CarFactory { companion object { - fun create(count: Int): Cars { - return Cars(count) + fun create(names: String): Cars { + return Cars(names) } } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 7a7ce34e94..81ece62679 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,12 +1,12 @@ package racing.domain -class Cars(count: Int) : Iterable { +class Cars(names: String) : Iterable { private val list: List init { - list = List(count) { - Car() + list = names.split(SEPARATOR).map { + Car(it) } } @@ -19,4 +19,8 @@ class Cars(count: Int) : Iterable { } } override fun iterator(): Iterator = list.iterator() + + companion object { + const val SEPARATOR = "," + } } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 22a73c2d95..555a5b48a9 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -7,8 +7,8 @@ class RacingGame { fun start() { - val carCount = InputView.requireCarsCount() - val cars = CarFactory.create(carCount) + val carNames = InputView.requireRacingCarNames() + val cars = CarFactory.create(carNames) var numberOfGames = InputView.requireNumberOfGames() while (numberOfGames-- > 0) { diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt index ae2f84ef99..cc5124981a 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -4,16 +4,18 @@ class InputView { companion object { - fun requireCarsCount(): Int { - println("자동차 대수는 몇 대인가요?") - return inputNumber() + fun requireRacingCarNames(): String { + println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분") + return readString() } fun requireNumberOfGames(): Int { println("시도할 횟수는 몇 회인가요?") - return inputNumber() + return readNum() } - private fun inputNumber() = readln().toInt() + private fun readNum() = readln().toInt() + + private fun readString() = readln() } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 353b35322f..2b2341c591 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -10,15 +10,17 @@ import racing.domain.Cars class CarTest { @Test - fun `자동차 생성`() { - val cars: Cars = CarFactory.create(3) + fun `자동차를 생성한다`() { + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) AssertionsForInterfaceTypes.assertThat(cars.count()).isEqualTo(3) } @ParameterizedTest @ValueSource(ints = [4, 9]) fun `자동차 이동`(num: Int) { - val cars: Cars = CarFactory.create(3) + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) @@ -28,7 +30,8 @@ class CarTest { @ParameterizedTest @ValueSource(ints = [0, 3]) fun `자동차 이동실패`(num: Int) { - val cars: Cars = CarFactory.create(3) + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 09d2fcba1a..4fb85df4d6 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -10,7 +10,8 @@ class RacingGameTest { @Test fun `실행결과 출력`() { - val cars: Cars = CarFactory.create(2) + val names = "lee,kkoks" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(4) } From 7f708457d0bc3fd8670296eec806959f84faa52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:54:29 +0900 Subject: [PATCH 22/49] =?UTF-8?q?=20:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=A6=84=EC=9D=B4=205=EA=B8=80=EC=9E=90?= =?UTF-8?q?=EB=B3=B4=EB=8B=A4=20=ED=81=B4=EA=B2=BD=EC=9A=B0=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++----- src/main/kotlin/racing/domain/Car.kt | 6 ++++++ src/test/kotlin/racing/CarTest.kt | 19 ++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6b1d9ebe18..a2b6dea879 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ - [o] 자동차 생성 - [o] 자동차에 이름을 부여할 수 있다. - - [] 자동차의 이름은 5글자를 초과할 수 없다. - - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. + - [o] 자동차의 이름은 5글자를 초과할 수 없다. + - [o] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. - [o] 자동차의 움직임 - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. -- [] 클라이언트로부터 값을 입력받을 수 있다. - - [] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - +- [o] 클라이언트로부터 값을 입력받을 수 있다. + - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - [] 실행결과를 출력한다. - [] 매 횟수마다 출력한다. - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index a6ced45378..8b54bbe222 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -5,6 +5,11 @@ class Car(name: String, position: Int = 0) { var position = position private set + init { + if (name.length > CAR_NAME_LIMIT) + throw IllegalArgumentException("자동차의 이름은 ${CAR_NAME_LIMIT}글자를 초과할 수 없습니다.") + } + fun move(num: Int) { if (num >= FORWARD_MOVE) { position++ @@ -13,5 +18,6 @@ class Car(name: String, position: Int = 0) { companion object { const val FORWARD_MOVE: Int = 4 + const val CAR_NAME_LIMIT: Int = 5 } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 2b2341c591..254f37c0b5 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -1,7 +1,8 @@ package racing -import org.assertj.core.api.AssertionsForInterfaceTypes +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import racing.domain.CarFactory @@ -10,10 +11,18 @@ import racing.domain.Cars class CarTest { @Test - fun `자동차를 생성한다`() { + fun `자동차를 생성할 때 자동차의 이름은 5글자 이하이다`() { val names = "lee,kkoks,amery" val cars: Cars = CarFactory.create(names) - AssertionsForInterfaceTypes.assertThat(cars.count()).isEqualTo(3) + assertThat(cars.count()).isEqualTo(3) + } + + @Test + fun `자동차를 생성할 때 자동차의 이름은 5글자를 초과한다`() { + val names = "leejhw,kkoks,amery" + assertThrows { + CarFactory.create(names) + } } @ParameterizedTest @@ -23,7 +32,7 @@ class CarTest { val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) - AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) + assertThat(car.position).isEqualTo(1) } } @@ -34,7 +43,7 @@ class CarTest { val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) - AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) + assertThat(car.position).isEqualTo(0) } } } From 289f67e1579c3d2cad44262211976a0792763ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:59:33 +0900 Subject: [PATCH 23/49] =?UTF-8?q?=20:=20=EB=A7=A4=20=ED=9A=9F?= =?UTF-8?q?=EC=88=98=EB=A7=88=EB=8B=A4=20=EC=8B=A4=ED=96=89=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/kotlin/racing/domain/Car.kt | 2 ++ src/main/kotlin/racing/domain/RacingGame.kt | 3 +-- src/main/kotlin/racing/domain/ResultStatistics.kt | 2 +- src/test/kotlin/racing/RacingGameTest.kt | 7 ++++++- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a2b6dea879..d075c839a9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,6 @@ - [o] 클라이언트로부터 값을 입력받을 수 있다. - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - [] 실행결과를 출력한다. - - [] 매 횟수마다 출력한다. - - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. + - [o] 매 횟수마다 출력한다. + - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 8b54bbe222..7f0ce91c05 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -2,6 +2,8 @@ package racing.domain class Car(name: String, position: Int = 0) { + var name = name + private set var position = position private set diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 555a5b48a9..1aebad953c 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -15,8 +15,7 @@ class RacingGame { cars.race { RandomGenerator.generate() } + ResultView.printGameResult(ResultStatistics(cars).toResult()) } - - ResultView.printGameResult(ResultStatistics(cars).toResult()) } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index d219320c28..241cc00d49 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -3,7 +3,7 @@ package racing.domain class ResultStatistics(private val cars: Cars) { fun toResult(): String { - return cars.map { toMark(it) }.joinToString(separator = System.lineSeparator()) + return cars.map { "${it.name}: ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() } private fun toMark(car: Car): String { diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4fb85df4d6..cccd1638c2 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -15,6 +15,11 @@ class RacingGameTest { for (car in cars) { car.move(4) } - assertThat(ResultStatistics(cars).toResult()).isEqualTo("-${System.lineSeparator()}-") + + val result = """ + lee: - + kkoks: - + """.trimIndent() + assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) } } From 8255e011f68a7b8f99f6a570478422d4cc5ae9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:01:15 +0900 Subject: [PATCH 24/49] =?UTF-8?q?=20:=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/RacingGame.kt | 3 ++- src/main/kotlin/racing/domain/ResultStatistics.kt | 2 +- src/main/kotlin/racing/ui/ResultView.kt | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 1aebad953c..a4aa7f0fb7 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -11,11 +11,12 @@ class RacingGame { val cars = CarFactory.create(carNames) var numberOfGames = InputView.requireNumberOfGames() + ResultView.printRacingGameGuideText() while (numberOfGames-- > 0) { cars.race { RandomGenerator.generate() } - ResultView.printGameResult(ResultStatistics(cars).toResult()) + ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) } } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index 241cc00d49..43293a0dff 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -3,7 +3,7 @@ package racing.domain class ResultStatistics(private val cars: Cars) { fun toResult(): String { - return cars.map { "${it.name}: ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() + return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() } private fun toMark(car: Car): String { diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index f323d39590..5f034992f7 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -3,8 +3,11 @@ package racing.ui class ResultView { companion object { - fun printGameResult(result: String) { + + fun printRacingGameGuideText() { println("실행결과") + } + fun printRacingGameResult(result: String) { println(result) } } From 8f355a9845bbf4a75591f9653971121b016a3e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:20:29 +0900 Subject: [PATCH 25/49] =?UTF-8?q?=20:=20=EC=9A=B0=EC=8A=B9=EC=9E=90?= =?UTF-8?q?=20=EC=84=A0=EC=A0=95=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/domain/Car.kt | 15 +++++++++++++++ src/main/kotlin/racing/domain/Winner.kt | 14 ++++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 24 ++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/racing/domain/Winner.kt diff --git a/README.md b/README.md index d075c839a9..53dfcc17f4 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ - [] 실행결과를 출력한다. - [o] 매 횟수마다 출력한다. - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file + - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 7f0ce91c05..57cd2c9255 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -18,6 +18,21 @@ class Car(name: String, position: Int = 0) { } } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Car + + if (name != other.name) return false + + return true + } + + override fun hashCode(): Int { + return name.hashCode() + } + companion object { const val FORWARD_MOVE: Int = 4 const val CAR_NAME_LIMIT: Int = 5 diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt new file mode 100644 index 0000000000..ae9d03ade6 --- /dev/null +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -0,0 +1,14 @@ +package racing.domain + +class Winner(cars: Cars) { + + var cars = cars + private set + + constructor(carList: List) : this(Cars(carList.map { it.name }.joinToString(","))) + + fun win(): List { + val maxPosition = cars.maxOf { it.position } + return cars.filter { it.position == maxPosition } + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index cccd1638c2..4b41a43a4e 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -2,9 +2,11 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import racing.domain.Car import racing.domain.CarFactory import racing.domain.Cars import racing.domain.ResultStatistics +import racing.domain.Winner class RacingGameTest { @@ -17,9 +19,27 @@ class RacingGameTest { } val result = """ - lee: - - kkoks: - + lee : - + kkoks : - """.trimIndent() assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) } + + @Test + fun `Racing Game 단독 우승자 출력`() { + val leeCar = Car("lee", 5) + val kkoksCar = Car("kkoks", 3) + val winner = Winner(listOf(leeCar, kkoksCar)) + val result = winner.win() + assertThat(result).contains(leeCar) + } + + @Test + fun `Racing Game 공동 우승자 출력`() { + val leeCar = Car("lee", 5) + val kkoksCar = Car("kkoks", 5) + val winner = Winner(listOf(leeCar, kkoksCar)) + val result = winner.win() + assertThat(result).containsAll(listOf(leeCar, kkoksCar)) + } } From 301f988b04125e9b7714221cea7613c6cfd8c570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:20:55 +0900 Subject: [PATCH 26/49] =?UTF-8?q?=20:=20README.md=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53dfcc17f4..7b97fcae21 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [o] 무작위 값은 0~9 범위 사이이다. - [o] 클라이언트로부터 값을 입력받을 수 있다. - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. -- [] 실행결과를 출력한다. +- [o] 실행결과를 출력한다. - [o] 매 횟수마다 출력한다. - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From 73e4b7e0a574183db635e684832b7c74e23106f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:31:41 +0900 Subject: [PATCH 27/49] =?UTF-8?q?=20:=20=EC=9A=B0=EC=8A=B9=EC=9E=90?= =?UTF-8?q?=20=EC=B6=94=EC=B6=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Cars.kt | 7 +++++-- src/main/kotlin/racing/domain/RacingGame.kt | 2 ++ src/main/kotlin/racing/domain/Winner.kt | 6 +++--- src/main/kotlin/racing/ui/ResultView.kt | 4 ++++ src/test/kotlin/racing/RacingGameTest.kt | 4 ++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 81ece62679..d808a241f7 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,14 +1,17 @@ package racing.domain -class Cars(names: String) : Iterable { +class Cars : Iterable { private val list: List - init { + constructor(names: String) { list = names.split(SEPARATOR).map { Car(it) } } + constructor(carList: List) { + list = carList + } fun count() = list.size diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index a4aa7f0fb7..2e39e1f5d1 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -18,5 +18,7 @@ class RacingGame { } ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) } + val winner = Winner(cars) + ResultView.printRacingGameWinner(winner.win()) } } diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt index ae9d03ade6..ede4483e1e 100644 --- a/src/main/kotlin/racing/domain/Winner.kt +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -5,10 +5,10 @@ class Winner(cars: Cars) { var cars = cars private set - constructor(carList: List) : this(Cars(carList.map { it.name }.joinToString(","))) + constructor(carList: List) : this(Cars(carList)) - fun win(): List { + fun win(): String { val maxPosition = cars.maxOf { it.position } - return cars.filter { it.position == maxPosition } + return cars.filter { it.position == maxPosition }.joinToString { it.name } } } diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 5f034992f7..419495c456 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -10,5 +10,9 @@ class ResultView { fun printRacingGameResult(result: String) { println(result) } + + fun printRacingGameWinner(winner: String) { + println("${winner}가 최종 우승했습니다.") + } } } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4b41a43a4e..35acf894af 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -31,7 +31,7 @@ class RacingGameTest { val kkoksCar = Car("kkoks", 3) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() - assertThat(result).contains(leeCar) + assertThat(result).isEqualTo("lee") } @Test @@ -40,6 +40,6 @@ class RacingGameTest { val kkoksCar = Car("kkoks", 5) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() - assertThat(result).containsAll(listOf(leeCar, kkoksCar)) + assertThat(result).isEqualTo("lee, kkoks") } } From 95ab2cf63656c097a1794047dc4d80b7be266072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Mon, 21 Nov 2022 23:15:19 +0900 Subject: [PATCH 28/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 1 + src/main/kotlin/racing/domain/Cars.kt | 4 ++-- src/main/kotlin/racing/domain/RacingGame.kt | 6 ++---- src/main/kotlin/racing/domain/RandomGenerator.kt | 2 +- .../kotlin/racing/domain/ResultStatistics.kt | 16 ---------------- src/main/kotlin/racing/ui/ResultView.kt | 13 +++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 12 ++++++------ 7 files changed, 25 insertions(+), 29 deletions(-) delete mode 100644 src/main/kotlin/racing/domain/ResultStatistics.kt diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 57cd2c9255..30fabc9172 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -36,5 +36,6 @@ class Car(name: String, position: Int = 0) { companion object { const val FORWARD_MOVE: Int = 4 const val CAR_NAME_LIMIT: Int = 5 + fun produce(name: String, position: Int = 0) = Car(name, position) } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index d808a241f7..c9d8b41a9b 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -6,7 +6,7 @@ class Cars : Iterable { constructor(names: String) { list = names.split(SEPARATOR).map { - Car(it) + Car.produce(it) } } constructor(carList: List) { @@ -18,7 +18,7 @@ class Cars : Iterable { fun race(movable: () -> Int) { list.forEach { car -> - car.move(movable.invoke()) + car.move(movable()) } } override fun iterator(): Iterator = list.iterator() diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 2e39e1f5d1..65c319dada 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -13,10 +13,8 @@ class RacingGame { ResultView.printRacingGameGuideText() while (numberOfGames-- > 0) { - cars.race { - RandomGenerator.generate() - } - ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) + cars.race { RandomGenerator.generate() } + ResultView.printRacingGameResult(ResultView.toRaceResult(cars)) } val winner = Winner(cars) ResultView.printRacingGameWinner(winner.win()) diff --git a/src/main/kotlin/racing/domain/RandomGenerator.kt b/src/main/kotlin/racing/domain/RandomGenerator.kt index 9a9946e7bd..28f70d7ecd 100644 --- a/src/main/kotlin/racing/domain/RandomGenerator.kt +++ b/src/main/kotlin/racing/domain/RandomGenerator.kt @@ -3,6 +3,6 @@ package racing.domain class RandomGenerator { companion object { - fun generate(): Int = (0..9).random() + fun generate() = (0..9).random() } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt deleted file mode 100644 index 43293a0dff..0000000000 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ /dev/null @@ -1,16 +0,0 @@ -package racing.domain - -class ResultStatistics(private val cars: Cars) { - - fun toResult(): String { - return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() - } - - private fun toMark(car: Car): String { - return MARK.repeat(car.position) - } - - companion object { - const val MARK: String = "-" - } -} diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 419495c456..2219bcaada 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -1,12 +1,23 @@ package racing.ui +import racing.domain.Car +import racing.domain.Cars + class ResultView { companion object { + fun toRaceResult(cars: Cars): String { + return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() + } + + private fun toMark(car: Car): String { + return MARK.repeat(car.position) + } fun printRacingGameGuideText() { println("실행결과") } + fun printRacingGameResult(result: String) { println(result) } @@ -14,5 +25,7 @@ class ResultView { fun printRacingGameWinner(winner: String) { println("${winner}가 최종 우승했습니다.") } + + const val MARK = "-" } } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 35acf894af..e75c2ac5fa 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -5,8 +5,8 @@ import org.junit.jupiter.api.Test import racing.domain.Car import racing.domain.CarFactory import racing.domain.Cars -import racing.domain.ResultStatistics import racing.domain.Winner +import racing.ui.ResultView class RacingGameTest { @@ -22,13 +22,13 @@ class RacingGameTest { lee : - kkoks : - """.trimIndent() - assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) + assertThat(ResultView.toRaceResult(cars)).isEqualTo(result) } @Test fun `Racing Game 단독 우승자 출력`() { - val leeCar = Car("lee", 5) - val kkoksCar = Car("kkoks", 3) + val leeCar = Car.produce("lee", 5) + val kkoksCar = Car.produce("kkoks", 3) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() assertThat(result).isEqualTo("lee") @@ -36,8 +36,8 @@ class RacingGameTest { @Test fun `Racing Game 공동 우승자 출력`() { - val leeCar = Car("lee", 5) - val kkoksCar = Car("kkoks", 5) + val leeCar = Car.produce("lee", 5) + val kkoksCar = Car.produce("kkoks", 5) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() assertThat(result).isEqualTo("lee, kkoks") From 00d1fa159405fc6147c70e9a999ab3573c5d8f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Wed, 9 Nov 2022 00:59:38 +0900 Subject: [PATCH 29/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Expression.kt | 54 +++++++++---------- src/main/kotlin/calculator/Num.kt | 2 +- .../kotlin/calculator/StringCalculator.kt | 36 ++++++++++--- .../kotlin/calculator/StringCalculatorTest.kt | 31 +++++++++-- 4 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt index 266cbf6dfc..5349ac851f 100644 --- a/src/main/kotlin/calculator/Expression.kt +++ b/src/main/kotlin/calculator/Expression.kt @@ -4,52 +4,50 @@ import java.util.LinkedList import java.util.Queue class Expression( - private var _mathematical: String + val input: String ) { - private val mathematical: String - get() = _mathematical - - init { - _mathematical = _mathematical.replace(" ", "") - verifyMathematical(_mathematical) - } - - fun compute(): Queue { - return polynomial(mathematical) + fun apply(): Queue { + val queue = createOperandAndOperatorQueue(input) + if (queue.size % 2 == 0) throw IllegalArgumentException() + return queue } private fun priorityIndexes(data: String): List { - return data.filter { c -> isOperatorLetter(c) }.toList() + val priorityList = mutableListOf() + + for (c in data) { + if (isOperatorLetter(c)) { + priorityList.add(c) + } + } + + return priorityList } private fun isOperatorLetter(c: Char): Boolean { - return Operator.exist(c) + for (operator in Operator.values()) { + if (operator.isSame(c)) { + return true + } + } + return false } - private fun polynomial(mathematical: String): Queue { + private fun createOperandAndOperatorQueue(data: String): Queue { - var newMathematical = mathematical - val sortedPriorityList = priorityIndexes(mathematical) + var temp = data + val sortedPriorityList = priorityIndexes(data) val queue = LinkedList() for (operator in sortedPriorityList) { - val operand = newMathematical.substringBefore(operator.toString()) + val operand = temp.substringBefore(operator.toString()) queue.add(operand) queue.add(operator.toString()) - newMathematical = newMathematical.substringAfter(operator.toString()) + temp = temp.substringAfter(operator.toString()) } - queue.add(newMathematical) - if (queue.size % 2 == 0) throw IllegalArgumentException() + queue.add(temp) return queue } - - private fun verifyMathematical(mathematical: String) { - val splitData = mathematical.split(*Operator.list().toTypedArray()) - - if (splitData.size != mathematical.length - (mathematical.length / 2)) { - throw IllegalArgumentException() - } - } } diff --git a/src/main/kotlin/calculator/Num.kt b/src/main/kotlin/calculator/Num.kt index 6240f6ed32..fd2a916ce3 100644 --- a/src/main/kotlin/calculator/Num.kt +++ b/src/main/kotlin/calculator/Num.kt @@ -2,7 +2,7 @@ package calculator data class Num(var value: Int) { - constructor(value: String) : this(value.toIntOrNull() ?: throw IllegalArgumentException()) + constructor(value: String) : this(Integer.parseInt(value)) fun add(number: Num) = Num(this.value + number.value) diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt index 880f0d6d9d..760be04360 100644 --- a/src/main/kotlin/calculator/StringCalculator.kt +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -2,21 +2,43 @@ package calculator class StringCalculator { - fun calculate(mathematical: String): Num { + fun calculate(input: String): Num { - val expression = Expression(mathematical) - val queue = expression.compute() + val data = removeSpace(input) + verifyOperator(data) + + val expression = Expression(data) + val queue = expression.apply() var result = Num(queue.poll()) while (queue.isNotEmpty()) { - val operator = Operator(queue.poll().first()) - val second = Num(queue.poll()) - result = calculate(result, second, operator) + val operator = queue.poll() + val operand = queue.poll() + val o = Operator(operator.first()) + result = o.calculate(result, Num(operand)) } return result } - private fun calculate(first: Num, second: Num, operator: Operator) = operator.calculate(first, second) + private fun removeSpace(input: String): String { + return input.replace(" ", "") + } + + private fun verifyOperator(data: String) { + val splitData = data.split("+", "-", "*", "/") + + if (splitData.size != data.length - (data.length / 2)) { + throw IllegalArgumentException() + } + + for (c in splitData) { + try { + Integer.parseInt(c) + } catch (e: NumberFormatException) { + throw IllegalArgumentException() + } + } + } } diff --git a/src/test/kotlin/calculator/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt index 590d68e278..e9ca3b8612 100644 --- a/src/test/kotlin/calculator/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -8,6 +8,27 @@ import org.junit.jupiter.params.provider.ValueSource class StringCalculatorTest { + @Test + fun `문자열 자르기`() { + + val input = "1234-5678-9000" + + val substringBefore = input.substringBefore("-") + val substringAfter = input.substringAfter("-") + + assertThat(substringBefore).isEqualTo("1234") + assertThat(substringAfter).isEqualTo("5678-9000") + } + + @Test + fun `인덱스 가져오기`() { + + var input = "2 + 3 * 4 / 2" + input = input.replace(" ", "") + val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } + assertThat(index).isEqualTo(1) + } + @Test fun `덧셈`() { val input = "2 + 3" @@ -56,20 +77,20 @@ class StringCalculatorTest { @ParameterizedTest @ValueSource(strings = ["2 ! 3 * 4 / 2", "23 * 22A * 1"]) - fun `사칙연산 기호가 아닌경우`(mathematical: String) { + fun `사칙연산 기호가 아닌경우`(input: String) { val stringCalculator = StringCalculator() assertThrows { - stringCalculator.calculate(mathematical) + stringCalculator.calculate(input) } } @Test - fun `사칙연산을 실행한다`() { + fun `사칙연산 기능 구현`() { - val mathematical = "2 + 3 * 4 / 2" + val input = "2 + 3 * 4 / 2" val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(mathematical) + val result = stringCalculator.calculate(input) assertThat(result).isEqualTo(Num(10)) } From 1252ad6f89d84df13d41dc36b8cab87250e9b845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 12 Nov 2022 16:00:14 +0900 Subject: [PATCH 30/49] =?UTF-8?q?=20:=20racing=20game=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Route.kt | 3 +++ src/main/kotlin/racing/domain/Routes.kt | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/main/kotlin/racing/domain/Route.kt create mode 100644 src/main/kotlin/racing/domain/Routes.kt diff --git a/src/main/kotlin/racing/domain/Route.kt b/src/main/kotlin/racing/domain/Route.kt new file mode 100644 index 0000000000..69bdc95d03 --- /dev/null +++ b/src/main/kotlin/racing/domain/Route.kt @@ -0,0 +1,3 @@ +package racing.domain + +class Route() diff --git a/src/main/kotlin/racing/domain/Routes.kt b/src/main/kotlin/racing/domain/Routes.kt new file mode 100644 index 0000000000..c9fd56ec0c --- /dev/null +++ b/src/main/kotlin/racing/domain/Routes.kt @@ -0,0 +1,13 @@ +package racing.domain + +class Routes { + + private val list = mutableListOf() + + fun add() { + list.add(Route()) + } + + fun stream() = list.stream() + fun size() = list.size +} From ad82787fc3f109a6aba814c0897e4c93f20cb480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 5 Nov 2022 20:50:11 +0900 Subject: [PATCH 31/49] =?UTF-8?q?=20:=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81,=20?= =?UTF-8?q?=ED=91=9C=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Operator.kt | 29 -------- src/main/kotlin/StringCalculator.kt | 79 -------------------- src/test/kotlin/StringCalculatorTest.kt | 95 ------------------------- 3 files changed, 203 deletions(-) delete mode 100644 src/main/kotlin/Operator.kt delete mode 100644 src/main/kotlin/StringCalculator.kt delete mode 100644 src/test/kotlin/StringCalculatorTest.kt diff --git a/src/main/kotlin/Operator.kt b/src/main/kotlin/Operator.kt deleted file mode 100644 index e49a6faafe..0000000000 --- a/src/main/kotlin/Operator.kt +++ /dev/null @@ -1,29 +0,0 @@ -enum class Operator(val sign: Char) { - PLUS('+') { - override fun calculate(a: Int, b: Int): Int = a + b - }, - MINUS('-') { - override fun calculate(a: Int, b: Int): Int = a - b - }, - MULTIPLY('*') { - override fun calculate(a: Int, b: Int): Int = a * b - }, - DIVIDE('/') { - override fun calculate(a: Int, b: Int): Int = a / b - }; - - abstract fun calculate(a: Int, b: Int): Int - - fun equals(sign: Char): Boolean = this.sign == sign - - companion object { - operator fun invoke(sign: Char): Operator { - for (operator in Operator.values()) { - if (operator.sign == sign) { - return operator - } - } - throw IllegalArgumentException() - } - } -} diff --git a/src/main/kotlin/StringCalculator.kt b/src/main/kotlin/StringCalculator.kt deleted file mode 100644 index f24b553c25..0000000000 --- a/src/main/kotlin/StringCalculator.kt +++ /dev/null @@ -1,79 +0,0 @@ -import java.util.LinkedList -import java.util.Queue - -class StringCalculator { - - fun calculate(input: String): Int { - - if (input.isNullOrEmpty()) { - throw IllegalArgumentException() - } - - var data = input.replace(" ", "") - verifyOperator(data) - val sortedPriorityList = priorityIndexes(data) - val queue = createOperandAndOperatorQueue(data, sortedPriorityList) - - var result: Int = Integer.parseInt(queue.poll()) - - if (queue.size % 2 != 0) { - throw IllegalStateException() - } - - while (!queue.isEmpty()) { - val operator = queue.poll() - val operand = queue.poll() - - val o = Operator(operator.first()) - result = o.calculate(result, Integer.parseInt(operand)) - } - - return result - } - - private fun verifyOperator(data: String) { - for (c in data) { - var isOperator = false - for (operator in Operator.values()) { - if (operator.equals(c)) { - isOperator = true - } - } - if (!isOperator && (c < 48.toChar() || c > 57.toChar())) { - throw IllegalArgumentException() - } - } - } - - private fun priorityIndexes(data: String): List> { - val priorityList = mutableListOf>() - - for (operator in Operator.values()) { - val index = data.indexOfFirst { c -> operator.equals(c) } - if (index > -1) { - val pair: Pair = Pair(operator.sign, index) - priorityList.add(pair) - } - } - - return priorityList.sortedBy { pair -> pair.second } - } - - private fun createOperandAndOperatorQueue(data: String, sortedPriorityList: List>): Queue { - - var temp = data - val queue = LinkedList() - - for (pair in sortedPriorityList) { - val operand = temp.substringBefore(pair.first.toString()) - if (!operand.isNullOrEmpty()) { - queue.add(operand) - queue.add(pair.first.toString()) - temp = temp.substringAfter(pair.first.toString()) - } - } - - queue.add(temp) - return queue - } -} diff --git a/src/test/kotlin/StringCalculatorTest.kt b/src/test/kotlin/StringCalculatorTest.kt deleted file mode 100644 index 41a6f77acf..0000000000 --- a/src/test/kotlin/StringCalculatorTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource - -class StringCalculatorTest { - - @Test - fun `문자열 자르기`() { - - val input = "1234-5678-9000" - - val substringBefore = input.substringBefore("-") - val substringAfter = input.substringAfter("-") - - assertThat(substringBefore).isEqualTo("1234") - assertThat(substringAfter).isEqualTo("5678-9000") - } - - @Test - fun `인덱스 가져오기`() { - - var input = "2 + 3 * 4 / 2" - input = input.replace(" ", "") - val index = input.indexOfFirst { c -> Operator.PLUS.equals(c) } - assertThat(index).isEqualTo(1) - } - - @Test - fun `덧셈`() { - val input = "2 + 3" - val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(5) - } - - @Test - fun `뺄셈`() { - - val input = "3 - 2" - val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(1) - } - - @Test - fun `곱셈`() { - - val input = "2 * 4" - val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(8) - } - - @Test - fun `나눗셈`() { - - val input = "4 / 2" - val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) - assertThat(result).isEqualTo(2) - } - - @ParameterizedTest - @ValueSource(strings = ["", " "]) - fun `입력값이 null 이거나 빈 공백문자 일경우`(input: String) { - - val stringCalculator = StringCalculator() - - assertThrows { - stringCalculator.calculate(input) - } - } - - @Test - fun `사칙연산 기호가 아닌경우`() { - - val input = "2 ! 3 * 4 / 2" - val stringCalculator = StringCalculator() - assertThrows { - stringCalculator.calculate(input) - } - } - - @Test - fun `사칙연산 기능 구현`() { - - val input = "2 + 3 * 4 / 2" - val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) - - assertThat(result).isEqualTo(10) - } -} From 663a61263e512ce103e5d5e8eae1143d27f35dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Thu, 17 Nov 2022 00:00:12 +0900 Subject: [PATCH 32/49] =?UTF-8?q?[feat]:=20step3=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Route.kt | 3 --- src/main/kotlin/racing/domain/Routes.kt | 13 ------------- 2 files changed, 16 deletions(-) delete mode 100644 src/main/kotlin/racing/domain/Route.kt delete mode 100644 src/main/kotlin/racing/domain/Routes.kt diff --git a/src/main/kotlin/racing/domain/Route.kt b/src/main/kotlin/racing/domain/Route.kt deleted file mode 100644 index 69bdc95d03..0000000000 --- a/src/main/kotlin/racing/domain/Route.kt +++ /dev/null @@ -1,3 +0,0 @@ -package racing.domain - -class Route() diff --git a/src/main/kotlin/racing/domain/Routes.kt b/src/main/kotlin/racing/domain/Routes.kt deleted file mode 100644 index c9fd56ec0c..0000000000 --- a/src/main/kotlin/racing/domain/Routes.kt +++ /dev/null @@ -1,13 +0,0 @@ -package racing.domain - -class Routes { - - private val list = mutableListOf() - - fun add() { - list.add(Route()) - } - - fun stream() = list.stream() - fun size() = list.size -} From ccd1f788931fec4ebf3629f7cea4a57b48788abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Thu, 17 Nov 2022 23:58:11 +0900 Subject: [PATCH 33/49] =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racing/RandomGeneratorTest.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index c33cc0ad7f..8c213d3032 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -8,8 +8,10 @@ class RandomGeneratorTest { @RepeatedTest(value = 5) fun `랜덤숫자 발행 테스트`() { - val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThanOrEqualTo(0) - assertThat(randomNumber).isLessThanOrEqualTo(9) + for (i in 1..9) { + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) + } } } From e966f5d4d286708971120ae27ee3e193e087adbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:35:57 +0900 Subject: [PATCH 34/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racing/RandomGeneratorTest.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/racing/RandomGeneratorTest.kt b/src/test/kotlin/racing/RandomGeneratorTest.kt index 8c213d3032..c33cc0ad7f 100644 --- a/src/test/kotlin/racing/RandomGeneratorTest.kt +++ b/src/test/kotlin/racing/RandomGeneratorTest.kt @@ -8,10 +8,8 @@ class RandomGeneratorTest { @RepeatedTest(value = 5) fun `랜덤숫자 발행 테스트`() { - for (i in 1..9) { - val randomNumber = RandomGenerator.generate() - assertThat(randomNumber).isGreaterThanOrEqualTo(0) - assertThat(randomNumber).isLessThanOrEqualTo(9) - } + val randomNumber = RandomGenerator.generate() + assertThat(randomNumber).isGreaterThanOrEqualTo(0) + assertThat(randomNumber).isLessThanOrEqualTo(9) } } From bb2be546124eedff5e93adceaf63203fc8a94fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:41:17 +0900 Subject: [PATCH 35/49] =?UTF-8?q?=20:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20README.md=EC=97=90=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 64924a267d..d124634a36 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # kotlin-racingcar - [o] 자동차 생성 - - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. + - [] 자동차에 이름을 부여할 수 있다. + - [] 자동차의 이름은 5글자를 초과할 수 없다. + - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. +- [o] 자동차의 움직임 + - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. + - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. - [o] 클라이언트로부터 값을 입력받을 수 있다. -- [o] 실행결과를 출력한다. \ No newline at end of file +- [o] 실행결과를 출력한다. + - [] 매 횟수마다 출력한다. + - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. + - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From 68d6e54a7f179934d578e2cf463ddd795139001e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:42:17 +0900 Subject: [PATCH 36/49] =?UTF-8?q?=20:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d124634a36..c694347bd1 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. -- [o] 클라이언트로부터 값을 입력받을 수 있다. -- [o] 실행결과를 출력한다. +- [] 클라이언트로부터 값을 입력받을 수 있다. + - [] 자동차의 이름은 쉼표(,)로 구분할 수 있다. + +- [] 실행결과를 출력한다. - [] 매 횟수마다 출력한다. - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From a2dc93d9940730ac61616dec90e2234b4ac8dee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:50:23 +0900 Subject: [PATCH 37/49] =?UTF-8?q?=20:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=EC=97=90=20=EC=9D=B4=EB=A6=84=20=EB=B6=80=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/domain/Car.kt | 2 +- src/main/kotlin/racing/domain/CarFactory.kt | 4 ++-- src/main/kotlin/racing/domain/Cars.kt | 10 +++++++--- src/main/kotlin/racing/domain/RacingGame.kt | 4 ++-- src/main/kotlin/racing/ui/InputView.kt | 12 +++++++----- src/test/kotlin/racing/CarTest.kt | 11 +++++++---- src/test/kotlin/racing/RacingGameTest.kt | 3 ++- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c694347bd1..6b1d9ebe18 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # kotlin-racingcar - [o] 자동차 생성 - - [] 자동차에 이름을 부여할 수 있다. + - [o] 자동차에 이름을 부여할 수 있다. - [] 자동차의 이름은 5글자를 초과할 수 없다. - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. - [o] 자동차의 움직임 diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index e187c38527..a6ced45378 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,6 +1,6 @@ package racing.domain -class Car(position: Int = 0) { +class Car(name: String, position: Int = 0) { var position = position private set diff --git a/src/main/kotlin/racing/domain/CarFactory.kt b/src/main/kotlin/racing/domain/CarFactory.kt index 6c8dab7711..0d6f69d203 100644 --- a/src/main/kotlin/racing/domain/CarFactory.kt +++ b/src/main/kotlin/racing/domain/CarFactory.kt @@ -3,8 +3,8 @@ package racing.domain class CarFactory { companion object { - fun create(count: Int): Cars { - return Cars(count) + fun create(names: String): Cars { + return Cars(names) } } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 7a7ce34e94..81ece62679 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,12 +1,12 @@ package racing.domain -class Cars(count: Int) : Iterable { +class Cars(names: String) : Iterable { private val list: List init { - list = List(count) { - Car() + list = names.split(SEPARATOR).map { + Car(it) } } @@ -19,4 +19,8 @@ class Cars(count: Int) : Iterable { } } override fun iterator(): Iterator = list.iterator() + + companion object { + const val SEPARATOR = "," + } } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 22a73c2d95..555a5b48a9 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -7,8 +7,8 @@ class RacingGame { fun start() { - val carCount = InputView.requireCarsCount() - val cars = CarFactory.create(carCount) + val carNames = InputView.requireRacingCarNames() + val cars = CarFactory.create(carNames) var numberOfGames = InputView.requireNumberOfGames() while (numberOfGames-- > 0) { diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt index ae2f84ef99..cc5124981a 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -4,16 +4,18 @@ class InputView { companion object { - fun requireCarsCount(): Int { - println("자동차 대수는 몇 대인가요?") - return inputNumber() + fun requireRacingCarNames(): String { + println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분") + return readString() } fun requireNumberOfGames(): Int { println("시도할 횟수는 몇 회인가요?") - return inputNumber() + return readNum() } - private fun inputNumber() = readln().toInt() + private fun readNum() = readln().toInt() + + private fun readString() = readln() } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 353b35322f..2b2341c591 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -10,15 +10,17 @@ import racing.domain.Cars class CarTest { @Test - fun `자동차 생성`() { - val cars: Cars = CarFactory.create(3) + fun `자동차를 생성한다`() { + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) AssertionsForInterfaceTypes.assertThat(cars.count()).isEqualTo(3) } @ParameterizedTest @ValueSource(ints = [4, 9]) fun `자동차 이동`(num: Int) { - val cars: Cars = CarFactory.create(3) + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) @@ -28,7 +30,8 @@ class CarTest { @ParameterizedTest @ValueSource(ints = [0, 3]) fun `자동차 이동실패`(num: Int) { - val cars: Cars = CarFactory.create(3) + val names = "lee,kkoks,amery" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 09d2fcba1a..4fb85df4d6 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -10,7 +10,8 @@ class RacingGameTest { @Test fun `실행결과 출력`() { - val cars: Cars = CarFactory.create(2) + val names = "lee,kkoks" + val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(4) } From c7bf83775815fc28934d751d7fac14ee6aed38af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:54:29 +0900 Subject: [PATCH 38/49] =?UTF-8?q?=20:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=A6=84=EC=9D=B4=205=EA=B8=80=EC=9E=90?= =?UTF-8?q?=EB=B3=B4=EB=8B=A4=20=ED=81=B4=EA=B2=BD=EC=9A=B0=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++----- src/main/kotlin/racing/domain/Car.kt | 6 ++++++ src/test/kotlin/racing/CarTest.kt | 19 ++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6b1d9ebe18..a2b6dea879 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ - [o] 자동차 생성 - [o] 자동차에 이름을 부여할 수 있다. - - [] 자동차의 이름은 5글자를 초과할 수 없다. - - [] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. + - [o] 자동차의 이름은 5글자를 초과할 수 없다. + - [o] 자동차의 이름이 5글자를 초과하면 예외를 발생시킨다. - [o] 자동차의 움직임 - [o] 자동차는 4~9 범위 사이일때 움직일 수 있다. - [o] 자동차는 0~3 범위 사이에는 움직일 수 없다. - [o] 무작위 값은 0~9 범위 사이이다. -- [] 클라이언트로부터 값을 입력받을 수 있다. - - [] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - +- [o] 클라이언트로부터 값을 입력받을 수 있다. + - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - [] 실행결과를 출력한다. - [] 매 횟수마다 출력한다. - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index a6ced45378..8b54bbe222 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -5,6 +5,11 @@ class Car(name: String, position: Int = 0) { var position = position private set + init { + if (name.length > CAR_NAME_LIMIT) + throw IllegalArgumentException("자동차의 이름은 ${CAR_NAME_LIMIT}글자를 초과할 수 없습니다.") + } + fun move(num: Int) { if (num >= FORWARD_MOVE) { position++ @@ -13,5 +18,6 @@ class Car(name: String, position: Int = 0) { companion object { const val FORWARD_MOVE: Int = 4 + const val CAR_NAME_LIMIT: Int = 5 } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 2b2341c591..254f37c0b5 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -1,7 +1,8 @@ package racing -import org.assertj.core.api.AssertionsForInterfaceTypes +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import racing.domain.CarFactory @@ -10,10 +11,18 @@ import racing.domain.Cars class CarTest { @Test - fun `자동차를 생성한다`() { + fun `자동차를 생성할 때 자동차의 이름은 5글자 이하이다`() { val names = "lee,kkoks,amery" val cars: Cars = CarFactory.create(names) - AssertionsForInterfaceTypes.assertThat(cars.count()).isEqualTo(3) + assertThat(cars.count()).isEqualTo(3) + } + + @Test + fun `자동차를 생성할 때 자동차의 이름은 5글자를 초과한다`() { + val names = "leejhw,kkoks,amery" + assertThrows { + CarFactory.create(names) + } } @ParameterizedTest @@ -23,7 +32,7 @@ class CarTest { val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) - AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(1) + assertThat(car.position).isEqualTo(1) } } @@ -34,7 +43,7 @@ class CarTest { val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) - AssertionsForInterfaceTypes.assertThat(car.position).isEqualTo(0) + assertThat(car.position).isEqualTo(0) } } } From 21b416079659115410f64cc6bebf9ce0c306fbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 20:59:33 +0900 Subject: [PATCH 39/49] =?UTF-8?q?=20:=20=EB=A7=A4=20=ED=9A=9F?= =?UTF-8?q?=EC=88=98=EB=A7=88=EB=8B=A4=20=EC=8B=A4=ED=96=89=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/kotlin/racing/domain/Car.kt | 2 ++ src/main/kotlin/racing/domain/RacingGame.kt | 3 +-- src/main/kotlin/racing/domain/ResultStatistics.kt | 2 +- src/test/kotlin/racing/RacingGameTest.kt | 7 ++++++- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a2b6dea879..d075c839a9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,6 @@ - [o] 클라이언트로부터 값을 입력받을 수 있다. - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. - [] 실행결과를 출력한다. - - [] 매 횟수마다 출력한다. - - [] 매 횟수마다 전진하는 자동차의 이름도 출력한다. + - [o] 매 횟수마다 출력한다. + - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 8b54bbe222..7f0ce91c05 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -2,6 +2,8 @@ package racing.domain class Car(name: String, position: Int = 0) { + var name = name + private set var position = position private set diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 555a5b48a9..1aebad953c 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -15,8 +15,7 @@ class RacingGame { cars.race { RandomGenerator.generate() } + ResultView.printGameResult(ResultStatistics(cars).toResult()) } - - ResultView.printGameResult(ResultStatistics(cars).toResult()) } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index d219320c28..241cc00d49 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -3,7 +3,7 @@ package racing.domain class ResultStatistics(private val cars: Cars) { fun toResult(): String { - return cars.map { toMark(it) }.joinToString(separator = System.lineSeparator()) + return cars.map { "${it.name}: ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() } private fun toMark(car: Car): String { diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4fb85df4d6..cccd1638c2 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -15,6 +15,11 @@ class RacingGameTest { for (car in cars) { car.move(4) } - assertThat(ResultStatistics(cars).toResult()).isEqualTo("-${System.lineSeparator()}-") + + val result = """ + lee: - + kkoks: - + """.trimIndent() + assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) } } From 20bec37c2ab722d341ed5267ab67936d6c2214c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:01:15 +0900 Subject: [PATCH 40/49] =?UTF-8?q?=20:=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/RacingGame.kt | 3 ++- src/main/kotlin/racing/domain/ResultStatistics.kt | 2 +- src/main/kotlin/racing/ui/ResultView.kt | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 1aebad953c..a4aa7f0fb7 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -11,11 +11,12 @@ class RacingGame { val cars = CarFactory.create(carNames) var numberOfGames = InputView.requireNumberOfGames() + ResultView.printRacingGameGuideText() while (numberOfGames-- > 0) { cars.race { RandomGenerator.generate() } - ResultView.printGameResult(ResultStatistics(cars).toResult()) + ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) } } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt index 241cc00d49..43293a0dff 100644 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ b/src/main/kotlin/racing/domain/ResultStatistics.kt @@ -3,7 +3,7 @@ package racing.domain class ResultStatistics(private val cars: Cars) { fun toResult(): String { - return cars.map { "${it.name}: ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() + return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() } private fun toMark(car: Car): String { diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index f323d39590..5f034992f7 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -3,8 +3,11 @@ package racing.ui class ResultView { companion object { - fun printGameResult(result: String) { + + fun printRacingGameGuideText() { println("실행결과") + } + fun printRacingGameResult(result: String) { println(result) } } From c6634b0788ee0ddcea27e7a1d08cb197ef1d6d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:20:29 +0900 Subject: [PATCH 41/49] =?UTF-8?q?=20:=20=EC=9A=B0=EC=8A=B9=EC=9E=90?= =?UTF-8?q?=20=EC=84=A0=EC=A0=95=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/domain/Car.kt | 15 +++++++++++++++ src/main/kotlin/racing/domain/Winner.kt | 14 ++++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 24 ++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/racing/domain/Winner.kt diff --git a/README.md b/README.md index d075c839a9..53dfcc17f4 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ - [] 실행결과를 출력한다. - [o] 매 횟수마다 출력한다. - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - - [] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file + - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 7f0ce91c05..57cd2c9255 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -18,6 +18,21 @@ class Car(name: String, position: Int = 0) { } } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Car + + if (name != other.name) return false + + return true + } + + override fun hashCode(): Int { + return name.hashCode() + } + companion object { const val FORWARD_MOVE: Int = 4 const val CAR_NAME_LIMIT: Int = 5 diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt new file mode 100644 index 0000000000..ae9d03ade6 --- /dev/null +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -0,0 +1,14 @@ +package racing.domain + +class Winner(cars: Cars) { + + var cars = cars + private set + + constructor(carList: List) : this(Cars(carList.map { it.name }.joinToString(","))) + + fun win(): List { + val maxPosition = cars.maxOf { it.position } + return cars.filter { it.position == maxPosition } + } +} diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index cccd1638c2..4b41a43a4e 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -2,9 +2,11 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.junit.jupiter.api.Test +import racing.domain.Car import racing.domain.CarFactory import racing.domain.Cars import racing.domain.ResultStatistics +import racing.domain.Winner class RacingGameTest { @@ -17,9 +19,27 @@ class RacingGameTest { } val result = """ - lee: - - kkoks: - + lee : - + kkoks : - """.trimIndent() assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) } + + @Test + fun `Racing Game 단독 우승자 출력`() { + val leeCar = Car("lee", 5) + val kkoksCar = Car("kkoks", 3) + val winner = Winner(listOf(leeCar, kkoksCar)) + val result = winner.win() + assertThat(result).contains(leeCar) + } + + @Test + fun `Racing Game 공동 우승자 출력`() { + val leeCar = Car("lee", 5) + val kkoksCar = Car("kkoks", 5) + val winner = Winner(listOf(leeCar, kkoksCar)) + val result = winner.win() + assertThat(result).containsAll(listOf(leeCar, kkoksCar)) + } } From 00a1c52ac6b0057ccbff289f20fde76617be9c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:20:55 +0900 Subject: [PATCH 42/49] =?UTF-8?q?=20:=20README.md=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53dfcc17f4..7b97fcae21 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [o] 무작위 값은 0~9 범위 사이이다. - [o] 클라이언트로부터 값을 입력받을 수 있다. - [o] 자동차의 이름은 쉼표(,)로 구분할 수 있다. -- [] 실행결과를 출력한다. +- [o] 실행결과를 출력한다. - [o] 매 횟수마다 출력한다. - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file From 9590f95b6c20d9e14b2b8e27903594b98a555cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 19 Nov 2022 21:31:41 +0900 Subject: [PATCH 43/49] =?UTF-8?q?=20:=20=EC=9A=B0=EC=8A=B9=EC=9E=90?= =?UTF-8?q?=20=EC=B6=94=EC=B6=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Cars.kt | 7 +++++-- src/main/kotlin/racing/domain/RacingGame.kt | 2 ++ src/main/kotlin/racing/domain/Winner.kt | 6 +++--- src/main/kotlin/racing/ui/ResultView.kt | 4 ++++ src/test/kotlin/racing/RacingGameTest.kt | 4 ++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 81ece62679..d808a241f7 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,14 +1,17 @@ package racing.domain -class Cars(names: String) : Iterable { +class Cars : Iterable { private val list: List - init { + constructor(names: String) { list = names.split(SEPARATOR).map { Car(it) } } + constructor(carList: List) { + list = carList + } fun count() = list.size diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index a4aa7f0fb7..2e39e1f5d1 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -18,5 +18,7 @@ class RacingGame { } ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) } + val winner = Winner(cars) + ResultView.printRacingGameWinner(winner.win()) } } diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt index ae9d03ade6..ede4483e1e 100644 --- a/src/main/kotlin/racing/domain/Winner.kt +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -5,10 +5,10 @@ class Winner(cars: Cars) { var cars = cars private set - constructor(carList: List) : this(Cars(carList.map { it.name }.joinToString(","))) + constructor(carList: List) : this(Cars(carList)) - fun win(): List { + fun win(): String { val maxPosition = cars.maxOf { it.position } - return cars.filter { it.position == maxPosition } + return cars.filter { it.position == maxPosition }.joinToString { it.name } } } diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 5f034992f7..419495c456 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -10,5 +10,9 @@ class ResultView { fun printRacingGameResult(result: String) { println(result) } + + fun printRacingGameWinner(winner: String) { + println("${winner}가 최종 우승했습니다.") + } } } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 4b41a43a4e..35acf894af 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -31,7 +31,7 @@ class RacingGameTest { val kkoksCar = Car("kkoks", 3) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() - assertThat(result).contains(leeCar) + assertThat(result).isEqualTo("lee") } @Test @@ -40,6 +40,6 @@ class RacingGameTest { val kkoksCar = Car("kkoks", 5) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() - assertThat(result).containsAll(listOf(leeCar, kkoksCar)) + assertThat(result).isEqualTo("lee, kkoks") } } From 05bde2eaf58a884907350c0989b2a638cb8e3594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Mon, 21 Nov 2022 23:15:19 +0900 Subject: [PATCH 44/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 1 + src/main/kotlin/racing/domain/Cars.kt | 4 ++-- src/main/kotlin/racing/domain/RacingGame.kt | 6 ++---- src/main/kotlin/racing/domain/RandomGenerator.kt | 2 +- .../kotlin/racing/domain/ResultStatistics.kt | 16 ---------------- src/main/kotlin/racing/ui/ResultView.kt | 13 +++++++++++++ src/test/kotlin/racing/RacingGameTest.kt | 12 ++++++------ 7 files changed, 25 insertions(+), 29 deletions(-) delete mode 100644 src/main/kotlin/racing/domain/ResultStatistics.kt diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 57cd2c9255..30fabc9172 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -36,5 +36,6 @@ class Car(name: String, position: Int = 0) { companion object { const val FORWARD_MOVE: Int = 4 const val CAR_NAME_LIMIT: Int = 5 + fun produce(name: String, position: Int = 0) = Car(name, position) } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index d808a241f7..c9d8b41a9b 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -6,7 +6,7 @@ class Cars : Iterable { constructor(names: String) { list = names.split(SEPARATOR).map { - Car(it) + Car.produce(it) } } constructor(carList: List) { @@ -18,7 +18,7 @@ class Cars : Iterable { fun race(movable: () -> Int) { list.forEach { car -> - car.move(movable.invoke()) + car.move(movable()) } } override fun iterator(): Iterator = list.iterator() diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 2e39e1f5d1..65c319dada 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -13,10 +13,8 @@ class RacingGame { ResultView.printRacingGameGuideText() while (numberOfGames-- > 0) { - cars.race { - RandomGenerator.generate() - } - ResultView.printRacingGameResult(ResultStatistics(cars).toResult()) + cars.race { RandomGenerator.generate() } + ResultView.printRacingGameResult(ResultView.toRaceResult(cars)) } val winner = Winner(cars) ResultView.printRacingGameWinner(winner.win()) diff --git a/src/main/kotlin/racing/domain/RandomGenerator.kt b/src/main/kotlin/racing/domain/RandomGenerator.kt index 9a9946e7bd..28f70d7ecd 100644 --- a/src/main/kotlin/racing/domain/RandomGenerator.kt +++ b/src/main/kotlin/racing/domain/RandomGenerator.kt @@ -3,6 +3,6 @@ package racing.domain class RandomGenerator { companion object { - fun generate(): Int = (0..9).random() + fun generate() = (0..9).random() } } diff --git a/src/main/kotlin/racing/domain/ResultStatistics.kt b/src/main/kotlin/racing/domain/ResultStatistics.kt deleted file mode 100644 index 43293a0dff..0000000000 --- a/src/main/kotlin/racing/domain/ResultStatistics.kt +++ /dev/null @@ -1,16 +0,0 @@ -package racing.domain - -class ResultStatistics(private val cars: Cars) { - - fun toResult(): String { - return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() - } - - private fun toMark(car: Car): String { - return MARK.repeat(car.position) - } - - companion object { - const val MARK: String = "-" - } -} diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 419495c456..2219bcaada 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -1,12 +1,23 @@ package racing.ui +import racing.domain.Car +import racing.domain.Cars + class ResultView { companion object { + fun toRaceResult(cars: Cars): String { + return cars.map { "${it.name} : ${toMark(it)}" }.joinToString(separator = System.lineSeparator()).trimIndent() + } + + private fun toMark(car: Car): String { + return MARK.repeat(car.position) + } fun printRacingGameGuideText() { println("실행결과") } + fun printRacingGameResult(result: String) { println(result) } @@ -14,5 +25,7 @@ class ResultView { fun printRacingGameWinner(winner: String) { println("${winner}가 최종 우승했습니다.") } + + const val MARK = "-" } } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 35acf894af..e75c2ac5fa 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -5,8 +5,8 @@ import org.junit.jupiter.api.Test import racing.domain.Car import racing.domain.CarFactory import racing.domain.Cars -import racing.domain.ResultStatistics import racing.domain.Winner +import racing.ui.ResultView class RacingGameTest { @@ -22,13 +22,13 @@ class RacingGameTest { lee : - kkoks : - """.trimIndent() - assertThat(ResultStatistics(cars).toResult()).isEqualTo(result) + assertThat(ResultView.toRaceResult(cars)).isEqualTo(result) } @Test fun `Racing Game 단독 우승자 출력`() { - val leeCar = Car("lee", 5) - val kkoksCar = Car("kkoks", 3) + val leeCar = Car.produce("lee", 5) + val kkoksCar = Car.produce("kkoks", 3) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() assertThat(result).isEqualTo("lee") @@ -36,8 +36,8 @@ class RacingGameTest { @Test fun `Racing Game 공동 우승자 출력`() { - val leeCar = Car("lee", 5) - val kkoksCar = Car("kkoks", 5) + val leeCar = Car.produce("lee", 5) + val kkoksCar = Car.produce("kkoks", 5) val winner = Winner(listOf(leeCar, kkoksCar)) val result = winner.win() assertThat(result).isEqualTo("lee, kkoks") From 81075ed90410de37c9c0e978f204aa8138e4fa18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Wed, 9 Nov 2022 00:59:38 +0900 Subject: [PATCH 45/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Expression.kt | 54 +++++++++---------- src/main/kotlin/calculator/Num.kt | 2 +- .../kotlin/calculator/StringCalculator.kt | 36 ++++++++++--- .../kotlin/calculator/StringCalculatorTest.kt | 31 +++++++++-- 4 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt index 266cbf6dfc..5349ac851f 100644 --- a/src/main/kotlin/calculator/Expression.kt +++ b/src/main/kotlin/calculator/Expression.kt @@ -4,52 +4,50 @@ import java.util.LinkedList import java.util.Queue class Expression( - private var _mathematical: String + val input: String ) { - private val mathematical: String - get() = _mathematical - - init { - _mathematical = _mathematical.replace(" ", "") - verifyMathematical(_mathematical) - } - - fun compute(): Queue { - return polynomial(mathematical) + fun apply(): Queue { + val queue = createOperandAndOperatorQueue(input) + if (queue.size % 2 == 0) throw IllegalArgumentException() + return queue } private fun priorityIndexes(data: String): List { - return data.filter { c -> isOperatorLetter(c) }.toList() + val priorityList = mutableListOf() + + for (c in data) { + if (isOperatorLetter(c)) { + priorityList.add(c) + } + } + + return priorityList } private fun isOperatorLetter(c: Char): Boolean { - return Operator.exist(c) + for (operator in Operator.values()) { + if (operator.isSame(c)) { + return true + } + } + return false } - private fun polynomial(mathematical: String): Queue { + private fun createOperandAndOperatorQueue(data: String): Queue { - var newMathematical = mathematical - val sortedPriorityList = priorityIndexes(mathematical) + var temp = data + val sortedPriorityList = priorityIndexes(data) val queue = LinkedList() for (operator in sortedPriorityList) { - val operand = newMathematical.substringBefore(operator.toString()) + val operand = temp.substringBefore(operator.toString()) queue.add(operand) queue.add(operator.toString()) - newMathematical = newMathematical.substringAfter(operator.toString()) + temp = temp.substringAfter(operator.toString()) } - queue.add(newMathematical) - if (queue.size % 2 == 0) throw IllegalArgumentException() + queue.add(temp) return queue } - - private fun verifyMathematical(mathematical: String) { - val splitData = mathematical.split(*Operator.list().toTypedArray()) - - if (splitData.size != mathematical.length - (mathematical.length / 2)) { - throw IllegalArgumentException() - } - } } diff --git a/src/main/kotlin/calculator/Num.kt b/src/main/kotlin/calculator/Num.kt index 6240f6ed32..fd2a916ce3 100644 --- a/src/main/kotlin/calculator/Num.kt +++ b/src/main/kotlin/calculator/Num.kt @@ -2,7 +2,7 @@ package calculator data class Num(var value: Int) { - constructor(value: String) : this(value.toIntOrNull() ?: throw IllegalArgumentException()) + constructor(value: String) : this(Integer.parseInt(value)) fun add(number: Num) = Num(this.value + number.value) diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt index 880f0d6d9d..760be04360 100644 --- a/src/main/kotlin/calculator/StringCalculator.kt +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -2,21 +2,43 @@ package calculator class StringCalculator { - fun calculate(mathematical: String): Num { + fun calculate(input: String): Num { - val expression = Expression(mathematical) - val queue = expression.compute() + val data = removeSpace(input) + verifyOperator(data) + + val expression = Expression(data) + val queue = expression.apply() var result = Num(queue.poll()) while (queue.isNotEmpty()) { - val operator = Operator(queue.poll().first()) - val second = Num(queue.poll()) - result = calculate(result, second, operator) + val operator = queue.poll() + val operand = queue.poll() + val o = Operator(operator.first()) + result = o.calculate(result, Num(operand)) } return result } - private fun calculate(first: Num, second: Num, operator: Operator) = operator.calculate(first, second) + private fun removeSpace(input: String): String { + return input.replace(" ", "") + } + + private fun verifyOperator(data: String) { + val splitData = data.split("+", "-", "*", "/") + + if (splitData.size != data.length - (data.length / 2)) { + throw IllegalArgumentException() + } + + for (c in splitData) { + try { + Integer.parseInt(c) + } catch (e: NumberFormatException) { + throw IllegalArgumentException() + } + } + } } diff --git a/src/test/kotlin/calculator/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt index 590d68e278..e9ca3b8612 100644 --- a/src/test/kotlin/calculator/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -8,6 +8,27 @@ import org.junit.jupiter.params.provider.ValueSource class StringCalculatorTest { + @Test + fun `문자열 자르기`() { + + val input = "1234-5678-9000" + + val substringBefore = input.substringBefore("-") + val substringAfter = input.substringAfter("-") + + assertThat(substringBefore).isEqualTo("1234") + assertThat(substringAfter).isEqualTo("5678-9000") + } + + @Test + fun `인덱스 가져오기`() { + + var input = "2 + 3 * 4 / 2" + input = input.replace(" ", "") + val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } + assertThat(index).isEqualTo(1) + } + @Test fun `덧셈`() { val input = "2 + 3" @@ -56,20 +77,20 @@ class StringCalculatorTest { @ParameterizedTest @ValueSource(strings = ["2 ! 3 * 4 / 2", "23 * 22A * 1"]) - fun `사칙연산 기호가 아닌경우`(mathematical: String) { + fun `사칙연산 기호가 아닌경우`(input: String) { val stringCalculator = StringCalculator() assertThrows { - stringCalculator.calculate(mathematical) + stringCalculator.calculate(input) } } @Test - fun `사칙연산을 실행한다`() { + fun `사칙연산 기능 구현`() { - val mathematical = "2 + 3 * 4 / 2" + val input = "2 + 3 * 4 / 2" val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(mathematical) + val result = stringCalculator.calculate(input) assertThat(result).isEqualTo(Num(10)) } From 0969d56788b2714fdeaa9713e024aab6ac0f2d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Mon, 21 Nov 2022 23:35:03 +0900 Subject: [PATCH 46/49] =?UTF-8?q?=20:=20rebase=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=95=EC=97=90=EC=84=9C=20=EC=B6=A9=EB=8F=8C=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Expression.kt | 54 ++++++++++--------- src/main/kotlin/calculator/Num.kt | 2 +- .../kotlin/calculator/StringCalculator.kt | 36 +++---------- .../kotlin/calculator/StringCalculatorTest.kt | 31 ++--------- 4 files changed, 41 insertions(+), 82 deletions(-) diff --git a/src/main/kotlin/calculator/Expression.kt b/src/main/kotlin/calculator/Expression.kt index 5349ac851f..266cbf6dfc 100644 --- a/src/main/kotlin/calculator/Expression.kt +++ b/src/main/kotlin/calculator/Expression.kt @@ -4,50 +4,52 @@ import java.util.LinkedList import java.util.Queue class Expression( - val input: String + private var _mathematical: String ) { - fun apply(): Queue { - val queue = createOperandAndOperatorQueue(input) - if (queue.size % 2 == 0) throw IllegalArgumentException() - return queue - } + private val mathematical: String + get() = _mathematical - private fun priorityIndexes(data: String): List { - val priorityList = mutableListOf() + init { + _mathematical = _mathematical.replace(" ", "") + verifyMathematical(_mathematical) + } - for (c in data) { - if (isOperatorLetter(c)) { - priorityList.add(c) - } - } + fun compute(): Queue { + return polynomial(mathematical) + } - return priorityList + private fun priorityIndexes(data: String): List { + return data.filter { c -> isOperatorLetter(c) }.toList() } private fun isOperatorLetter(c: Char): Boolean { - for (operator in Operator.values()) { - if (operator.isSame(c)) { - return true - } - } - return false + return Operator.exist(c) } - private fun createOperandAndOperatorQueue(data: String): Queue { + private fun polynomial(mathematical: String): Queue { - var temp = data - val sortedPriorityList = priorityIndexes(data) + var newMathematical = mathematical + val sortedPriorityList = priorityIndexes(mathematical) val queue = LinkedList() for (operator in sortedPriorityList) { - val operand = temp.substringBefore(operator.toString()) + val operand = newMathematical.substringBefore(operator.toString()) queue.add(operand) queue.add(operator.toString()) - temp = temp.substringAfter(operator.toString()) + newMathematical = newMathematical.substringAfter(operator.toString()) } - queue.add(temp) + queue.add(newMathematical) + if (queue.size % 2 == 0) throw IllegalArgumentException() return queue } + + private fun verifyMathematical(mathematical: String) { + val splitData = mathematical.split(*Operator.list().toTypedArray()) + + if (splitData.size != mathematical.length - (mathematical.length / 2)) { + throw IllegalArgumentException() + } + } } diff --git a/src/main/kotlin/calculator/Num.kt b/src/main/kotlin/calculator/Num.kt index fd2a916ce3..6240f6ed32 100644 --- a/src/main/kotlin/calculator/Num.kt +++ b/src/main/kotlin/calculator/Num.kt @@ -2,7 +2,7 @@ package calculator data class Num(var value: Int) { - constructor(value: String) : this(Integer.parseInt(value)) + constructor(value: String) : this(value.toIntOrNull() ?: throw IllegalArgumentException()) fun add(number: Num) = Num(this.value + number.value) diff --git a/src/main/kotlin/calculator/StringCalculator.kt b/src/main/kotlin/calculator/StringCalculator.kt index 760be04360..880f0d6d9d 100644 --- a/src/main/kotlin/calculator/StringCalculator.kt +++ b/src/main/kotlin/calculator/StringCalculator.kt @@ -2,43 +2,21 @@ package calculator class StringCalculator { - fun calculate(input: String): Num { + fun calculate(mathematical: String): Num { - val data = removeSpace(input) - verifyOperator(data) - - val expression = Expression(data) - val queue = expression.apply() + val expression = Expression(mathematical) + val queue = expression.compute() var result = Num(queue.poll()) while (queue.isNotEmpty()) { - val operator = queue.poll() - val operand = queue.poll() - val o = Operator(operator.first()) - result = o.calculate(result, Num(operand)) + val operator = Operator(queue.poll().first()) + val second = Num(queue.poll()) + result = calculate(result, second, operator) } return result } - private fun removeSpace(input: String): String { - return input.replace(" ", "") - } - - private fun verifyOperator(data: String) { - val splitData = data.split("+", "-", "*", "/") - - if (splitData.size != data.length - (data.length / 2)) { - throw IllegalArgumentException() - } - - for (c in splitData) { - try { - Integer.parseInt(c) - } catch (e: NumberFormatException) { - throw IllegalArgumentException() - } - } - } + private fun calculate(first: Num, second: Num, operator: Operator) = operator.calculate(first, second) } diff --git a/src/test/kotlin/calculator/StringCalculatorTest.kt b/src/test/kotlin/calculator/StringCalculatorTest.kt index e9ca3b8612..590d68e278 100644 --- a/src/test/kotlin/calculator/StringCalculatorTest.kt +++ b/src/test/kotlin/calculator/StringCalculatorTest.kt @@ -8,27 +8,6 @@ import org.junit.jupiter.params.provider.ValueSource class StringCalculatorTest { - @Test - fun `문자열 자르기`() { - - val input = "1234-5678-9000" - - val substringBefore = input.substringBefore("-") - val substringAfter = input.substringAfter("-") - - assertThat(substringBefore).isEqualTo("1234") - assertThat(substringAfter).isEqualTo("5678-9000") - } - - @Test - fun `인덱스 가져오기`() { - - var input = "2 + 3 * 4 / 2" - input = input.replace(" ", "") - val index = input.indexOfFirst { c -> Operator.PLUS.isSame(c) } - assertThat(index).isEqualTo(1) - } - @Test fun `덧셈`() { val input = "2 + 3" @@ -77,20 +56,20 @@ class StringCalculatorTest { @ParameterizedTest @ValueSource(strings = ["2 ! 3 * 4 / 2", "23 * 22A * 1"]) - fun `사칙연산 기호가 아닌경우`(input: String) { + fun `사칙연산 기호가 아닌경우`(mathematical: String) { val stringCalculator = StringCalculator() assertThrows { - stringCalculator.calculate(input) + stringCalculator.calculate(mathematical) } } @Test - fun `사칙연산 기능 구현`() { + fun `사칙연산을 실행한다`() { - val input = "2 + 3 * 4 / 2" + val mathematical = "2 + 3 * 4 / 2" val stringCalculator = StringCalculator() - val result = stringCalculator.calculate(input) + val result = stringCalculator.calculate(mathematical) assertThat(result).isEqualTo(Num(10)) } From e25f17510620d595bbd6f45a224da86d09d6db8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Sat, 26 Nov 2022 00:31:44 +0900 Subject: [PATCH 47/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Car.kt | 24 ++++----------------- src/main/kotlin/racing/domain/CarFactory.kt | 2 +- src/main/kotlin/racing/domain/Cars.kt | 18 +++------------- src/main/kotlin/racing/domain/Winner.kt | 6 ++---- src/main/kotlin/racing/ui/InputView.kt | 6 ++++-- src/main/kotlin/racing/ui/ResultView.kt | 5 +++-- src/test/kotlin/racing/CarTest.kt | 9 ++++---- src/test/kotlin/racing/RacingGameTest.kt | 20 ++++++++++++----- 8 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/main/kotlin/racing/domain/Car.kt b/src/main/kotlin/racing/domain/Car.kt index 30fabc9172..2baea214e3 100644 --- a/src/main/kotlin/racing/domain/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,15 +1,14 @@ package racing.domain -class Car(name: String, position: Int = 0) { +class Car(val name: String, position: Int = 0) { - var name = name - private set var position = position private set init { - if (name.length > CAR_NAME_LIMIT) - throw IllegalArgumentException("자동차의 이름은 ${CAR_NAME_LIMIT}글자를 초과할 수 없습니다.") + require(name.length <= CAR_NAME_LIMIT) { + "자동차의 이름은 ${CAR_NAME_LIMIT}글자를 초과할 수 없습니다." + } } fun move(num: Int) { @@ -18,21 +17,6 @@ class Car(name: String, position: Int = 0) { } } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Car - - if (name != other.name) return false - - return true - } - - override fun hashCode(): Int { - return name.hashCode() - } - companion object { const val FORWARD_MOVE: Int = 4 const val CAR_NAME_LIMIT: Int = 5 diff --git a/src/main/kotlin/racing/domain/CarFactory.kt b/src/main/kotlin/racing/domain/CarFactory.kt index 0d6f69d203..02b4296073 100644 --- a/src/main/kotlin/racing/domain/CarFactory.kt +++ b/src/main/kotlin/racing/domain/CarFactory.kt @@ -3,7 +3,7 @@ package racing.domain class CarFactory { companion object { - fun create(names: String): Cars { + fun create(names: Array): Cars { return Cars(names) } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index c9d8b41a9b..6658953b93 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,17 +1,9 @@ package racing.domain -class Cars : Iterable { +class Cars(list: List) : Iterable { - private val list: List - - constructor(names: String) { - list = names.split(SEPARATOR).map { - Car.produce(it) - } - } - constructor(carList: List) { - list = carList - } + private val list = list + constructor(names: Array) : this(names.map { Car.produce(it) }) fun count() = list.size @@ -22,8 +14,4 @@ class Cars : Iterable { } } override fun iterator(): Iterator = list.iterator() - - companion object { - const val SEPARATOR = "," - } } diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt index ede4483e1e..354e9162ac 100644 --- a/src/main/kotlin/racing/domain/Winner.kt +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -5,10 +5,8 @@ class Winner(cars: Cars) { var cars = cars private set - constructor(carList: List) : this(Cars(carList)) - - fun win(): String { + fun win(): List { val maxPosition = cars.maxOf { it.position } - return cars.filter { it.position == maxPosition }.joinToString { it.name } + return cars.filter { it.position == maxPosition } } } diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/ui/InputView.kt index cc5124981a..49147aee66 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/ui/InputView.kt @@ -3,10 +3,12 @@ package racing.ui class InputView { companion object { + private const val SEPARATOR = "," - fun requireRacingCarNames(): String { + fun requireRacingCarNames(): Array { println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분") - return readString() + val readString = readString() + return readString.split(SEPARATOR).toTypedArray() } fun requireNumberOfGames(): Int { diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/ui/ResultView.kt index 2219bcaada..3c7fd92e0c 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/ui/ResultView.kt @@ -22,10 +22,11 @@ class ResultView { println(result) } - fun printRacingGameWinner(winner: String) { + fun printRacingGameWinner(cars: List) { + val winner = cars.joinToString { it.name } println("${winner}가 최종 우승했습니다.") } - const val MARK = "-" + private const val MARK = "-" } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 254f37c0b5..ff7e5339fc 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -1,6 +1,7 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.assertj.core.util.Arrays import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest @@ -12,14 +13,14 @@ class CarTest { @Test fun `자동차를 생성할 때 자동차의 이름은 5글자 이하이다`() { - val names = "lee,kkoks,amery" + val names = Arrays.array("lee", "kkoks", "amery") val cars: Cars = CarFactory.create(names) assertThat(cars.count()).isEqualTo(3) } @Test fun `자동차를 생성할 때 자동차의 이름은 5글자를 초과한다`() { - val names = "leejhw,kkoks,amery" + val names = Arrays.array("lee", "kkokss", "amery") assertThrows { CarFactory.create(names) } @@ -28,7 +29,7 @@ class CarTest { @ParameterizedTest @ValueSource(ints = [4, 9]) fun `자동차 이동`(num: Int) { - val names = "lee,kkoks,amery" + val names = Arrays.array("lee", "kkoks", "amery") val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) @@ -39,7 +40,7 @@ class CarTest { @ParameterizedTest @ValueSource(ints = [0, 3]) fun `자동차 이동실패`(num: Int) { - val names = "lee,kkoks,amery" + val names = Arrays.array("lee", "kkoks", "amery") val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(num) diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index e75c2ac5fa..0629c14e66 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -1,6 +1,7 @@ package racing import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.assertj.core.util.Arrays import org.junit.jupiter.api.Test import racing.domain.Car import racing.domain.CarFactory @@ -12,7 +13,7 @@ class RacingGameTest { @Test fun `실행결과 출력`() { - val names = "lee,kkoks" + val names = Arrays.array("lee", "kkoks") val cars: Cars = CarFactory.create(names) for (car in cars) { car.move(4) @@ -25,12 +26,20 @@ class RacingGameTest { assertThat(ResultView.toRaceResult(cars)).isEqualTo(result) } + @Test + fun `Racing Game 단독 우승자 출력(차가 한대일경우)`() { + val kkoksCar = Car.produce("kkoks", 3) + val winner = Winner(Cars(listOf(kkoksCar))) + val result = winner.win().joinToString { it.name } + assertThat(result).isEqualTo("kkoks") + } + @Test fun `Racing Game 단독 우승자 출력`() { val leeCar = Car.produce("lee", 5) val kkoksCar = Car.produce("kkoks", 3) - val winner = Winner(listOf(leeCar, kkoksCar)) - val result = winner.win() + val winner = Winner(Cars(listOf(leeCar, kkoksCar))) + val result = winner.win().joinToString { it.name } assertThat(result).isEqualTo("lee") } @@ -38,8 +47,9 @@ class RacingGameTest { fun `Racing Game 공동 우승자 출력`() { val leeCar = Car.produce("lee", 5) val kkoksCar = Car.produce("kkoks", 5) - val winner = Winner(listOf(leeCar, kkoksCar)) - val result = winner.win() + val tesyCar = Car.produce("tesy", 3) + val winner = Winner(Cars(listOf(leeCar, kkoksCar, tesyCar))) + val result = winner.win().joinToString { it.name } assertThat(result).isEqualTo("lee, kkoks") } } From 7798f1a5948a2d377a7628ac7d31f23a5dcae63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Mon, 28 Nov 2022 00:42:52 +0900 Subject: [PATCH 48/49] =?UTF-8?q?=20:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/domain/Cars.kt | 5 +++++ src/main/kotlin/racing/domain/Winner.kt | 5 +---- src/test/kotlin/racing/RacingGameTest.kt | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 6658953b93..439b1d3fd2 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -13,5 +13,10 @@ class Cars(list: List) : Iterable { car.move(movable()) } } + + fun isWinnerPosition() = list.maxOf { it.position } + + fun isWinner() = list.filter { it.position == isWinnerPosition() } + override fun iterator(): Iterator = list.iterator() } diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt index 354e9162ac..ce91c1f974 100644 --- a/src/main/kotlin/racing/domain/Winner.kt +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -5,8 +5,5 @@ class Winner(cars: Cars) { var cars = cars private set - fun win(): List { - val maxPosition = cars.maxOf { it.position } - return cars.filter { it.position == maxPosition } - } + fun win(): List = cars.isWinner() } diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 0629c14e66..60493e014d 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -30,8 +30,8 @@ class RacingGameTest { fun `Racing Game 단독 우승자 출력(차가 한대일경우)`() { val kkoksCar = Car.produce("kkoks", 3) val winner = Winner(Cars(listOf(kkoksCar))) - val result = winner.win().joinToString { it.name } - assertThat(result).isEqualTo("kkoks") + val result = winner.win() + assertThat(result).contains(kkoksCar) } @Test @@ -39,8 +39,8 @@ class RacingGameTest { val leeCar = Car.produce("lee", 5) val kkoksCar = Car.produce("kkoks", 3) val winner = Winner(Cars(listOf(leeCar, kkoksCar))) - val result = winner.win().joinToString { it.name } - assertThat(result).isEqualTo("lee") + val result = winner.win() + assertThat(result).contains(leeCar) } @Test @@ -49,7 +49,7 @@ class RacingGameTest { val kkoksCar = Car.produce("kkoks", 5) val tesyCar = Car.produce("tesy", 3) val winner = Winner(Cars(listOf(leeCar, kkoksCar, tesyCar))) - val result = winner.win().joinToString { it.name } - assertThat(result).isEqualTo("lee, kkoks") + val result = winner.win() + assertThat(result).contains(leeCar, kkoksCar) } } From a353de46a9d6b5f309c0d593ab661c4f75406b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI2=ED=8C=80-=EC=9D=B4=EC=A0=95=ED=99=98?= Date: Mon, 28 Nov 2022 01:03:04 +0900 Subject: [PATCH 49/49] =?UTF-8?q?=20:=20=EC=9D=98=EC=A1=B4=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++++- .../kotlin/racing/application/RacingGameService.kt | 9 ++++++++- src/main/kotlin/racing/domain/Cars.kt | 6 ++---- src/main/kotlin/racing/domain/RacingGame.kt | 13 +++++-------- src/main/kotlin/racing/domain/Winner.kt | 5 +---- src/main/kotlin/racing/{ui => view}/InputView.kt | 2 +- src/main/kotlin/racing/{ui => view}/ResultView.kt | 2 +- src/test/kotlin/racing/RacingGameTest.kt | 2 +- 8 files changed, 23 insertions(+), 21 deletions(-) rename src/main/kotlin/racing/{ui => view}/InputView.kt (96%) rename src/main/kotlin/racing/{ui => view}/ResultView.kt (97%) diff --git a/README.md b/README.md index 7b97fcae21..f339a944f8 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,7 @@ - [o] 실행결과를 출력한다. - [o] 매 횟수마다 출력한다. - [o] 매 횟수마다 전진하는 자동차의 이름도 출력한다. - - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. \ No newline at end of file + - [o] 최종 우승자를 출력하며, 우승자는 한명 이상이다. +- [o] 의존관계 + - [o] Domain -> View X + - [o] View -> Domain O \ No newline at end of file diff --git a/src/main/kotlin/racing/application/RacingGameService.kt b/src/main/kotlin/racing/application/RacingGameService.kt index a303b10de7..bc3cb40acd 100644 --- a/src/main/kotlin/racing/application/RacingGameService.kt +++ b/src/main/kotlin/racing/application/RacingGameService.kt @@ -1,11 +1,18 @@ package racing.application import racing.domain.RacingGame +import racing.view.InputView +import racing.view.ResultView class RacingGameService { fun main() { + val racingCarNames = InputView.requireRacingCarNames() + val numberOfGames = InputView.requireNumberOfGames() + val racingGame = RacingGame() - racingGame.start() + val winCars = racingGame.start(racingCarNames, numberOfGames) + ResultView.printRacingGameGuideText() + ResultView.printRacingGameWinner(winCars) } } diff --git a/src/main/kotlin/racing/domain/Cars.kt b/src/main/kotlin/racing/domain/Cars.kt index 439b1d3fd2..d442f1f449 100644 --- a/src/main/kotlin/racing/domain/Cars.kt +++ b/src/main/kotlin/racing/domain/Cars.kt @@ -1,8 +1,6 @@ package racing.domain -class Cars(list: List) : Iterable { - - private val list = list +class Cars(private val list: List) : Iterable { constructor(names: Array) : this(names.map { Car.produce(it) }) fun count() = list.size @@ -14,7 +12,7 @@ class Cars(list: List) : Iterable { } } - fun isWinnerPosition() = list.maxOf { it.position } + private fun isWinnerPosition() = list.maxOf { it.position } fun isWinner() = list.filter { it.position == isWinnerPosition() } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 65c319dada..174f372bef 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -1,22 +1,19 @@ package racing.domain -import racing.ui.InputView -import racing.ui.ResultView +import racing.view.ResultView class RacingGame { - fun start() { + fun start(carNames: Array, numberOfGames: Int): List { - val carNames = InputView.requireRacingCarNames() val cars = CarFactory.create(carNames) - var numberOfGames = InputView.requireNumberOfGames() - ResultView.printRacingGameGuideText() - while (numberOfGames-- > 0) { + for (i in 1..numberOfGames) { cars.race { RandomGenerator.generate() } ResultView.printRacingGameResult(ResultView.toRaceResult(cars)) } + val winner = Winner(cars) - ResultView.printRacingGameWinner(winner.win()) + return winner.win() } } diff --git a/src/main/kotlin/racing/domain/Winner.kt b/src/main/kotlin/racing/domain/Winner.kt index ce91c1f974..58b0a8f4f4 100644 --- a/src/main/kotlin/racing/domain/Winner.kt +++ b/src/main/kotlin/racing/domain/Winner.kt @@ -1,9 +1,6 @@ package racing.domain -class Winner(cars: Cars) { - - var cars = cars - private set +class Winner(private val cars: Cars) { fun win(): List = cars.isWinner() } diff --git a/src/main/kotlin/racing/ui/InputView.kt b/src/main/kotlin/racing/view/InputView.kt similarity index 96% rename from src/main/kotlin/racing/ui/InputView.kt rename to src/main/kotlin/racing/view/InputView.kt index 49147aee66..a9403d971b 100644 --- a/src/main/kotlin/racing/ui/InputView.kt +++ b/src/main/kotlin/racing/view/InputView.kt @@ -1,4 +1,4 @@ -package racing.ui +package racing.view class InputView { diff --git a/src/main/kotlin/racing/ui/ResultView.kt b/src/main/kotlin/racing/view/ResultView.kt similarity index 97% rename from src/main/kotlin/racing/ui/ResultView.kt rename to src/main/kotlin/racing/view/ResultView.kt index 3c7fd92e0c..b5e5613408 100644 --- a/src/main/kotlin/racing/ui/ResultView.kt +++ b/src/main/kotlin/racing/view/ResultView.kt @@ -1,4 +1,4 @@ -package racing.ui +package racing.view import racing.domain.Car import racing.domain.Cars diff --git a/src/test/kotlin/racing/RacingGameTest.kt b/src/test/kotlin/racing/RacingGameTest.kt index 60493e014d..3ee700ae1e 100644 --- a/src/test/kotlin/racing/RacingGameTest.kt +++ b/src/test/kotlin/racing/RacingGameTest.kt @@ -7,7 +7,7 @@ import racing.domain.Car import racing.domain.CarFactory import racing.domain.Cars import racing.domain.Winner -import racing.ui.ResultView +import racing.view.ResultView class RacingGameTest {