-
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] 제로(공재호) 미션 제출합니다. #7
base: main
Are you sure you want to change the base?
Changes from all commits
3208e76
a6bfd74
5ecc453
ae9220f
693fd1d
977e755
2bf267f
4a32fdc
6a91799
960f8a4
3523863
18b51a2
0faee3c
518fdc5
38377e6
535438d
dc4168c
96402e7
c07aeb2
a815c59
857a983
4ad4f5f
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,8 @@ | ||
package study | ||
|
||
import study.person.Person | ||
import study.person.PersonBuilder | ||
|
||
fun introduce(builder: PersonBuilder.() -> Unit): Person { | ||
return PersonBuilder().apply(builder).build() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package study.language | ||
|
||
data class Language(val name: String, val level: Int) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package study.language | ||
|
||
class LanguageBuilder { | ||
|
||
var languages: MutableList<Language> = mutableListOf() | ||
|
||
infix fun String.level(level: Int) { | ||
languages.add(Language(this, level)) | ||
} | ||
|
||
fun build(): MutableList<Language> { | ||
return languages | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package study.person | ||
|
||
import study.language.Language | ||
import study.skill.Skill | ||
|
||
data class Person( | ||
val name: String, | ||
val company: String, | ||
val skills: MutableList<Skill>, | ||
val languages: MutableList<Language> | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package study.person | ||
|
||
import study.language.Language | ||
import study.language.LanguageBuilder | ||
import study.skill.Skill | ||
import study.skill.SkillBuilder | ||
|
||
class PersonBuilder { | ||
|
||
lateinit var name: String | ||
lateinit var company: String | ||
lateinit var skills: MutableList<Skill> | ||
lateinit var languages: MutableList<Language> | ||
|
||
fun name(value: String) { | ||
name = value | ||
} | ||
|
||
fun company(value: String) { | ||
company = value | ||
} | ||
|
||
fun skills(builder: SkillBuilder.() -> Unit) { | ||
skills = SkillBuilder().apply(builder).build() | ||
} | ||
|
||
fun languages(builder: LanguageBuilder.() -> Unit) { | ||
languages = LanguageBuilder().apply(builder).build() | ||
} | ||
|
||
fun build(): Person { | ||
return Person(name, company, skills, languages) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package study.skill | ||
|
||
sealed class Skill | ||
|
||
data class SoftSkill(val value: String) : Skill() | ||
|
||
data class HardSkill(val value: String) : Skill() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package study.skill | ||
|
||
class SkillBuilder { | ||
|
||
var skills: MutableList<Skill> = mutableListOf() | ||
|
||
fun soft(value: String) { | ||
skills.add(SoftSkill(value)) | ||
} | ||
|
||
fun hard(value: String) { | ||
skills.add(HardSkill(value)) | ||
} | ||
|
||
fun build(): MutableList<Skill> { | ||
return skills | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package wordle | ||
|
||
import wordle.domain.Game | ||
import wordle.domain.GameResult | ||
import wordle.domain.Word | ||
import wordle.domain.Words | ||
import wordle.domain.WordsReader | ||
import wordle.view.InputView | ||
import wordle.view.OutputView | ||
import java.time.LocalDate | ||
|
||
fun main() { | ||
|
||
val wordsReader = WordsReader("words.txt") | ||
val words = Words(wordsReader.words) | ||
val game = Game(words, LocalDate.now()) | ||
val gameResult = GameResult(game.maxRound) | ||
|
||
OutputView.printInitMessage(game.maxRound) | ||
play(game, gameResult) | ||
} | ||
|
||
private fun play(game: Game, gameResult: GameResult) { | ||
return try { | ||
while (!game.isOver) { | ||
val playerWord = Word(InputView.requestAnswer()) | ||
val matchResult = game.matchResult(playerWord) | ||
gameResult.add(matchResult) | ||
OutputView.printGameResult(game.isOver, game.count, game.maxRound, gameResult) | ||
} | ||
} catch (exception: IllegalArgumentException) { | ||
OutputView.printErrorMessage(exception.message) | ||
play(game, gameResult) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package wordle.domain | ||
|
||
import java.time.LocalDate | ||
|
||
class Game(val words: Words, val date: LocalDate) { | ||
|
||
var count: Int = 0 | ||
private set | ||
var isOver: Boolean = false | ||
private set | ||
val maxRound: Int | ||
get() = MAX_ROUND | ||
|
||
fun matchResult(playerWord: Word): Tiles { | ||
require(words.contains(playerWord)) { "[ERROR] words.txt에 있는 단어를 입력해주세요." } | ||
val answer = words.findAnswer(date) | ||
val tiles = playerWord.value.withIndex() | ||
.mapIndexedNotNull { index, value -> | ||
matchSpell(value.value, index, answer) | ||
} | ||
count++ | ||
val newTiles = Tiles(tiles) | ||
updateIsOver(newTiles) | ||
return newTiles | ||
} | ||
|
||
private fun updateIsOver(newTiles: Tiles) { | ||
if (count >= MAX_ROUND || newTiles.isAllGreen()) { | ||
isOver = true | ||
} | ||
} | ||
|
||
private fun matchSpell(spell: Char, index: Int, answer: Word): Tile { | ||
if (answer.sameIndexAndSpell(index, spell)) { | ||
return Tile.GREEN | ||
} | ||
if (answer.contains(spell)) { | ||
return Tile.YELLOW | ||
} | ||
return Tile.GRAY | ||
} | ||
|
||
companion object { | ||
private const val MAX_ROUND = 6 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package wordle.domain | ||
|
||
class GameResult(size: Int) { | ||
|
||
var gameResult: MutableList<Tiles> = ArrayList(size) | ||
private set | ||
|
||
fun add(tiles: Tiles) { | ||
this.gameResult.add(tiles) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package wordle.domain | ||
|
||
enum class Tile(val symbol: String) { | ||
|
||
GRAY("⬜"), | ||
GREEN("\uD83D\uDFE9"), | ||
YELLOW("\uD83D\uDFE8"); | ||
|
||
fun isGreen(): Boolean { | ||
return this == GREEN | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package wordle.domain | ||
|
||
data class Tiles(val tiles: List<Tile>) { | ||
|
||
fun isAllGreen(): Boolean { | ||
return tiles.all { it.isGreen() } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package wordle.domain | ||
|
||
import java.util.regex.Pattern | ||
|
||
data class Word(val value: String) { | ||
|
||
init { | ||
require(isRightSize()) { "[ERROR] 5글자의 단어를 입력하세요." } | ||
require(isAlphabet()) { "[ERROR] 영어 단어를 입력하세요." } | ||
} | ||
|
||
private fun isRightSize(): Boolean = value.length == SIZE | ||
|
||
private fun isAlphabet(): Boolean = Pattern.matches("^[a-zA-Z]*$", value) | ||
|
||
fun sameIndexAndSpell(index: Int, spell: Char): Boolean = value[index] == spell | ||
|
||
fun contains(spell: Char): Boolean = value.contains(spell) | ||
|
||
companion object { | ||
private const val SIZE = 5 | ||
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. 음... 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. 해당 링크 접속이 안되네요! ㅠ_ㅠ |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package wordle.domain | ||
|
||
import java.time.LocalDate | ||
import java.time.temporal.ChronoUnit | ||
|
||
class Words(private val words: List<Word>) { | ||
|
||
fun findAnswer(current: LocalDate): Word { | ||
val answerIndex = ChronoUnit.DAYS.between(BASE_DATE, current) | ||
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. 맞아요ㅠ 연산 추가해주어야해요! 왜인지 잊어버렸군요 ㅎㅎㅎ,, |
||
return words[answerIndex.toInt() % words.size] | ||
} | ||
|
||
fun contains(word: Word): Boolean { | ||
return words.contains(word) | ||
} | ||
|
||
companion object { | ||
private val BASE_DATE = LocalDate.of(2021, 6, 19) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package wordle.domain | ||
|
||
import java.io.File | ||
|
||
class WordsReader(private val path: String) { | ||
|
||
val words: List<Word> | ||
get() = getWords(path) | ||
|
||
companion object { | ||
private fun getWords(path: String): List<Word> { | ||
return File(ClassLoader.getSystemResource(path).file).readLines() | ||
.map { Word(it) } | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package wordle.view | ||
|
||
object InputView { | ||
|
||
fun requestAnswer(): String { | ||
println() | ||
println("정답을 입력해 주세요.") | ||
return readln() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package wordle.view | ||
|
||
import wordle.domain.GameResult | ||
import wordle.domain.Tiles | ||
|
||
object OutputView { | ||
|
||
fun printInitMessage(maxRound: Int) { | ||
println("WORDLE을 ${maxRound}번 만에 맞춰 보세요.") | ||
println("시도의 결과는 타일의 색 변화로 나타납니다.") | ||
} | ||
|
||
fun printGameResult(isOver: Boolean, count: Int, maxRound: Int, gameResult: GameResult) { | ||
if (isOver) { | ||
println("$count/$maxRound") | ||
} | ||
println() | ||
gameResult.gameResult | ||
.forEach { | ||
printTiles(it) | ||
println() | ||
} | ||
} | ||
|
||
private fun printTiles(tiles: Tiles) { | ||
tiles.tiles | ||
.forEach { print(it.symbol) } | ||
} | ||
|
||
fun printErrorMessage(message: String?) { | ||
println(message) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package study | ||
|
||
import io.kotest.matchers.collections.shouldContainExactly | ||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import study.language.Language | ||
import study.skill.HardSkill | ||
import study.skill.SoftSkill | ||
|
||
class Introduce { | ||
|
||
@Test | ||
fun `자기소개`() { | ||
val person = introduce { | ||
name("제로") | ||
company("우아한테크코스") | ||
skills { | ||
soft("A passion for problem solving") | ||
soft("common communication skills") | ||
hard("Kotlin") | ||
} | ||
languages { | ||
"Korean" level 2 | ||
"English" level 1 | ||
} | ||
} | ||
|
||
person.name shouldBe "제로" | ||
person.company shouldBe "우아한테크코스" | ||
person.skills shouldContainExactly listOf( | ||
SoftSkill("A passion for problem solving"), | ||
SoftSkill("common communication skills"), | ||
HardSkill("Kotlin") | ||
) | ||
person.languages shouldContainExactly listOf( | ||
Language("Korean", 2), | ||
Language("English", 1) | ||
) | ||
} | ||
} |
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.
play
라는 책임이 도메인의 책임처럼 느껴져서 저는Game
객체가 가지도록 했는데 제로는 어떻게 생각하시나요? 😀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.
수업 때 잠깐 제로랑 얘기했던 부분인데
역시 책임을 어떻게 할당할지에 대한 고민은 항상 어려운 것 같네요 😂
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.
그쵸 ㅠㅠ 역할과 책임 분리가 가장 어려운것같아요