-
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
Pako 워들제출합니다. #4
base: main
Are you sure you want to change the base?
Changes from all commits
5d8479e
eb31a9d
f2afbd3
5bab906
58b435b
35852c3
6fde073
3bb8164
6fc2288
991380a
7369f19
51876df
7bba0b9
3d994bf
050f619
de730f8
d9546f3
3bb172b
ced063d
759013e
1d39fa9
eb71087
cbf8f74
8e52fd5
0a32d12
b06d616
79f9e49
c4263dd
21a5791
1d526cd
1f4a332
ad3d1b5
6783141
5319a1a
6d6d054
e4dfdf0
4ee303d
6cc86be
beb1b18
2494155
605b476
dd9930b
828fb34
155f16a
72ebdb8
f57b1e5
64f24a9
5bce301
e544c0f
c0633eb
7e67435
842c92e
0fcd81e
293c4b6
c40742d
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,38 @@ | ||
package wordle.controller | ||
|
||
import wordle.domain.Answers | ||
import wordle.domain.Game | ||
import wordle.domain.Results | ||
import wordle.domain.Word | ||
import wordle.view.InputView | ||
import wordle.view.ResultView | ||
|
||
private const val LAST_PLAY_COUNT = 6 | ||
|
||
fun main() { | ||
val game = Game(Answers().answer) | ||
|
||
ResultView.printInit() | ||
|
||
playGame(game) | ||
} | ||
|
||
private fun playGame(game: Game) { | ||
val results = Results() | ||
|
||
var tryCount = 0 | ||
|
||
while (tryCount < LAST_PLAY_COUNT) { | ||
val inputWord = InputView.askWord(Answers.WORDS) | ||
val resultTiles = game.play(Word(inputWord)) | ||
|
||
results.combine(resultTiles) | ||
ResultView.printAllResults(results) | ||
tryCount++ | ||
|
||
if (game.isWinner(resultTiles)) { | ||
ResultView.printGamePlayCount(tryCount) | ||
break | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package wordle.domain | ||
|
||
import java.io.File | ||
|
||
class Answers { | ||
val answer: Word | ||
get() = createAnswer() | ||
|
||
private fun createAnswer() = WORDS.findAnswer() | ||
|
||
companion object { | ||
private const val ANSWERS_TEXT_PATH = "./words.txt" | ||
val WORDS = createWords() | ||
|
||
private fun createWords(): Words { | ||
val wordsFile = getResourceText().readLines() | ||
return Words(wordsFile.map { Word(it) }) | ||
} | ||
|
||
private fun getResourceText(): File { | ||
return File(ClassLoader.getSystemResource(ANSWERS_TEXT_PATH).file) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package wordle.domain | ||
|
||
class Game(private val answer: Word) { | ||
|
||
fun play(input: Word): Tiles { | ||
val inputChars = input.value.toCharArray() | ||
val wordMatcher = WordMatcher(answer) | ||
|
||
return createResultTiles(inputChars, wordMatcher) | ||
} | ||
|
||
private fun createResultTiles(inputChars: CharArray, wordMatcher: WordMatcher): Tiles { | ||
return Tiles(inputChars.mapIndexed { index, it -> wordMatcher.match(it.toString(), index) }) | ||
} | ||
|
||
fun isWinner(resultTiles: Tiles): Boolean { | ||
return resultTiles.isWinner() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package wordle.domain | ||
|
||
class Results { | ||
private val _results = mutableListOf<Tiles>() | ||
val results: List<Tiles> | ||
get() = _results | ||
|
||
fun combine(newResults: Tiles) { | ||
_results.add(newResults) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package wordle.domain | ||
|
||
enum class Tile { | ||
YELLOW, | ||
GREEN, | ||
GRAY | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package wordle.domain | ||
|
||
@JvmInline | ||
value class Tiles(val tiles: List<Tile>) { | ||
|
||
fun isWinner(): Boolean { | ||
val count = tiles.count { it == Tile.GREEN } | ||
|
||
return count == TOTAL_TILE_COUNT | ||
} | ||
|
||
companion object { | ||
private const val TOTAL_TILE_COUNT = 5 | ||
} | ||
Comment on lines
+6
to
+14
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,33 @@ | ||
package wordle.domain | ||
|
||
@JvmInline | ||
value class Word(val value: String) { | ||
|
||
init { | ||
require(isWordSizeAndAlphabet()) { | ||
WRONG_WORD_SIZE_MESSAGE | ||
} | ||
} | ||
|
||
private fun isWordSizeAndAlphabet() = value.length == WORD_SIZE && ALPHABET_REGEX.matches(value) | ||
|
||
fun findAlphabet(index: Int): String { | ||
require(index >= FIRST_INDEX && index <= value.length) { | ||
INDEX_OUT_RANGE_MESSAGE | ||
} | ||
|
||
return value[index].toString() | ||
} | ||
|
||
fun contains(compareValue: String): Boolean { | ||
return value.contains(compareValue) | ||
} | ||
|
||
companion object { | ||
private const val FIRST_INDEX = 0 | ||
private const val WORD_SIZE = 5 | ||
private const val WRONG_WORD_SIZE_MESSAGE = "5글자여야합니다" | ||
private const val INDEX_OUT_RANGE_MESSAGE = "인덱스 범위를 초과했습니다." | ||
private val ALPHABET_REGEX = Regex("^[a-zA-Z]*$") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package wordle.domain | ||
|
||
class WordMatcher(private val answer: Word) { | ||
|
||
fun match(alphabet: String, index: Int): Tile { | ||
if (alphabet == answer.findAlphabet(index)) { | ||
return Tile.GREEN | ||
} | ||
|
||
if (answer.contains(alphabet)) { | ||
return Tile.YELLOW | ||
} | ||
|
||
return Tile.GRAY | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package wordle.domain | ||
|
||
import java.time.LocalDate | ||
import java.time.temporal.ChronoUnit | ||
|
||
class Words(private val words: List<Word>) { | ||
|
||
fun findAnswer(): Word { | ||
return words[(findAnswerPosition() % words.size).toInt()] | ||
} | ||
|
||
private fun findAnswerPosition() = ChronoUnit.DAYS.between(SUBTRACT_DATE_FOR_ANSWER, LocalDate.now()) | ||
|
||
fun contains(value: String): Boolean { | ||
return words.contains(Word(value)) | ||
} | ||
|
||
companion object { | ||
private val SUBTRACT_DATE_FOR_ANSWER = LocalDate.of(2021, 6, 19) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package wordle.view | ||
|
||
import wordle.domain.Words | ||
|
||
object InputView { | ||
|
||
fun askWord(words: Words): String { | ||
while (true) { | ||
val input = question() | ||
if (words.contains(input)) { | ||
return input | ||
} | ||
|
||
println("올바르지 않은 단어입니다.") | ||
} | ||
} | ||
|
||
private fun question(): String { | ||
println("정답을 입력해 주세요.") | ||
return readln() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package wordle.view | ||
|
||
import wordle.domain.Results | ||
import wordle.domain.Tile | ||
|
||
private const val MAX_TRY_COUNT = 6 | ||
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.
|
||
|
||
object ResultView { | ||
|
||
fun printInit() { | ||
println("WORDLE을 ${MAX_TRY_COUNT}번 만에 맞춰 보세요.\n시도의 결과는 타일의 색 변화로 나타납니다.") | ||
} | ||
|
||
fun printGamePlayCount(index: Int) { | ||
println("$index /$MAX_TRY_COUNT") | ||
} | ||
|
||
fun printAllResults(results: Results) { | ||
results.results.forEach { | ||
printAllTiles(it.tiles) | ||
println() | ||
} | ||
} | ||
|
||
private fun printAllTiles(tiles: List<Tile>) { | ||
tiles.forEach { tile -> | ||
print(tile.viewTile()) | ||
} | ||
} | ||
|
||
private val Tile.viewTile: () -> String | ||
get() = { | ||
when (this) { | ||
Tile.GREEN -> "\uD83D\uDFE9" | ||
Tile.YELLOW -> "\uD83D\uDFE8" | ||
Tile.GRAY -> "⬜" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package wordle.domain | ||
|
||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
|
||
class GameTest { | ||
|
||
@Test | ||
fun `6번의 기회안에 5글자를 모두 맞추면 성공한다`() { | ||
val givenAnswer = Word("words") | ||
val game = Game(givenAnswer) | ||
val givenInput = Word("words") | ||
|
||
val result = game.play(givenInput) | ||
val isWinner = game.isWinner(result) | ||
|
||
assertThat(isWinner).isTrue | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package wordle.domain | ||
|
||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
|
||
class ResultsTest { | ||
|
||
@Test | ||
fun `기존에_존재하는_결과타일에_타일결과를_추가한다`() { | ||
val results = Results() | ||
|
||
results.combine(Tiles(listOf(Tile.YELLOW, Tile.YELLOW, Tile.YELLOW, Tile.GRAY, Tile.YELLOW))) | ||
results.combine(Tiles(listOf(Tile.GREEN, Tile.GRAY, Tile.GREEN, Tile.GRAY, Tile.YELLOW))) | ||
|
||
assertThat(results.results).containsExactly( | ||
Tiles(listOf(Tile.YELLOW, Tile.YELLOW, Tile.YELLOW, Tile.GRAY, Tile.YELLOW)), | ||
Tiles(listOf(Tile.GREEN, Tile.GRAY, Tile.GREEN, Tile.GRAY, Tile.YELLOW)) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package wordle.domain | ||
|
||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
|
||
class TileTest { | ||
|
||
@Test | ||
fun `타일은 노란색, 초록색, 회색을 가진다`() { | ||
assertThat(Tile.values()).containsExactly(Tile.YELLOW, Tile.GREEN, Tile.GRAY) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package wordle.domain | ||
|
||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
|
||
class TilesTest { | ||
@Test | ||
fun `모두 초록색인 경우 우승자이다`() { | ||
val givenTiles = Tiles(listOf(Tile.GREEN, Tile.GREEN, Tile.GREEN, Tile.GREEN, Tile.GREEN)) | ||
|
||
val actual = givenTiles.isWinner() | ||
|
||
assertThat(actual).isTrue | ||
} | ||
|
||
@Test | ||
fun `모두 초록색이 아닌 경우 우승자가아니다`() { | ||
val givenTiles = Tiles(listOf(Tile.GREEN, Tile.YELLOW, Tile.GREEN, Tile.GRAY, Tile.GREEN)) | ||
|
||
val actual = givenTiles.isWinner() | ||
|
||
assertThat(actual).isFalse | ||
} | ||
} |
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.
답안은 도메인인데 외부 자원(resource)의 특정 위치를 알고 있어야 할 필요가 있을까요? 도메인 영역은 가능한 독립적으로 구현되어있는게 좋을것 같습니다.