-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Wordle] 파랑(이하은) 미션 제출합니다. #13
base: main
Are you sure you want to change the base?
Changes from 11 commits
5577af4
913234c
9adf4b7
490274e
6fd8eb7
41725cb
eb2e781
50de938
6ca90e7
6c29542
a77bf9e
0a62335
200333b
7812438
80fd53d
2d19c45
125d27d
668cbdd
6a295e8
ed3ab9f
d12e369
f45ae33
7832770
be18256
102e8d7
23bb4e4
6a28632
961eac9
8df1ac1
d7e35f8
ace29e4
e210cfe
9e9c283
fd86a0e
ac5ff8f
ad32c27
2370f77
a2d57b4
f35a779
7696783
fce9fe0
5693dcb
6e78472
3cdc51e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package wordle | ||
|
||
import wordle.domain.Game | ||
import wordle.domain.Word | ||
import wordle.util.WordsReader | ||
import wordle.view.InputView | ||
import wordle.view.OutputView | ||
|
||
fun main() { | ||
val game = Game(WordsReader.getWords()) | ||
OutputView.printStartMessage() | ||
doGame(game) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. play game이 더 자연스러운 것 같아서 변경했습니다👍 |
||
OutputView.printCount(game.count) | ||
OutputView.printResults(game.results) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. View에 대한 호출을 최소화해 보면 어떨까요? |
||
} | ||
|
||
private fun doGame(game: Game) { | ||
val answer = Word(InputView.inputAnswer()) | ||
game.match(answer) | ||
if (game.isGameOver(answer)) { | ||
return | ||
} | ||
OutputView.printResults(game.results) | ||
doGame(game) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package wordle.domain | ||
|
||
class Game(private val words: Words) { | ||
|
||
constructor(words: List<Word>) : this(Words(words)) | ||
|
||
var count: Int = 0 | ||
private set | ||
|
||
var results: MutableList<List<Tile>> = ArrayList() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 뒷받침하는 프로퍼티(backing property)를 사용해 보세요. |
||
private set | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그때 제로가 질문해서 배웠습니다👍 |
||
|
||
fun isGameOver(answer: Word): Boolean { | ||
return count == 6 || words.isCorrect(answer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OutputView에서 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그렇네요 Game에서 public 상수로 선언해서 OutputView에서 가져다 쓰는 것으로 변경했습니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 깰끔하네여 ㅎ |
||
} | ||
|
||
fun match(answer: Word) { | ||
count++ | ||
require(words.contains(answer)) { "등록된 단어가 아닙니다." } | ||
results.add(words.check(answer)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package wordle.domain | ||
|
||
enum class Tile(val symbol: String) { | ||
|
||
YELLOW("🟨"), GREEN("🟩"), GRAY("⬜") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package wordle.domain | ||
|
||
data class Word(val value: String) { | ||
|
||
init { | ||
require(value.length == 5) { "단어의 길이는 5글자여야 합니다." } | ||
require(Regex("[a-zA-Z]*").matches(value)) { "단어에 영어가 아닌 글자나 공백이 포함될 수 없습니다." } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
fun isSameChar(other: Word, index: Int): Boolean { | ||
return this.value[index] == other.value[index] | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 깔끔 하네요ㅎㅎ 💯 |
||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,70 @@ | ||||||
package wordle.domain | ||||||
|
||||||
import java.time.LocalDate | ||||||
import java.time.temporal.ChronoUnit | ||||||
|
||||||
class Words(private val values: List<Word>) { | ||||||
|
||||||
private val answer: Word = findAnswer() | ||||||
private var answerMap: MutableMap<Char, Int> = HashMap() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문자를 비교해서 같은 경우 문자를 소진하기 때문에 문자의 개수를 저장할 필요가 있었습니다. 그렇기 때문에 문자 - 문자의 개수를 key, value로 저장하기 위해 HashMap을 사용했습니다! 이 부분이 궁금했던 거 맞나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이해했습니다!! 역시 S.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코틀린은 읽기 전용 컬렉션과 변경 가능한 컬렉션을 구별해 제공합니다.
Suggested change
|
||||||
|
||||||
private fun findAnswer(): Word { | ||||||
val date: LocalDate = LocalDate.now() | ||||||
val standardDate: LocalDate = LocalDate.of(2021, 6, 19) | ||||||
val days: Int = ChronoUnit.DAYS.between(standardDate, date).toInt() | ||||||
return values[days % values.size] | ||||||
} | ||||||
|
||||||
fun contains(word: Word): Boolean { | ||||||
return values.contains(word) | ||||||
} | ||||||
|
||||||
fun isCorrect(word: Word): Boolean { | ||||||
return word == answer | ||||||
} | ||||||
|
||||||
fun check(word: Word): List<Tile> { | ||||||
answerMap = initAnswerMap() | ||||||
val result: ArrayList<Tile> = ArrayList() | ||||||
repeat(5) { result.add(Tile.GRAY) } | ||||||
|
||||||
repeat(5) { i -> result[i] = findTileBySameCheck(word, i) } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
이렇게도 될거같아요! |
||||||
repeat(5) { i -> result[i] = findTileByContainCheck(result, word, i) } | ||||||
return result | ||||||
} | ||||||
|
||||||
private fun initAnswerMap(): MutableMap<Char, Int> { | ||||||
val answerMap: MutableMap<Char, Int> = HashMap() | ||||||
answer.value.forEach { | ||||||
answerMap.putIfAbsent(it, 0) | ||||||
answerMap.computeIfPresent(it) { _, v -> v + 1 } | ||||||
} | ||||||
return answerMap | ||||||
} | ||||||
|
||||||
private fun findTileBySameCheck(word: Word, index: Int): Tile { | ||||||
if (answer.isSameChar(word, index)) { | ||||||
calculateAnswerMap(word.value[index]) | ||||||
return Tile.GREEN | ||||||
} | ||||||
return Tile.GRAY | ||||||
} | ||||||
|
||||||
private fun findTileByContainCheck(result: List<Tile>, word: Word, index: Int): Tile { | ||||||
if (result[index] == Tile.GREEN) { | ||||||
return Tile.GREEN | ||||||
} | ||||||
if (answerMap.keys.contains(word.value[index])) { | ||||||
calculateAnswerMap(word.value[index]) | ||||||
return Tile.YELLOW | ||||||
} | ||||||
return Tile.GRAY | ||||||
} | ||||||
|
||||||
private fun calculateAnswerMap(key: Char) { | ||||||
answerMap.computeIfPresent(key) { _, v -> v - 1 } | ||||||
if (answerMap[key] == 0) { | ||||||
answerMap.remove(key) | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package wordle.util | ||
|
||
import wordle.domain.Word | ||
import java.io.FileReader | ||
|
||
object WordsReader { | ||
|
||
fun getWords(): List<Word> { | ||
val path = "src/main/resources/words.txt" | ||
val reader = FileReader(path) | ||
return reader.readLines().map { Word(it) } | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. txt 파일에서 문자열을 읽어와 Word list로 변환해주는 역할만 하고 있어서 util 클래스라고 생각했습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package wordle.view | ||
|
||
object InputView { | ||
|
||
fun inputAnswer(): String { | ||
println("정답을 입력해 주세요.") | ||
return readln() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package wordle.view | ||
|
||
import wordle.domain.Tile | ||
|
||
object OutputView { | ||
|
||
fun printStartMessage() { | ||
println( | ||
"WORDLE을 6번 만에 맞춰 보세요.\n" + | ||
"시도의 결과는 타일의 색 변화로 나타납니다." | ||
) | ||
} | ||
|
||
fun printResults(results: List<List<Tile>>) { | ||
println() | ||
results.forEach { printResult(it) } | ||
println() | ||
} | ||
|
||
private fun printResult(result: List<Tile>) { | ||
result.forEach { print(it.symbol) } | ||
println() | ||
} | ||
|
||
fun printCount(count: Int) { | ||
println() | ||
println("$count/6") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package wordle.domain | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class GameTest { | ||
|
||
@Test | ||
fun `등록된 단어가 아닌 경우 예외가 발생한다`() { | ||
val game = Game(listOf(Word("apple"), Word("hello"), Word("spicy"))) | ||
|
||
val exception = shouldThrow<IllegalArgumentException> { | ||
game.match(Word("spell")) | ||
} | ||
exception.message shouldBe "등록된 단어가 아닙니다." | ||
} | ||
|
||
@Test | ||
fun `게임 종료여부를 확인한다`() { | ||
val game = Game(listOf(Word("apple"), Word("hello"), Word("spicy"))) | ||
repeat(6) { game.match(Word("apple")) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 매번 이렇게 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Game을 생성할 때 maxGameCount를 받아 match를 사용하지 않고도 테스트할 수 있도록 수정했습니다! |
||
game.isGameOver(Word("apple")) shouldBe true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package wordle.domain | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import io.kotest.inspectors.forAll | ||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class WordTest { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코테스트 배워갑니다. 👍 👍 👍 👍 👍 👍 |
||
|
||
@Test | ||
fun `5글자가 아닌 word를 생성하면 예외가 발생한다`() { | ||
val exception = shouldThrow<IllegalArgumentException> { | ||
Word("test") | ||
} | ||
exception.message shouldBe "단어의 길이는 5글자여야 합니다." | ||
} | ||
|
||
@Test | ||
fun `영어가 아닌 글자가 포함된 word를 생성하면 예외가 발생한다`() { | ||
listOf("ap pl", "ap피le").forAll { | ||
val exception = shouldThrow<IllegalArgumentException> { | ||
Word(it) | ||
} | ||
exception.message shouldBe "단어에 영어가 아닌 글자나 공백이 포함될 수 없습니다." | ||
} | ||
} | ||
|
||
@Test | ||
fun `해당 글자가 단어의 특정 인덱스와 일치하는지 확인한다`() { | ||
val word = Word("style") | ||
val other = Word("soooo") | ||
word.isSameChar(other, 0) shouldBe true | ||
word.isSameChar(other, 1) shouldBe false | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package wordle.domain | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class WordsTest { | ||
|
||
@Test | ||
fun `단어가 리스트 안에 존재하는지 확인해준다`() { | ||
val apple = Word("apple") | ||
val happy = Word("happy") | ||
val doggy = Word("doggy") | ||
val words = Words(listOf(apple, happy)) | ||
|
||
words.contains(apple) shouldBe true | ||
words.contains(doggy) shouldBe false | ||
} | ||
|
||
@Test | ||
fun `단어가 정답인지 확인해준다`() { | ||
val words = Words(listOf(Word("apple"))) | ||
|
||
words.isCorrect(Word("apple")) shouldBe true | ||
words.isCorrect(Word("happy")) shouldBe false | ||
} | ||
|
||
@Test | ||
fun `단어를 정답과 비교하여 결과 타일을 반환한다`() { | ||
val words = Words(listOf(Word("apple"))) | ||
val word = Word("hello") | ||
|
||
val checkList = words.check(word) | ||
|
||
checkList shouldBe listOf(Tile.GRAY, Tile.YELLOW, Tile.GRAY, Tile.GREEN, Tile.GRAY) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package wordle.util | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class WordsReaderTest { | ||
|
||
@Test | ||
fun `파일을 읽어서 List를 반환해준다`() { | ||
val words = WordsReader.getWords() | ||
words.size shouldBe 2309 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기능 요구 사항을 잘 정리해주셨는데 아직 [x] 업데이트가 아직 안된 것 같아요!