diff --git a/src/main/kotlin/README.md b/src/main/kotlin/README.md new file mode 100644 index 0000000000..d494e302be --- /dev/null +++ b/src/main/kotlin/README.md @@ -0,0 +1,17 @@ +## πŸš€ 2단계 - λ¬Έμžμ—΄ 계산기 +- [ ] μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ¬Έμžμ—΄ 값에 따라 사칙 연산을 μˆ˜ν–‰ν•  수 μžˆλŠ” 계산기λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€. +- [ ] λ¬Έμžμ—΄ κ³„μ‚°κΈ°λŠ” 사칙 μ—°μ‚°μ˜ 계산 μš°μ„ μˆœμœ„κ°€ μ•„λ‹Œ μž…λ ₯ 값에 따라 계산 μˆœμ„œκ°€ κ²°μ •λœλ‹€. + - [ ] 즉, μˆ˜ν•™μ—μ„œλŠ” κ³±μ…ˆ, λ‚˜λˆ—μ…ˆμ΄ λ§μ…ˆ, λΊ„μ…ˆ 보닀 λ¨Όμ € 계산해야 ν•˜μ§€λ§Œ 이λ₯Ό λ¬΄μ‹œν•œλ‹€. + - [ ] 예λ₯Ό λ“€μ–΄ "2 + 3 * 4 / 2"와 같은 λ¬Έμžμ—΄μ„ μž…λ ₯ν•  경우 2 + 3 * 4 / 2 μ‹€ν–‰ 결과인 10을 좜λ ₯ν•΄μ•Ό ν•œλ‹€. +- [ ] λ§μ…ˆ +- [ ] λΊ„μ…ˆ +- [ ] κ³±μ…ˆ +- [ ] λ‚˜λˆ—μ…ˆ +- [ ] μž…λ ₯값이 nullμ΄κ±°λ‚˜ 빈 곡백 문자일 경우 IllegalArgumentE ception throw +- [ ] 사칙연산 κΈ°ν˜Έκ°€ μ•„λ‹Œ 경우 IllegalArgumentE ception throw +- [ ] 사칙 연산을 λͺ¨λ‘ ν¬ν•¨ν•˜λŠ” κΈ°λŠ₯ κ΅¬ν˜„ +- [ ] 곡백 λ¬Έμžμ—΄μ„ 빈 곡백 문자둜 λΆ„λ¦¬ν•˜λ €λ©΄ String 클래슀의 split(" ") λ©”μ†Œλ“œλ₯Ό ν™œμš©ν•œλ‹€. +- [ ] 반볡적인 νŒ¨ν„΄μ„ μ°Ύμ•„ 반볡문으둜 κ΅¬ν˜„ν•œλ‹€. +- [ ] Parameterized Tests ν™œμš© +- [ ] μ—°μ‚°μž λ¨Όμ € μ‹œμž‘λ˜λŠ” 엣지 μΌ€μ΄μŠ€ +- [ ] μ—°μ‚°μžμ™€ 숫자의 κ°œμˆ˜κ°€ μ˜¬λ°”λ₯΄μ§€ μ•Šμ€ μΌ€μ΄μŠ€ \ No newline at end of file diff --git a/src/main/kotlin/calc/Calculator.kt b/src/main/kotlin/calc/Calculator.kt new file mode 100644 index 0000000000..d4f5d3a97c --- /dev/null +++ b/src/main/kotlin/calc/Calculator.kt @@ -0,0 +1,45 @@ +package calc + +class Calculator( + private val input: String +) { + init { + require( + input.split(" ").withIndex() + .all { (idx, value) -> + if (idx % 2 == 0) value.isNumber() else value.isOperator() + } + ) { "ν˜•μ‹ μ§€μΌœλž΄ γ…‹" } + } + + fun calc(): Int { + val elements = input.split(" ") + .filterNot { it.isBlank() } + .groupBy { it.isNumber() } + + val expressions = elements[false] ?: emptyList() + val numbers = (elements[true] ?: emptyList()) + .map { it.toInt() } + .toCollection(ArrayDeque()) + + for (expr in expressions) { + val operand1 = numbers.removeFirst() + val operand2 = numbers.removeFirst() + + val result = when (expr) { + "+" -> operand1 + operand2 + "-" -> operand1 - operand2 + "*" -> operand1 * operand2 + "/" -> operand1 / operand2 + else -> throw IllegalArgumentException() + } + + numbers.addFirst(result) + } + + return numbers.last() + } +} + +private fun String.isNumber() = toIntOrNull() != null +private fun String.isOperator() = this in setOf("+", "-", "*", "/") diff --git a/src/test/kotlin/CalculatorTest.kt b/src/test/kotlin/CalculatorTest.kt new file mode 100644 index 0000000000..e914bf36cf --- /dev/null +++ b/src/test/kotlin/CalculatorTest.kt @@ -0,0 +1,18 @@ +import calc.Calculator +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe + +class CalculatorTest : StringSpec({ + "계산 잘~ 해봐 " { + val result = Calculator("5 + 1 / 3").calc() + result shouldBe 2 + } + + "ν˜•μ‹ μ§€ν‚€λŠ”μ§€ 보자" { + shouldThrowWithMessage("ν˜•μ‹ μ§€μΌœλž΄ γ…‹") { + Calculator("223 h d23") + } + + } +}) \ No newline at end of file