oh-my-oop 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MCP_STRUCTURE.md +301 -0
- package/README.md +167 -0
- package/SCOPE.md +27 -0
- package/dist/application/discovery.d.ts +133 -0
- package/dist/application/discovery.js +62 -0
- package/dist/application/discovery.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/collaborators.d.ts +2 -0
- package/dist/domain/collaborators.js +26 -0
- package/dist/domain/collaborators.js.map +1 -0
- package/dist/domain/ids.d.ts +4 -0
- package/dist/domain/ids.js +23 -0
- package/dist/domain/ids.js.map +1 -0
- package/dist/domain/model.d.ts +71 -0
- package/dist/domain/model.js +2 -0
- package/dist/domain/model.js.map +1 -0
- package/dist/domain/schemas.d.ts +213 -0
- package/dist/domain/schemas.js +79 -0
- package/dist/domain/schemas.js.map +1 -0
- package/dist/domain/stereotypes.d.ts +7 -0
- package/dist/domain/stereotypes.js +65 -0
- package/dist/domain/stereotypes.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/io/classStore.d.ts +9 -0
- package/dist/io/classStore.js +39 -0
- package/dist/io/classStore.js.map +1 -0
- package/dist/io/collaborationStore.d.ts +7 -0
- package/dist/io/collaborationStore.js +32 -0
- package/dist/io/collaborationStore.js.map +1 -0
- package/dist/io/design.d.ts +3 -0
- package/dist/io/design.js +22 -0
- package/dist/io/design.js.map +1 -0
- package/dist/io/designIndex.d.ts +6 -0
- package/dist/io/designIndex.js +49 -0
- package/dist/io/designIndex.js.map +1 -0
- package/dist/io/frontmatter.d.ts +8 -0
- package/dist/io/frontmatter.js +31 -0
- package/dist/io/frontmatter.js.map +1 -0
- package/dist/io/history.d.ts +10 -0
- package/dist/io/history.js +38 -0
- package/dist/io/history.js.map +1 -0
- package/dist/io/useCaseStore.d.ts +8 -0
- package/dist/io/useCaseStore.js +36 -0
- package/dist/io/useCaseStore.js.map +1 -0
- package/dist/io/workspace.d.ts +14 -0
- package/dist/io/workspace.js +82 -0
- package/dist/io/workspace.js.map +1 -0
- package/dist/oop/commands.d.ts +446 -0
- package/dist/oop/commands.js +319 -0
- package/dist/oop/commands.js.map +1 -0
- package/dist/oop/conformance.d.ts +16 -0
- package/dist/oop/conformance.js +30 -0
- package/dist/oop/conformance.js.map +1 -0
- package/dist/prompts/discovery.d.ts +2 -0
- package/dist/prompts/discovery.js +41 -0
- package/dist/prompts/discovery.js.map +1 -0
- package/dist/prompts/imagineWithoutController.d.ts +2 -0
- package/dist/prompts/imagineWithoutController.js +75 -0
- package/dist/prompts/imagineWithoutController.js.map +1 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +17 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/phasePressureTest.d.ts +2 -0
- package/dist/prompts/phasePressureTest.js +69 -0
- package/dist/prompts/phasePressureTest.js.map +1 -0
- package/dist/prompts/rddIntro.d.ts +2 -0
- package/dist/prompts/rddIntro.js +53 -0
- package/dist/prompts/rddIntro.js.map +1 -0
- package/dist/prompts/review.d.ts +2 -0
- package/dist/prompts/review.js +45 -0
- package/dist/prompts/review.js.map +1 -0
- package/dist/prompts/stateMachineIntrospect.d.ts +2 -0
- package/dist/prompts/stateMachineIntrospect.js +80 -0
- package/dist/prompts/stateMachineIntrospect.js.map +1 -0
- package/dist/prompts/tellDontAskRephrase.d.ts +2 -0
- package/dist/prompts/tellDontAskRephrase.js +66 -0
- package/dist/prompts/tellDontAskRephrase.js.map +1 -0
- package/dist/render/diff.d.ts +21 -0
- package/dist/render/diff.js +84 -0
- package/dist/render/diff.js.map +1 -0
- package/dist/render/mermaid.d.ts +24 -0
- package/dist/render/mermaid.js +53 -0
- package/dist/render/mermaid.js.map +1 -0
- package/dist/render/sideBySide.d.ts +14 -0
- package/dist/render/sideBySide.js +91 -0
- package/dist/render/sideBySide.js.map +1 -0
- package/dist/resources/index.d.ts +2 -0
- package/dist/resources/index.js +349 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +22 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/alternatives.d.ts +2 -0
- package/dist/tools/alternatives.js +9 -0
- package/dist/tools/alternatives.js.map +1 -0
- package/dist/tools/classes.d.ts +2 -0
- package/dist/tools/classes.js +13 -0
- package/dist/tools/classes.js.map +1 -0
- package/dist/tools/collaborations.d.ts +2 -0
- package/dist/tools/collaborations.js +8 -0
- package/dist/tools/collaborations.js.map +1 -0
- package/dist/tools/compare.d.ts +2 -0
- package/dist/tools/compare.js +9 -0
- package/dist/tools/compare.js.map +1 -0
- package/dist/tools/conformance.d.ts +3 -0
- package/dist/tools/conformance.js +11 -0
- package/dist/tools/conformance.js.map +1 -0
- package/dist/tools/diagram.d.ts +2 -0
- package/dist/tools/diagram.js +9 -0
- package/dist/tools/diagram.js.map +1 -0
- package/dist/tools/discovery.d.ts +2 -0
- package/dist/tools/discovery.js +23 -0
- package/dist/tools/discovery.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +27 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/init.d.ts +2 -0
- package/dist/tools/init.js +9 -0
- package/dist/tools/init.js.map +1 -0
- package/dist/tools/oop.d.ts +9 -0
- package/dist/tools/oop.js +26 -0
- package/dist/tools/oop.js.map +1 -0
- package/dist/tools/responsibilities.d.ts +2 -0
- package/dist/tools/responsibilities.js +13 -0
- package/dist/tools/responsibilities.js.map +1 -0
- package/dist/tools/state.d.ts +2 -0
- package/dist/tools/state.js +8 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/useCases.d.ts +2 -0
- package/dist/tools/useCases.js +18 -0
- package/dist/tools/useCases.js.map +1 -0
- package/dist/tools/validate.d.ts +2 -0
- package/dist/tools/validate.js +9 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tradeoff/engine.d.ts +61 -0
- package/dist/tradeoff/engine.js +171 -0
- package/dist/tradeoff/engine.js.map +1 -0
- package/dist/tradeoff/heuristics/classSplit.d.ts +3 -0
- package/dist/tradeoff/heuristics/classSplit.js +94 -0
- package/dist/tradeoff/heuristics/classSplit.js.map +1 -0
- package/dist/tradeoff/heuristics/collaborationShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/collaborationShape.js +82 -0
- package/dist/tradeoff/heuristics/collaborationShape.js.map +1 -0
- package/dist/tradeoff/heuristics/collectionShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/collectionShape.js +113 -0
- package/dist/tradeoff/heuristics/collectionShape.js.map +1 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.d.ts +2 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.js +114 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.js.map +1 -0
- package/dist/tradeoff/heuristics/errorHandling.d.ts +2 -0
- package/dist/tradeoff/heuristics/errorHandling.js +110 -0
- package/dist/tradeoff/heuristics/errorHandling.js.map +1 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.d.ts +23 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.js +183 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.js.map +1 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.d.ts +2 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.js +23 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.js.map +1 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.d.ts +2 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.js +110 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.js.map +1 -0
- package/dist/tradeoff/heuristics/valueObjectShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/valueObjectShape.js +111 -0
- package/dist/tradeoff/heuristics/valueObjectShape.js.map +1 -0
- package/dist/tradeoff/templates.d.ts +2 -0
- package/dist/tradeoff/templates.js +33 -0
- package/dist/tradeoff/templates.js.map +1 -0
- package/dist/util/log.d.ts +1 -0
- package/dist/util/log.js +7 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/mcp.d.ts +4 -0
- package/dist/util/mcp.js +18 -0
- package/dist/util/mcp.js.map +1 -0
- package/dist/validate/cohesion.d.ts +3 -0
- package/dist/validate/cohesion.js +88 -0
- package/dist/validate/cohesion.js.map +1 -0
- package/dist/validate/collectionWrapper.d.ts +3 -0
- package/dist/validate/collectionWrapper.js +131 -0
- package/dist/validate/collectionWrapper.js.map +1 -0
- package/dist/validate/coupling.d.ts +3 -0
- package/dist/validate/coupling.js +47 -0
- package/dist/validate/coupling.js.map +1 -0
- package/dist/validate/cycle.d.ts +3 -0
- package/dist/validate/cycle.js +101 -0
- package/dist/validate/cycle.js.map +1 -0
- package/dist/validate/dataDuplication.d.ts +3 -0
- package/dist/validate/dataDuplication.js +150 -0
- package/dist/validate/dataDuplication.js.map +1 -0
- package/dist/validate/dependencyDirection.d.ts +3 -0
- package/dist/validate/dependencyDirection.js +106 -0
- package/dist/validate/dependencyDirection.js.map +1 -0
- package/dist/validate/dualUseKnowing.d.ts +3 -0
- package/dist/validate/dualUseKnowing.js +137 -0
- package/dist/validate/dualUseKnowing.js.map +1 -0
- package/dist/validate/emptyObjectFill.d.ts +3 -0
- package/dist/validate/emptyObjectFill.js +119 -0
- package/dist/validate/emptyObjectFill.js.map +1 -0
- package/dist/validate/findings.d.ts +22 -0
- package/dist/validate/findings.js +12 -0
- package/dist/validate/findings.js.map +1 -0
- package/dist/validate/functionDecompositionExcess.d.ts +3 -0
- package/dist/validate/functionDecompositionExcess.js +120 -0
- package/dist/validate/functionDecompositionExcess.js.map +1 -0
- package/dist/validate/functionNotObject.d.ts +3 -0
- package/dist/validate/functionNotObject.js +80 -0
- package/dist/validate/functionNotObject.js.map +1 -0
- package/dist/validate/godObject.d.ts +6 -0
- package/dist/validate/godObject.js +76 -0
- package/dist/validate/godObject.js.map +1 -0
- package/dist/validate/presentationInDomain.d.ts +3 -0
- package/dist/validate/presentationInDomain.js +57 -0
- package/dist/validate/presentationInDomain.js.map +1 -0
- package/dist/validate/primitiveWrapper.d.ts +3 -0
- package/dist/validate/primitiveWrapper.js +106 -0
- package/dist/validate/primitiveWrapper.js.map +1 -0
- package/dist/validate/rules.d.ts +24 -0
- package/dist/validate/rules.js +269 -0
- package/dist/validate/rules.js.map +1 -0
- package/dist/validate/singletonStatefulHolder.d.ts +3 -0
- package/dist/validate/singletonStatefulHolder.js +128 -0
- package/dist/validate/singletonStatefulHolder.js.map +1 -0
- package/dist/validate/strategyAsymmetry.d.ts +3 -0
- package/dist/validate/strategyAsymmetry.js +131 -0
- package/dist/validate/strategyAsymmetry.js.map +1 -0
- package/dist/validate/testability.d.ts +5 -0
- package/dist/validate/testability.js +157 -0
- package/dist/validate/testability.js.map +1 -0
- package/dist/validate/vagueName.d.ts +3 -0
- package/dist/validate/vagueName.js +136 -0
- package/dist/validate/vagueName.js.map +1 -0
- package/dist/validate/validationLocation.d.ts +3 -0
- package/dist/validate/validationLocation.js +120 -0
- package/dist/validate/validationLocation.js.map +1 -0
- package/lessons/STYLE_GUIDE.md +304 -0
- package/lessons/woowacourse-kotlin-blackjack/2chang5/33-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +293 -0
- package/lessons/woowacourse-kotlin-blackjack/Choisehyeon/52-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +106 -0
- package/lessons/woowacourse-kotlin-blackjack/Choisehyeon/9-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +282 -0
- package/lessons/woowacourse-kotlin-blackjack/DYGames/14-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +182 -0
- package/lessons/woowacourse-kotlin-blackjack/DYGames/37-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +122 -0
- package/lessons/woowacourse-kotlin-blackjack/EmilyCh0/12-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +117 -0
- package/lessons/woowacourse-kotlin-blackjack/EmilyCh0/38-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +291 -0
- package/lessons/woowacourse-kotlin-blackjack/HANDOVER.md +1475 -0
- package/lessons/woowacourse-kotlin-blackjack/HamBeomJoon/119-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +251 -0
- package/lessons/woowacourse-kotlin-blackjack/HamBeomJoon/137-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +459 -0
- package/lessons/woowacourse-kotlin-blackjack/Hevton/100-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +282 -0
- package/lessons/woowacourse-kotlin-blackjack/Hevton/82-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +303 -0
- package/lessons/woowacourse-kotlin-blackjack/Hogu59/71-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +134 -0
- package/lessons/woowacourse-kotlin-blackjack/Hogu59/96-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +323 -0
- package/lessons/woowacourse-kotlin-blackjack/JoYehyun99/66-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +210 -0
- package/lessons/woowacourse-kotlin-blackjack/Junyoung-WON/101-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +191 -0
- package/lessons/woowacourse-kotlin-blackjack/Junyoung-WON/80-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/Leeyerin0210/108-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +516 -0
- package/lessons/woowacourse-kotlin-blackjack/Leeyerin0210/133-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +541 -0
- package/lessons/woowacourse-kotlin-blackjack/RightHennessy/22-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +278 -0
- package/lessons/woowacourse-kotlin-blackjack/RightHennessy/48-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/SeongHoonC/16-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +228 -0
- package/lessons/woowacourse-kotlin-blackjack/SeongHoonC/54-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +227 -0
- package/lessons/woowacourse-kotlin-blackjack/Yunseok-Nam/76-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/Yunseok-Nam/86-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +203 -0
- package/lessons/woowacourse-kotlin-blackjack/aprilgom/105-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +162 -0
- package/lessons/woowacourse-kotlin-blackjack/aprilgom/64-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/boogi-woogi/18-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/boogi-woogi/36-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +769 -0
- package/lessons/woowacourse-kotlin-blackjack/briandr97/19-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +226 -0
- package/lessons/woowacourse-kotlin-blackjack/briandr97/59-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +193 -0
- package/lessons/woowacourse-kotlin-blackjack/chaehyuns/70-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +175 -0
- package/lessons/woowacourse-kotlin-blackjack/chaehyuns/98-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +206 -0
- package/lessons/woowacourse-kotlin-blackjack/chanho0908/123-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +277 -0
- package/lessons/woowacourse-kotlin-blackjack/chanho0908/150-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +219 -0
- package/lessons/woowacourse-kotlin-blackjack/chws0508/26-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +259 -0
- package/lessons/woowacourse-kotlin-blackjack/chws0508/43-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +189 -0
- package/lessons/woowacourse-kotlin-blackjack/cucumber99/109-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +351 -0
- package/lessons/woowacourse-kotlin-blackjack/cucumber99/149-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +147 -0
- package/lessons/woowacourse-kotlin-blackjack/devfeijoa/121-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +168 -0
- package/lessons/woowacourse-kotlin-blackjack/devfeijoa/153-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +116 -0
- package/lessons/woowacourse-kotlin-blackjack/doabletuple/126-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +680 -0
- package/lessons/woowacourse-kotlin-blackjack/doabletuple/142-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +739 -0
- package/lessons/woowacourse-kotlin-blackjack/donghyun81/116-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +297 -0
- package/lessons/woowacourse-kotlin-blackjack/donghyun81/147-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +244 -0
- package/lessons/woowacourse-kotlin-blackjack/dpcks0509/78-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +232 -0
- package/lessons/woowacourse-kotlin-blackjack/dpcks0509/88-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +137 -0
- package/lessons/woowacourse-kotlin-blackjack/etama123/112-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +269 -0
- package/lessons/woowacourse-kotlin-blackjack/etama123/148-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +240 -0
- package/lessons/woowacourse-kotlin-blackjack/gaeun5744/102-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +146 -0
- package/lessons/woowacourse-kotlin-blackjack/gaeun5744/69-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +224 -0
- package/lessons/woowacourse-kotlin-blackjack/gahyunkim/118-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +397 -0
- package/lessons/woowacourse-kotlin-blackjack/gahyunkim/141-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +215 -0
- package/lessons/woowacourse-kotlin-blackjack/giovannijunseokim/106-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +395 -0
- package/lessons/woowacourse-kotlin-blackjack/giovannijunseokim/134-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +219 -0
- package/lessons/woowacourse-kotlin-blackjack/haeum808/62-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +230 -0
- package/lessons/woowacourse-kotlin-blackjack/haeum808/89-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +169 -0
- package/lessons/woowacourse-kotlin-blackjack/hwannow/110-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +221 -0
- package/lessons/woowacourse-kotlin-blackjack/hwannow/132-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +573 -0
- package/lessons/woowacourse-kotlin-blackjack/hxeyexn/103-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/hxeyexn/81-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +301 -0
- package/lessons/woowacourse-kotlin-blackjack/hyemdooly/21-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +613 -0
- package/lessons/woowacourse-kotlin-blackjack/hyemdooly/35-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +691 -0
- package/lessons/woowacourse-kotlin-blackjack/hyunji1203/13-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +206 -0
- package/lessons/woowacourse-kotlin-blackjack/ii2001/79-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +153 -0
- package/lessons/woowacourse-kotlin-blackjack/ii2001/85-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +318 -0
- package/lessons/woowacourse-kotlin-blackjack/ijh1298/128-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +250 -0
- package/lessons/woowacourse-kotlin-blackjack/ijh1298/135-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +269 -0
- package/lessons/woowacourse-kotlin-blackjack/inseonyun/28-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +346 -0
- package/lessons/woowacourse-kotlin-blackjack/inseonyun/49-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +360 -0
- package/lessons/woowacourse-kotlin-blackjack/ippnsj/30-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +152 -0
- package/lessons/woowacourse-kotlin-blackjack/ippnsj/42-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +213 -0
- package/lessons/woowacourse-kotlin-blackjack/jaeyeongjo/73-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +247 -0
- package/lessons/woowacourse-kotlin-blackjack/jaeyeongjo/87-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +900 -0
- package/lessons/woowacourse-kotlin-blackjack/jerry8282/125-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +248 -0
- package/lessons/woowacourse-kotlin-blackjack/jerry8282/151-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +243 -0
- package/lessons/woowacourse-kotlin-blackjack/jinuemong/63-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +281 -0
- package/lessons/woowacourse-kotlin-blackjack/jinuemong/92-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +283 -0
- package/lessons/woowacourse-kotlin-blackjack/jiyuneel/113-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +348 -0
- package/lessons/woowacourse-kotlin-blackjack/jiyuneel/140-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +265 -0
- package/lessons/woowacourse-kotlin-blackjack/junjange/61-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +270 -0
- package/lessons/woowacourse-kotlin-blackjack/junjange/93-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +465 -0
- package/lessons/woowacourse-kotlin-blackjack/junseo511/107-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +296 -0
- package/lessons/woowacourse-kotlin-blackjack/junseo511/145-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +316 -0
- package/lessons/woowacourse-kotlin-blackjack/ki960213/11-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +175 -0
- package/lessons/woowacourse-kotlin-blackjack/kimhm0728/72-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +458 -0
- package/lessons/woowacourse-kotlin-blackjack/kimhm0728/97-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +225 -0
- package/lessons/woowacourse-kotlin-blackjack/kkosang/68-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +221 -0
- package/lessons/woowacourse-kotlin-blackjack/kkosang/94-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +158 -0
- package/lessons/woowacourse-kotlin-blackjack/kmkim2689/65-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +252 -0
- package/lessons/woowacourse-kotlin-blackjack/kmkim2689/90-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +460 -0
- package/lessons/woowacourse-kotlin-blackjack/krrong/32-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +216 -0
- package/lessons/woowacourse-kotlin-blackjack/krrong/46-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +285 -0
- package/lessons/woowacourse-kotlin-blackjack/m6z1/122-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +177 -0
- package/lessons/woowacourse-kotlin-blackjack/m6z1/144-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +155 -0
- package/lessons/woowacourse-kotlin-blackjack/medAndro/130-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +683 -0
- package/lessons/woowacourse-kotlin-blackjack/medAndro/143-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +678 -0
- package/lessons/woowacourse-kotlin-blackjack/moondev03/114-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +262 -0
- package/lessons/woowacourse-kotlin-blackjack/moondev03/131-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +498 -0
- package/lessons/woowacourse-kotlin-blackjack/murjune/77-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +287 -0
- package/lessons/woowacourse-kotlin-blackjack/murjune/91-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +280 -0
- package/lessons/woowacourse-kotlin-blackjack/no1msh/31-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +250 -0
- package/lessons/woowacourse-kotlin-blackjack/otter66/24-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +302 -0
- package/lessons/woowacourse-kotlin-blackjack/otter66/58-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +391 -0
- package/lessons/woowacourse-kotlin-blackjack/oungsi2000/111-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/oungsi2000/136-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +540 -0
- package/lessons/woowacourse-kotlin-blackjack/parkjiminnnn/117-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +819 -0
- package/lessons/woowacourse-kotlin-blackjack/parkjiminnnn/139-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +683 -0
- package/lessons/woowacourse-kotlin-blackjack/pingu244/20-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +258 -0
- package/lessons/woowacourse-kotlin-blackjack/pingu244/41-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +171 -0
- package/lessons/woowacourse-kotlin-blackjack/re4rk/34-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +289 -0
- package/lessons/woowacourse-kotlin-blackjack/re4rk/8-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +297 -0
- package/lessons/woowacourse-kotlin-blackjack/rhkrwngud445/17-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/rhkrwngud445/50-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +145 -0
- package/lessons/woowacourse-kotlin-blackjack/rhthrhrl0/23-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/rhthrhrl0/39-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +238 -0
- package/lessons/woowacourse-kotlin-blackjack/rosemin928/129-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +726 -0
- package/lessons/woowacourse-kotlin-blackjack/rosemin928/138-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +845 -0
- package/lessons/woowacourse-kotlin-blackjack/s6m1n/67-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +220 -0
- package/lessons/woowacourse-kotlin-blackjack/s6m1n/99-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +229 -0
- package/lessons/woowacourse-kotlin-blackjack/s9hn/10-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +284 -0
- package/lessons/woowacourse-kotlin-blackjack/sh1mj1/75-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +224 -0
- package/lessons/woowacourse-kotlin-blackjack/songpink/74-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +238 -0
- package/lessons/woowacourse-kotlin-blackjack/songpink/95-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +216 -0
- package/lessons/woowacourse-kotlin-blackjack/sujin9/15-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +132 -0
- package/lessons/woowacourse-kotlin-blackjack/sujin9/47-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +265 -0
- package/lessons/woowacourse-kotlin-blackjack/tmdgh1592/29-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +305 -0
- package/lessons/woowacourse-kotlin-blackjack/tmdgh1592/51-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +278 -0
- package/lessons/woowacourse-kotlin-blackjack/tobae-time/115-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +305 -0
- package/lessons/woowacourse-kotlin-blackjack/tobae-time/154-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +298 -0
- package/lessons/woowacourse-kotlin-blackjack/whk06061/25-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +235 -0
- package/lessons/woowacourse-kotlin-blackjack/whk06061/53-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +130 -0
- package/lessons/woowacourse-kotlin-blackjack/wondroid-world/124-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +486 -0
- package/lessons/woowacourse-kotlin-blackjack/wondroid-world/152-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +482 -0
- package/lessons/woowacourse-kotlin-blackjack/yrsel/120-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +194 -0
- package/lessons/woowacourse-kotlin-blackjack/yrsel/146-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +444 -0
- package/lessons/woowacourse-kotlin-lotto/2chang5/27-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/2chang5/52-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +187 -0
- package/lessons/woowacourse-kotlin-lotto/Choisehyeon/14-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +206 -0
- package/lessons/woowacourse-kotlin-lotto/Choisehyeon/47-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +119 -0
- package/lessons/woowacourse-kotlin-lotto/DYGames/2-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +83 -0
- package/lessons/woowacourse-kotlin-lotto/DYGames/34-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +88 -0
- package/lessons/woowacourse-kotlin-lotto/EmilyCh0/12-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/EmilyCh0/40-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +135 -0
- package/lessons/woowacourse-kotlin-lotto/HANDOVER.md +217 -0
- package/lessons/woowacourse-kotlin-lotto/HamBeomJoon/121-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/HamBeomJoon/139-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +75 -0
- package/lessons/woowacourse-kotlin-lotto/Hevton/76-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/Hevton/92-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +122 -0
- package/lessons/woowacourse-kotlin-lotto/Hogu59/100-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +110 -0
- package/lessons/woowacourse-kotlin-lotto/Hogu59/68-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +84 -0
- package/lessons/woowacourse-kotlin-lotto/JoYehyun99/60-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +176 -0
- package/lessons/woowacourse-kotlin-lotto/JoYehyun99/96-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +71 -0
- package/lessons/woowacourse-kotlin-lotto/Junyoung-WON/61-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/Junyoung-WON/93-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +16 -0
- package/lessons/woowacourse-kotlin-lotto/Leeyerin0210/109-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +57 -0
- package/lessons/woowacourse-kotlin-lotto/Leeyerin0210/135-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +115 -0
- package/lessons/woowacourse-kotlin-lotto/PROGRESS.md +160 -0
- package/lessons/woowacourse-kotlin-lotto/README.md +77 -0
- package/lessons/woowacourse-kotlin-lotto/RightHennessy/32-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/RightHennessy/5-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/SUMMARY.md +369 -0
- package/lessons/woowacourse-kotlin-lotto/SeongHoonC/25-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/SeongHoonC/37-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +27 -0
- package/lessons/woowacourse-kotlin-lotto/Yunseok-Nam/72-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +137 -0
- package/lessons/woowacourse-kotlin-lotto/Yunseok-Nam/86-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +17 -0
- package/lessons/woowacourse-kotlin-lotto/aprilgom/102-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +62 -0
- package/lessons/woowacourse-kotlin-lotto/aprilgom/64-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +146 -0
- package/lessons/woowacourse-kotlin-lotto/boogi-woogi/11-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/boogi-woogi/29-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/briandr97/26-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/briandr97/51-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +123 -0
- package/lessons/woowacourse-kotlin-lotto/chaehyuns/71-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +115 -0
- package/lessons/woowacourse-kotlin-lotto/chaehyuns/97-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/chanho0908/124-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +51 -0
- package/lessons/woowacourse-kotlin-lotto/chanho0908/129-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/chws0508/24-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +117 -0
- package/lessons/woowacourse-kotlin-lotto/chws0508/50-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +167 -0
- package/lessons/woowacourse-kotlin-lotto/cucumber99/116-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/cucumber99/147-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +223 -0
- package/lessons/woowacourse-kotlin-lotto/devfeijoa/125-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +68 -0
- package/lessons/woowacourse-kotlin-lotto/devfeijoa/153-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/doabletuple/119-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +157 -0
- package/lessons/woowacourse-kotlin-lotto/doabletuple/138-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +77 -0
- package/lessons/woowacourse-kotlin-lotto/donghyun81/111-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +67 -0
- package/lessons/woowacourse-kotlin-lotto/donghyun81/152-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/dpcks0509/80-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +141 -0
- package/lessons/woowacourse-kotlin-lotto/dpcks0509/87-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +134 -0
- package/lessons/woowacourse-kotlin-lotto/etama123/112-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +170 -0
- package/lessons/woowacourse-kotlin-lotto/etama123/148-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +183 -0
- package/lessons/woowacourse-kotlin-lotto/gaeun5744/101-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/gaeun5744/78-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +158 -0
- package/lessons/woowacourse-kotlin-lotto/gahyunkim/107-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +83 -0
- package/lessons/woowacourse-kotlin-lotto/gahyunkim/136-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +51 -0
- package/lessons/woowacourse-kotlin-lotto/giovannijunseokim/106-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +171 -0
- package/lessons/woowacourse-kotlin-lotto/giovannijunseokim/137-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +111 -0
- package/lessons/woowacourse-kotlin-lotto/haeum808/67-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/haeum808/95-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/hwannow/113-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +235 -0
- package/lessons/woowacourse-kotlin-lotto/hwannow/132-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/hxeyexn/77-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +141 -0
- package/lessons/woowacourse-kotlin-lotto/hxeyexn/98-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +162 -0
- package/lessons/woowacourse-kotlin-lotto/hyemdooly/17-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +19 -0
- package/lessons/woowacourse-kotlin-lotto/hyemdooly/28-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +23 -0
- package/lessons/woowacourse-kotlin-lotto/hyunji1203/15-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +171 -0
- package/lessons/woowacourse-kotlin-lotto/hyunji1203/48-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +150 -0
- package/lessons/woowacourse-kotlin-lotto/ii2001/62-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/ii2001/88-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/ijh1298/122-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +179 -0
- package/lessons/woowacourse-kotlin-lotto/ijh1298/133-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +153 -0
- package/lessons/woowacourse-kotlin-lotto/inseonyun/3-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +222 -0
- package/lessons/woowacourse-kotlin-lotto/inseonyun/49-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +166 -0
- package/lessons/woowacourse-kotlin-lotto/ippnsj/16-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +154 -0
- package/lessons/woowacourse-kotlin-lotto/ippnsj/55-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/jaeyeongjo/59-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +68 -0
- package/lessons/woowacourse-kotlin-lotto/jaeyeongjo/83-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +53 -0
- package/lessons/woowacourse-kotlin-lotto/jerry8282/115-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/jerry8282/134-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/jinuemong/63-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +144 -0
- package/lessons/woowacourse-kotlin-lotto/jinuemong/89-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +148 -0
- package/lessons/woowacourse-kotlin-lotto/jiyuneel/128-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/jiyuneel/144-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/junjange/58-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +148 -0
- package/lessons/woowacourse-kotlin-lotto/junjange/81-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/junseo511/120-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +153 -0
- package/lessons/woowacourse-kotlin-lotto/junseo511/131-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +188 -0
- package/lessons/woowacourse-kotlin-lotto/ki960213/43-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +24 -0
- package/lessons/woowacourse-kotlin-lotto/ki960213/8-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +159 -0
- package/lessons/woowacourse-kotlin-lotto/kimhm0728/74-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +50 -0
- package/lessons/woowacourse-kotlin-lotto/kimhm0728/94-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +176 -0
- package/lessons/woowacourse-kotlin-lotto/kkosang/85-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/kmkim2689/70-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/kmkim2689/82-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +157 -0
- package/lessons/woowacourse-kotlin-lotto/krrong/19-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +161 -0
- package/lessons/woowacourse-kotlin-lotto/krrong/41-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +73 -0
- package/lessons/woowacourse-kotlin-lotto/m6z1/105-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +67 -0
- package/lessons/woowacourse-kotlin-lotto/m6z1/151-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/medAndro/127-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +186 -0
- package/lessons/woowacourse-kotlin-lotto/medAndro/130-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +132 -0
- package/lessons/woowacourse-kotlin-lotto/moondev03/110-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/moondev03/141-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/murjune/69-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/murjune/90-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +177 -0
- package/lessons/woowacourse-kotlin-lotto/no1msh/20-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +69 -0
- package/lessons/woowacourse-kotlin-lotto/no1msh/46-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/otter66/13-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/otter66/53-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +160 -0
- package/lessons/woowacourse-kotlin-lotto/oungsi2000/126-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +71 -0
- package/lessons/woowacourse-kotlin-lotto/oungsi2000/149-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +56 -0
- package/lessons/woowacourse-kotlin-lotto/parkjiminnnn/117-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/parkjiminnnn/146-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +173 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/33-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/54-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +30 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/7-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +19 -0
- package/lessons/woowacourse-kotlin-lotto/re4rk/31-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/re4rk/4-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/rhkrwngud445/23-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/rhkrwngud445/38-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/rhthrhrl0/21-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +146 -0
- package/lessons/woowacourse-kotlin-lotto/rhthrhrl0/36-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +150 -0
- package/lessons/woowacourse-kotlin-lotto/rosemin928/123-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +179 -0
- package/lessons/woowacourse-kotlin-lotto/rosemin928/140-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +126 -0
- package/lessons/woowacourse-kotlin-lotto/s6m1n/103-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +119 -0
- package/lessons/woowacourse-kotlin-lotto/s6m1n/66-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +118 -0
- package/lessons/woowacourse-kotlin-lotto/s9hn/18-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +112 -0
- package/lessons/woowacourse-kotlin-lotto/sh1mj1/75-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/sh1mj1/91-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +140 -0
- package/lessons/woowacourse-kotlin-lotto/songpink/65-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +96 -0
- package/lessons/woowacourse-kotlin-lotto/songpink/99-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +64 -0
- package/lessons/woowacourse-kotlin-lotto/sujin9/10-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/sujin9/35-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/tmdgh1592/22-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +30 -0
- package/lessons/woowacourse-kotlin-lotto/tmdgh1592/30-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/tobae-time/114-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +158 -0
- package/lessons/woowacourse-kotlin-lotto/tobae-time/145-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +120 -0
- package/lessons/woowacourse-kotlin-lotto/whk06061/42-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/whk06061/9-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +89 -0
- package/lessons/woowacourse-kotlin-lotto/wondroid-world/118-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +100 -0
- package/lessons/woowacourse-kotlin-lotto/wondroid-world/150-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +142 -0
- package/lessons/woowacourse-kotlin-lotto/yrsel/108-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/yrsel/143-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +108 -0
- package/lessons/woowacourse-racingcar/2chang5/33-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/2chang5/75-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/CFalws/85-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/Choisehyeon/46-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/DYGames/49-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/EmilyCh0/40-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +64 -0
- package/lessons/woowacourse-racingcar/EmilyCh0/57-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/HamBeomJoon/137-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/HamBeomJoon/170-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/Hevton/106-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/Hevton/118-/353/246/254/355/214/251/355/204/260/353/247/201.md +51 -0
- package/lessons/woowacourse-racingcar/Hogu59/108-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/Hogu59/125-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/JoYehyun99/111-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/JoYehyun99/88-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +45 -0
- package/lessons/woowacourse-racingcar/Junyoung-WON/127-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/Junyoung-WON/90-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/Leeyerin0210/133-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/Leeyerin0210/159-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/PROGRESS.md +94 -0
- package/lessons/woowacourse-racingcar/README.md +69 -0
- package/lessons/woowacourse-racingcar/RightHennessy/51-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/RightHennessy/58-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/RunaNam/81-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +44 -0
- package/lessons/woowacourse-racingcar/SUMMARY.md +339 -0
- package/lessons/woowacourse-racingcar/SeongHoonC/37-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/SeongHoonC/66-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/Songusika/84-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/Yunseok-Nam/114-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/Yunseok-Nam/96-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/aprilgom/130-/353/246/254/355/214/251/355/204/260/353/247/201.md +52 -0
- package/lessons/woowacourse-racingcar/aprilgom/97-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/awesomeo184/23-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/boogi-woogi/35-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/boogi-woogi/59-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/briandr97/54-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/chaehyuns/131-/353/246/254/355/214/251/355/204/260/353/247/201.md +49 -0
- package/lessons/woowacourse-racingcar/chaehyuns/99-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/chanho0908/147-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/chanho0908/160-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/chws0508/45-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/chws0508/73-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +46 -0
- package/lessons/woowacourse-racingcar/cucumber99/132-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/cucumber99/177-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/devfeijoa/146-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/doabletuple/149-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/doabletuple/175-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/donghyun81/154-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/dpcks0509/103-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/dpcks0509/112-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/drunkenhw/82-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/etama123/145-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/gaeun5744/124-/353/246/254/355/214/251/355/204/260/353/247/201.md +53 -0
- package/lessons/woowacourse-racingcar/gaeun5744/93-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/gahyunkim/134-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/gahyunkim/164-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/giovannijunseokim/140-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/haeum808/101-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/haeum808/129-/353/246/254/355/214/251/355/204/260/353/247/201.md +46 -0
- package/lessons/woowacourse-racingcar/hwannow/141-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/hwannow/157-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +45 -0
- package/lessons/woowacourse-racingcar/hxeyexn/109-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/hxeyexn/128-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/hyemdooly/50-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/hyemdooly/68-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/hyunji1203/29-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/hyunji1203/60-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/ii2001/102-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +42 -0
- package/lessons/woowacourse-racingcar/ii2001/122-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/ijh1298/144-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/injoon2019/24-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/inseonyun/44-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/inseonyun/76-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/ippnsj/36-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/ippnsj/67-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/jaeyeongjo/110-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +39 -0
- package/lessons/woowacourse-racingcar/jaeyeongjo/89-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +46 -0
- package/lessons/woowacourse-racingcar/jinuemong/104-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/jinuemong/117-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +42 -0
- package/lessons/woowacourse-racingcar/jiyuneel/142-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/junjange/113-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +41 -0
- package/lessons/woowacourse-racingcar/junjange/87-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +39 -0
- package/lessons/woowacourse-racingcar/junseo511/148-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/junseo511/165-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/ki960213/32-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/ki960213/63-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/kimhm0728/100-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/kimhm0728/116-/353/246/254/355/214/251/355/204/260/353/247/201.md +54 -0
- package/lessons/woowacourse-racingcar/kkosang/105-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/kkosang/126-/353/246/254/355/214/251/355/204/260/353/247/201.md +53 -0
- package/lessons/woowacourse-racingcar/kmkim2689/123-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/kmkim2689/92-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/krrong/34-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +63 -0
- package/lessons/woowacourse-racingcar/m6z1/150-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/m6z1/156-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +40 -0
- package/lessons/woowacourse-racingcar/medAndro/153-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/moondev03/135-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/moondev03/161-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/murjune/121-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/murjune/95-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/no1msh/43-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/no1msh/69-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/otter66/48-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/otter66/77-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/oungsi2000/152-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/oungsi2000/187-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/parkjiminnnn/143-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/parkjiminnnn/158-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/pingu244/38-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/pingu244/62-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/re4rk/28-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/re4rk/55-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/rhkrwngud445/42-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/rhkrwngud445/74-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +47 -0
- package/lessons/woowacourse-racingcar/rhthrhrl0/31-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/rosemin928/138-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/rosemin928/171-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +38 -0
- package/lessons/woowacourse-racingcar/s6m1n/120-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/s6m1n/91-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/s9hn/53-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +44 -0
- package/lessons/woowacourse-racingcar/s9hn/78-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/sh1mj1/107-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/sh1mj1/115-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/songpink/119-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/songpink/98-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/sujin9/52-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/sujin9/61-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +47 -0
- package/lessons/woowacourse-racingcar/tmdgh1592/47-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/tmdgh1592/64-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/tobae-time/151-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/tobae-time/167-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/whk06061/41-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/wondroid-world/136-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/wondroid-world/166-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/yrsel/139-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/yujamint/83-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/package.json +46 -0
- package/skills/oh-my-oop/SKILL.md +39 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# PR #63 — [블랙잭 1단계] 누누 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@jinuemong](https://github.com/jinuemong)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-blackjack/pull/63
|
|
5
|
+
- **단계:** 1단계 (페어 — 클래스 다이어그램 동봉)
|
|
6
|
+
- **리뷰어:** @laco-dev
|
|
7
|
+
- **라인 코멘트:** 30 (리뷰어 20 / 리뷰이 10)
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`State` sealed class — `Action.Hit` / `Finish.Stay`·`BlackJack`·`Bust`** — 상태별 분기 폭증 회피.
|
|
12
|
+
- **`HandCard` + `State` 묶음으로 `BlackJack` 객체 도입** — 손패와 상태를 *Player*에서 분리. (의미는 별도 토론 — 못한 점 §3.)
|
|
13
|
+
- **`Result` enum + win/draw/lose 누적** — `MutableMap<Result, Int>`로 딜러 결과 집계.
|
|
14
|
+
- **`Participants` 일급 컬렉션 + `init` invariant** — 최대 인원, 딜러 1명 등을 생성 시 차단.
|
|
15
|
+
- **클래스 다이어그램을 PR 본문에 첨부** — 페어 토론의 가시화 (리뷰어가 다이어그램을 기반으로 질문 던짐).
|
|
16
|
+
- **`Ace` 1↔11 동적 보정 (`changeAceScore`)** — 21 초과 시 ACE를 1점으로 차감.
|
|
17
|
+
|
|
18
|
+
## 못한 점 (설계 관점)
|
|
19
|
+
|
|
20
|
+
### 1. `main()`이 게임 시나리오 결정자
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
fun main() {
|
|
24
|
+
val blackJackController = BlackJackController()
|
|
25
|
+
blackJackController.apply {
|
|
26
|
+
startGameFlow()
|
|
27
|
+
playGame()
|
|
28
|
+
calculateResult()
|
|
29
|
+
showResult()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
리뷰어: "컨트롤러가 블랙잭 게임이라는 하나의 프로그램으로 본다면 하나의 함수 대신 여러개의 함수로 분리된 이유는 무엇인가요?" → "블랙잭 게임의 시나리오를 결정하는 것이 현재는 Main 클래스입니다." — *시나리오*는 Controller의 책임. `main()`은 *진입점*만.
|
|
35
|
+
|
|
36
|
+
### 2. `Controller`의 `lateinit var` 멤버 — 호출 순서 의존
|
|
37
|
+
|
|
38
|
+
```kotlin
|
|
39
|
+
class BlackJackController {
|
|
40
|
+
private val gameManager = GameManager()
|
|
41
|
+
private lateinit var participants: Participants
|
|
42
|
+
private lateinit var gameResult: GameResult
|
|
43
|
+
|
|
44
|
+
fun startGameFlow() { participants = ...; gameManager.setGame(participants) }
|
|
45
|
+
fun playGame() { participants.getAlivePlayers()... } // startGameFlow() 호출 안 하면 lateinit 예외
|
|
46
|
+
fun calculateResult() { gameResult = GameResult(...) }
|
|
47
|
+
fun showResult() { gameResult.getDealerResults()... }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
리뷰어: "참가자와 게임 결과를 멤버 프로퍼티로 만드는 것은 지역 변수로 만드는 것과 어떤 장단점이 있나요?" / "하나의 컨트롤러 인스턴스에서 여러번의 게임이 진행 될 경우 발생할 수 있는 문제가 걱정됩니다. > Controller의 startGameFlow()를 가장 먼저 호출하지 않으면 어떻게 될까?" — *호출 순서 invariant*가 코드로 보호되지 않음.
|
|
52
|
+
|
|
53
|
+
### 3. `BlackJack` 객체의 의미 모호 — `HandCard + State` 묶음
|
|
54
|
+
|
|
55
|
+
```kotlin
|
|
56
|
+
class BlackJack {
|
|
57
|
+
private val handCard = HandCard()
|
|
58
|
+
private var _state: State = State.Action.Hit
|
|
59
|
+
val state: State get() = _state
|
|
60
|
+
fun addCard(card: Card) { handCard.addCard(card); changeState() }
|
|
61
|
+
fun changeState() { ... } // public — 테스트용 노출
|
|
62
|
+
}
|
|
63
|
+
class Participant(val name: String) {
|
|
64
|
+
val blackJack = BlackJack()
|
|
65
|
+
...
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
리뷰어: "참가자가 가지고 있는 블랙잭이라는 객체는 무슨 역할을 하기를 기대할까요? 다이어그램 상으로는 `블랙잭 == 상태` 라는 판단으로 보이지만, 이 블랙잭 객체는 무엇을 하고 싶은 것인지 잘 모르겠어요. > 블랙잭 상태도 있는데 블랙잭 객체는 뭐지? 🤔"
|
|
70
|
+
|
|
71
|
+
학생 자가 설명: "블랙잭은 상태와 손패(사용자가 가지고 있는 카드 리스트)를 나타냅니다. 처음에 플레이어별로 손패와 state를 가지게 하려했지만, 관심사를 분리하고 확장성을 고려, 생성자의 수를 2로 제한이라는 규칙으로 고민끝에 하나의 객체를 더 만들게 되었습니다." — *생성자 수 2 제한*이라는 형식 규칙을 위해 *의미 없는 묶음 객체*가 탄생. *형식 규칙*과 *도메인 의미*가 충돌하면 의미가 우선.
|
|
72
|
+
|
|
73
|
+
### 4. `Card`에 `private val` + `getCardDenomination()` 함수형 getter
|
|
74
|
+
|
|
75
|
+
```kotlin
|
|
76
|
+
class Card(
|
|
77
|
+
private val denomination: Denomination,
|
|
78
|
+
private val suit: Suit,
|
|
79
|
+
) {
|
|
80
|
+
fun getCardDenomination(): Denomination = denomination
|
|
81
|
+
fun getCardSuit(): Suit = suit
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
리뷰어: "프로퍼티의 접근자를 public으로 하는 것과, 함수로 getter()를 만드는 것에 차이가 있나요?"
|
|
86
|
+
학생: "좀 더 많은 것을 제어할 수 있다고 생각했습니다. 단순히 getter()로 만드는 것은 함수를 추가적으로 호출하기 때문에 최적의 선택이라고 생각하지는 않습니다. 2단계 미션을 고려하여 추가적인 로직이 있을 것이라고 생각하였고, getter() 사용을 습관화(?)하려 하였습니다." — Kotlin의 `val`은 *이미 getter*이며 *나중에 커스텀 getter로 대체 가능*. Java 습관을 그대로 가져온 함수형 getter.
|
|
87
|
+
|
|
88
|
+
### 5. `CardDeck`이 `Set<Card>` — "한 장씩 뽑기" 개념과 부정합
|
|
89
|
+
|
|
90
|
+
```kotlin
|
|
91
|
+
class CardDeck {
|
|
92
|
+
private var cards: Set<Card> = ... .shuffled().toSet()
|
|
93
|
+
fun draw(): Card {
|
|
94
|
+
val popCard = cards.take(DRAW_COUNT).firstOrNull() ?: throw IllegalArgumentException(EMPTY_CARD_DECK)
|
|
95
|
+
cards -= popCard
|
|
96
|
+
return popCard
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
리뷰어: "카드를 한장 씩 뽑아쓰는 것을 표현하기 위해 다른 자료구조를 사용 해 볼 수 있지 않을까요? 지금의 Set 구조는 이 개념을 나타내기에 적절하지 않아 보이네요" — `ArrayDeque`/`Stack` 또는 가변 `MutableList`로 *맨 위 카드를 뽑는다* 개념을 자료구조 자체로 표현. *셔플 후 Set으로 toSet()* 한 시점에 순서가 무의미해지므로 *항상 같은 카드*가 나올 위험.
|
|
102
|
+
|
|
103
|
+
또 리뷰어: "준비된 덱이 항상 52장의 랜덤한 카드뭉치로 되어 있다면, 테스트가 어렵지 않을까요? 가령 덱에 스페이드 A 카드 1장이 들어있을 때, 카드를 뽑으면 스페이드 A다 라는 테스트는 어떻게 할 수 있을까요?" — `CardDeck`이 외부에서 주입된 카드 순서를 받을 수 있어야 *결정적 테스트* 가능.
|
|
104
|
+
|
|
105
|
+
### 6. `Dealer.openFirstCard()`가 정상 흐름에서 예외 던짐
|
|
106
|
+
|
|
107
|
+
```kotlin
|
|
108
|
+
class Dealer(name: String = DEFAULT_DEALER_NAME) : Participant(name) {
|
|
109
|
+
fun openFirstCard(): Card =
|
|
110
|
+
getCards().firstOrNull() ?: throw IllegalArgumentException(ERROR_CARD_INDEX)
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
리뷰어: "지난 로또 미션에서 오류 발생을 최대한 피하는 전략을 경험했습니다. 첫번 째 카드가 없다는 동작이 오류를 발생시키지 않도록 만들어 보면 어떨까요?" — `Dealer` 생성 직후 `setGame(participants)` 호출로 *2장 분배*가 보장된다면, *카드 분배 후*에만 `openFirstCard()`를 호출하는 흐름이 정상. 그러나 호출 시점 invariant를 깨고 예외로 보호하면 *정상 흐름에서 예외*가 발생할 위험.
|
|
115
|
+
|
|
116
|
+
### 7. `Dealer.checkDealerScoreCondition()` — 함수명 모호
|
|
117
|
+
|
|
118
|
+
```kotlin
|
|
119
|
+
fun checkDealerScoreCondition(): Boolean = getBlackJackScore() <= MIN_HAND_CARD_SCORE
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
리뷰어: "`checkDealerScoreCondition` 라는 이름은 반환 값이 무엇인지 예측이 어려워 보입니다. `점수를 검사한다 --> true --> 뽑는다 ??` 이 의미를 나타내는 적절한 이름은 없을까요?" — `canDraw()` / `shouldHit()` / `mustHit()` — *결과를 동사로*. `check`/`condition` 같은 *검사 동작*은 *반환값과의 연관*이 끊김.
|
|
123
|
+
|
|
124
|
+
### 8. `GameManager`가 가변 setter 보유 — 게임 단위 인스턴스 아님
|
|
125
|
+
|
|
126
|
+
```kotlin
|
|
127
|
+
class GameManager {
|
|
128
|
+
private val cardDeck = CardDeck()
|
|
129
|
+
fun setGame(participants: Participants) {
|
|
130
|
+
repeat(INIT_HAND_CARD_COUNT) {
|
|
131
|
+
participants.getParticipants().forEach { it.draw(cardDeck.draw()) }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
리뷰어: "게임 매니저가 하나의 게임을 관장한다면, 게임이 시작할 때 새로운 인스턴스가 만들어지고, 게임이 끝나면 인스턴스를 종료하는 그런 설계를 해 볼 수 있지 않을까요? `class GameManager(참가자, 딜러, 덱, ...)`" — *setter 기반 setup*은 *생성 시점의 invariant 보호*를 잃는다.
|
|
138
|
+
|
|
139
|
+
### 9. `GameResult`에서 *플레이어 상태 판단*
|
|
140
|
+
|
|
141
|
+
```kotlin
|
|
142
|
+
private fun judgeBlackJackScore(player: Player) {
|
|
143
|
+
when (player.getBlackJackState()) {
|
|
144
|
+
is State.Finish.Bust -> addDealerWin(player)
|
|
145
|
+
is State.Finish.BlackJack -> applyBlackJackState(player)
|
|
146
|
+
is State.Finish.Stay, State.Action.Hit -> compareToResult(player)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
리뷰어: "플레이어의 상태를 판단하고 변경하는 것 또한 플레이어가 스스로 하도록 할 수 있지 않을까요?" / "마찬가지로 승부를 겨루는 것은, 게임 결과가 하는 대신 참가자가 스스로 하도록 만들어보세요. 승부를 결정하는 것은, 참가자 정보만 있다면 상대가 누구라도 상관이 없습니다. 딜러와 플레이어 / 플레이어와 플레이어 / 딜러와 딜러" — *Tell-Don't-Ask*. `player.compete(other)` 형태로.
|
|
152
|
+
|
|
153
|
+
학생 자가 토론: "참가자가 죽었는지 확인은 심판의 역할이라고 생각하며, 현재 제가 설계한 객체들에서 참가자가 승부를 결정하는 역할을 하는 것이 맞는지 생각이 듭니다.." — *심판*과 *참가자*의 책임 경계는 도메인 비유에 의존. 리뷰어 입장은 *상대가 누구든 무관한 비교*는 참가자 자신의 책임. *심판*의 진짜 책임은 *룰 적용*(보너스 1.5배 등)이지 *점수 비교*가 아님.
|
|
154
|
+
|
|
155
|
+
### 10. `Participants` 첫 항목 = `Dealer` invariant — 추상화 누수
|
|
156
|
+
|
|
157
|
+
```kotlin
|
|
158
|
+
class Participants(private val participants: List<Participant>) {
|
|
159
|
+
init {
|
|
160
|
+
require(participants.first() is Dealer) { ERROR_NOT_EXIST_DEALER }
|
|
161
|
+
require(participants.count { it is Dealer } == DEALER_COUNT) { ERROR_INVALID_DEALER_COUNT }
|
|
162
|
+
}
|
|
163
|
+
fun getDealer(): Dealer = participants.first() as Dealer
|
|
164
|
+
fun getPlayers(): List<Player> = participants.subList(1, participants.size).map { it as Player }
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
리뷰어: "참가자라는 타입으로 추상화를 했다면, 1번째 항목이 딜러라는 것을 어떻게 신뢰할 수 있을까요?" — *동일 타입 컬렉션*인데 *0번 인덱스만 특별*하면 추상화 위반. `class Participants(val dealer: Dealer, val players: List<Player>)`로 두 역할을 *타입으로 분리*. `as Dealer` 다운캐스트와 인덱스 비교의 *근거*가 사라지면 컴파일러가 *0번 = Dealer* invariant를 보장.
|
|
169
|
+
|
|
170
|
+
### 11. `Player.checkDuplication`이 정적 메서드
|
|
171
|
+
|
|
172
|
+
```kotlin
|
|
173
|
+
class Player(name: String) : Participant(name) {
|
|
174
|
+
companion object {
|
|
175
|
+
fun checkDuplication(name: String, playerNames: Set<String>) {
|
|
176
|
+
require(!playerNames.contains(name)) { ERROR_DUPLICATION_NAME }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
리뷰어: "이름이 중복되었는지 검사하는게 Player 객체의 역할일까요?" — *중복*은 *컬렉션 수준*의 invariant. `Players(names: List<String>)` 의 `init`에 두는 것이 자연.
|
|
183
|
+
|
|
184
|
+
### 12. `UserDecision` enum / `UserInputValidator` — 도메인 패키지에 UI 형식
|
|
185
|
+
|
|
186
|
+
```kotlin
|
|
187
|
+
// blackjack/model/user/UserDecision.kt
|
|
188
|
+
enum class UserDecision(private val userDecision: String) {
|
|
189
|
+
YES("y"),
|
|
190
|
+
NO("n"),
|
|
191
|
+
;
|
|
192
|
+
companion object {
|
|
193
|
+
fun getUserDecision(input: String): UserDecision =
|
|
194
|
+
UserDecision.entries.find { it.userDecision == input }
|
|
195
|
+
?: throw IllegalArgumentException(ERROR_DECISION)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// blackjack/model/user/UserInputValidator.kt
|
|
200
|
+
object UserInputValidator { ... }
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
리뷰어: ""y"와 "n"으로 결정되는 것은 UI 로직이 아닐까요? 만약 "Y", "N" 으로 입력한다면 도메인 모델이 수정되어야 합니다." / "`UserInputValidator`도 마찬가지로 UI 로직으로 볼 수 있지 않을까요?" — *UI 형식 변경(대소문자)이 도메인 변경을 유발*하면 의존 방향 역전. *도메인은 `Hit`/`Stay` 같은 도메인 어휘만*. `"y"→Hit`/`"n"→Stay` 매핑은 InputView.
|
|
204
|
+
|
|
205
|
+
### 13. `BlackJack.changeState()` public — 테스트 위해 캡슐화 깸
|
|
206
|
+
|
|
207
|
+
```kotlin
|
|
208
|
+
fun changeState() {
|
|
209
|
+
when (val totalScore = handCard.getTotalCardsSum()) {
|
|
210
|
+
in MIN_SCORE until BLACK_JACK_SCORE -> _state = State.Action.Hit
|
|
211
|
+
BLACK_JACK_SCORE -> _state = State.Finish.BlackJack
|
|
212
|
+
in BUST_SCORE..MAX_SCORE -> { _state = State.Finish.Bust; changeAceScore(totalScore) }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
리뷰어: "`changeState`는 외부에서 사용되지 않고 있네요. 테스트를 위해 public으로 함수를 공개하는 것은 적절하지 않습니다. 이 기능을 테스트 하기 위한 다른 방법을 찾아야 합니다. 또한 함수 이름으로 하여금 어떤 역할을 하는 것인지 기대하기가 어려워 보입니다." — 테스트는 *입력 → 출력*을 검증. `addCard(card)` 호출 후 `state`를 확인하면 자연. *내부 메서드 호출*을 테스트하는 패턴은 *구현에 결합된 테스트*.
|
|
218
|
+
|
|
219
|
+
### 14. Ace 보정 로직 복잡 — `while + 차감` 패턴
|
|
220
|
+
|
|
221
|
+
```kotlin
|
|
222
|
+
private fun changeAceScore(totalScore: Int) {
|
|
223
|
+
var currentScore = totalScore
|
|
224
|
+
var aceCount = handCard.getAceCount()
|
|
225
|
+
while (aceCount > 0 && state == State.Finish.Bust) {
|
|
226
|
+
aceCount -= 1
|
|
227
|
+
currentScore -= Denomination.ACE.getScore() + Denomination.aceTransferScore()
|
|
228
|
+
checkCurrentScore(currentScore)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
리뷰어 권고: "블랙잭 보너스 점수를 계산할 때 아래 방법으로 간단하게 계산할 수 있습니다. > 카드들에 에이스 번호가 있을 때, 카드들의 점수 합계가 11점 이하라면, 보너스 포인트 10점을 획득한다." — *Ace를 1점으로 시작 + 합 ≤ 11이면 +10*. 한 줄 룰. `while + 차감 + 상태 재검사`보다 *불변식 한 줄*이 도메인 표현에 부합.
|
|
234
|
+
|
|
235
|
+
## 리뷰어 의견 요지
|
|
236
|
+
|
|
237
|
+
- **`main`은 진입점, Controller가 시나리오 결정자.**
|
|
238
|
+
- **호출 순서 invariant는 *생성자 주입*으로 보호** — `lateinit var` + `setGame(...)`는 위반.
|
|
239
|
+
- **`BlackJack` 같은 *의미 모호 객체*는 도메인 어휘에 없으면 의심** — *형식 규칙*보다 *도메인 의미*.
|
|
240
|
+
- **`val`은 이미 getter** — `fun getX()`는 Java 습관.
|
|
241
|
+
- **`CardDeck` 자료구조 = 한 장씩 뽑기 = Stack/Deque** — `Set`은 *순서 없음*과 충돌.
|
|
242
|
+
- **`Dealer.openFirstCard`가 예외 던지면 호출 시점 invariant 누락.**
|
|
243
|
+
- **`check*Condition()` 같은 *검사* 동사보다 *결과 동사*** — `canDraw()` / `shouldHit()`.
|
|
244
|
+
- **`GameManager`는 게임 단위 인스턴스 — 생성자 주입 + 종료.**
|
|
245
|
+
- **상태 판단/변경/승부는 *참가자 자신*** — `Tell, Don't Ask`.
|
|
246
|
+
- **`Participants` = `Dealer + Players` 타입 분리** — 인덱스 0번 invariant 회피.
|
|
247
|
+
- **`UserDecision`/`UserInputValidator`는 도메인 X** — UI 입력 형식.
|
|
248
|
+
- **`changeState()` public은 캡슐화 위반** — `addCard()` → `state` 변화로 테스트.
|
|
249
|
+
|
|
250
|
+
## 대표 인용
|
|
251
|
+
|
|
252
|
+
> 참가자가 가지고 있는 블랙잭이라는 객체는 무슨 역할을 하기를 기대할까요? 다이어그램 상으로는 `블랙잭 == 상태` 라는 판단으로 보이지만, 이 블랙잭 객체는 무엇을 하고 싶은 것인지 잘 모르겠어요.
|
|
253
|
+
> — @laco-dev on `src/main/kotlin/blackjack/model/BlackJack.kt`
|
|
254
|
+
|
|
255
|
+
> 마찬가지로 승부를 겨루는 것은, 게임 결과가 하는 대신 참가자가 스스로 하도록 만들어보세요. 승부를 결정하는 것은, 참가자 정보만 있다면 상대가 누구라도 상관이 없습니다. 딜러와 플레이어 / 플레이어와 플레이어 / 딜러와 딜러
|
|
256
|
+
> — @laco-dev on `src/main/kotlin/blackjack/model/GameResult.kt`
|
|
257
|
+
|
|
258
|
+
> 참가자라는 타입으로 추상화를 했다면, 1번째 항목이 딜러라는 것을 어떻게 신뢰할 수 있을까요?
|
|
259
|
+
> — @laco-dev on `src/main/kotlin/blackjack/model/Participants.kt`
|
|
260
|
+
|
|
261
|
+
> "y"와 "n"으로 결정되는 것은 UI 로직이 아닐까요? 만약 "Y", "N" 으로 입력한다면 도메인 모델이 수정되어야 합니다.
|
|
262
|
+
> — @laco-dev on `src/main/kotlin/blackjack/model/user/UserDecision.kt`
|
|
263
|
+
|
|
264
|
+
> 카드를 한장 씩 뽑아쓰는 것을 표현하기 위해 다른 자료구조를 사용 해 볼 수 있지 않을까요? 지금의 Set 구조는 이 개념을 나타내기에 적절하지 않아 보이네요
|
|
265
|
+
> — @laco-dev on `src/main/kotlin/blackjack/model/CardDeck.kt`
|
|
266
|
+
|
|
267
|
+
## 얻은 교훈
|
|
268
|
+
|
|
269
|
+
- **`main()`은 *진입점*만, *시나리오*는 Controller.** `apply { startGameFlow(); playGame(); ... }`이 main에 있으면 *흐름 결정자*가 main으로 누수.
|
|
270
|
+
- **`lateinit var` + setter setup = 호출 순서 invariant 누락** — 생성자 주입으로 컴파일러가 invariant 보장.
|
|
271
|
+
- **객체 이름이 *도메인 어휘에 없으면* 의심하라.** `BlackJack` 객체 = 손패 + 상태 묶음은 *생성자 수 제한* 같은 형식 규칙을 위한 *인공물*일 가능성. *형식 규칙은 의미를 만들지 않는다.*
|
|
272
|
+
- **Kotlin `val`은 이미 getter** — `fun getX() = x`는 Java의 *수동 getter* 습관. 필요 시 *커스텀 getter*로 대체 가능.
|
|
273
|
+
- **자료구조가 도메인 개념을 표현해야** — *한 장씩 뽑기* = `ArrayDeque`/`Stack`. `Set + shuffled`은 *순서 없음*과 *뽑기 순서*가 충돌.
|
|
274
|
+
- **`Dealer.openFirstCard()`처럼 정상 흐름에서 예외 던지지 말 것** — 호출 시점 invariant를 *분배 후*로 보장.
|
|
275
|
+
- **함수명 = 결과 동사** — `checkDealerScoreCondition()` 같은 *검사* 동사는 *반환값이 무엇을 의미하는지* 모호. `canDraw()`, `shouldHit()`.
|
|
276
|
+
- **`Tell, Don't Ask` — 상태 판단·변경·승부는 객체 자신**. `GameResult`가 `player.state`를 보고 `addDealerWin`하지 말고, `player.compete(other)`.
|
|
277
|
+
- **추상화한 컬렉션의 *인덱스 특별 처리*는 추상화 누수** — `Participants(dealer, players)`로 타입 분리.
|
|
278
|
+
- **UI 입력 형식(`"y"`/`"n"`, `"Y"`/`"N"`)은 InputView 책임** — 도메인 enum은 `Hit`/`Stay` 같은 도메인 어휘만.
|
|
279
|
+
- **`public` 함수를 *테스트 때문에 노출*하지 말 것** — 입력→출력 경로로 테스트. *내부 메서드 호출*을 검증하는 테스트는 구현 결합.
|
|
280
|
+
- **Ace 보정 = *불변식 한 줄*** — *합 ≤ 11이면 +10*. `while + 차감 + 재검사`는 *알고리즘으로 룰을 흩뜨림*.
|
|
281
|
+
- **도메인 비유로 책임 분배 가능 — 그러나 비유와 SRP가 충돌할 때는 SRP** — 학생 의문(*심판이 점수 비교*)은 도메인 비유 충실. 리뷰어 입장(*비교는 참가자*)은 *상대 무관 비교*의 일반화. 도메인 비유가 *재사용 단위*를 가르치지 않을 때는 *코드의 응집도*가 우선.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# PR #92 — [블랙잭 2단계] 누누 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@jinuemong](https://github.com/jinuemong)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-blackjack/pull/92
|
|
5
|
+
- **단계:** 2단계 (베팅 + 수익률 1.5배 룰)
|
|
6
|
+
- **리뷰어:** @laco-dev
|
|
7
|
+
- **라인 코멘트:** 30 (리뷰어 17 / 리뷰이 13)
|
|
8
|
+
- **참고:** 같은 학생의 1단계 = PR #63
|
|
9
|
+
|
|
10
|
+
## 잘한 점 (설계 관점)
|
|
11
|
+
|
|
12
|
+
- **`State` sealed (Action.Hit / Finish.Stay·BlackJack·Bust) 유지** — 1단계에서 도입.
|
|
13
|
+
- **`runBlackJackGame()` 단일 엔트리포인트로 진행 응집 (후속 반영)** — `main`이 시나리오 결정자였던 PR #63 문제 해결.
|
|
14
|
+
- **`Wallet` → `UserInformation` 명명 변경 + `Proceeds` → `revenue` 명명 변경** — 학생 자가 토론으로 이름 개선.
|
|
15
|
+
- **`GameResult` private 멤버 + 접근 메서드** — 외부에서 Map 직접 접근 차단.
|
|
16
|
+
- **블랙잭 1.5배 룰 분리 — `settleBettingPayout(result, isBlackJackState)`**.
|
|
17
|
+
|
|
18
|
+
## 못한 점 (설계 관점)
|
|
19
|
+
|
|
20
|
+
### 1. `main` vs Controller 책임 — 학생 자가 의문 + 리뷰어 심층 답변
|
|
21
|
+
|
|
22
|
+
학생 질문: "요 코드가 *각 함수로 되어져 있다면 하나라도 먼저 호출되지 않는다면 같은 상황이 발생하는 것인가요?* 제가 *코드를 순차적으로 실행하는 것을 보장하고 있지 않은 것*인지, *모든 코드에서 순차 실행이 되지 않을 경우를 생각해야 할까요?*"
|
|
23
|
+
|
|
24
|
+
리뷰어: "*문제의 본질을 잘 해석하셨습니다.* 마찬가지로 블랙잭 매니저 도메인도 같은 문제를 가질 수 있습니다. 하지만 *컨트롤러는 도메인 로직의 상태를 판단하고, 그에 맞춰 함수를 작성*하는 반면 메인 클래스는 어떻게 해야 할까요? [...] 만약 게임이 *정상적으로 동작하지 않는다면, 개발자는 메인 클래스를 잘못 작성한 것일까요? 컨트롤러를 잘못 작성한 것일까요?* [...] 결론적으로 *컨트롤러와 뷰 없이도 게임을 진행할 수 있는가?* 라는 목표를 예로 둘 수 있겠습니다."
|
|
25
|
+
|
|
26
|
+
→ **호출 순서 invariant의 책임 위치 = Controller**. *main은 어떤 게임/Controller를 띄울지* 결정만, *각 컨트롤러는 자기 게임의 호출 순서 책임*. 학생 후속: `main` → `runBlackJackGame()` 단일 호출.
|
|
27
|
+
|
|
28
|
+
### 2. `runBlackJackGame()`의 *void 반환 함수 시퀀스* — 사이드 이펙트 의존
|
|
29
|
+
|
|
30
|
+
```kotlin
|
|
31
|
+
fun runBlackJackGame() {
|
|
32
|
+
startGameFlow() // 사이드 이펙트
|
|
33
|
+
playGame() // 사이드 이펙트
|
|
34
|
+
showResult() // 사이드 이펙트
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
리뷰어: "*원래 함수란, 무언가를 반환하도록 설계되었습니다. 만약 아무것도 반환하지 않는다면 사이드 이펙트를 발생시킨다는 것을 의미*할 수 있으니까요. [...] 아래 코드랑 비교했을때 어떤 차이가 있는지 고민 해보시면 좋겠습니다. ```kotlin fun runBlackJackGame() { val gameManager = createGameManager(); readyGame(gameManager); val gameResult: GameResult = playGame(gameManager); showResult(gameResult) } ```"
|
|
39
|
+
|
|
40
|
+
→ *void 함수 시퀀스 + 멤버 필드 공유*는 *암묵 의존*. *return 값 전달*은 *데이터 흐름 가시화*. 후속 학생 인정: "*사이드 이펙트에 대해서 좀 더 공부를 해보고, 코드를 짤 때 고민해봐야겠습니다*."
|
|
41
|
+
|
|
42
|
+
### 3. `Wallet(name, balance)` — *지갑에 이름 붙임* + *3변수 제한 회피*
|
|
43
|
+
|
|
44
|
+
```kotlin
|
|
45
|
+
data class Wallet(val name: String) {
|
|
46
|
+
private var balance: Int = 0
|
|
47
|
+
fun setMoney(money: Int) { balance = money }
|
|
48
|
+
fun getBalance(): Int { return balance }
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
리뷰어: "*참가자가 이름을 가지지 않고, 지갑에 이름을 붙이는게 맞나요?* *인스턴스 변수 3개 조건을 억지로 지키려고 만들어진 것 같은 느낌*이 듭니다. 우선은 3개를 사용하더라도, 더 좋은 구조라고 생각이 든다면 그렇게 해주시면 됩니다. > 딜러는 "딜러"라는 이름을 가진다. > 딜러는 "딜러"라는 이름의 지갑을 가진다."
|
|
53
|
+
|
|
54
|
+
학생: "저는 wallet에 *신분증과 베팅 머니를 저장하는 그림*을 생각했습니다. *다시보니 네이밍에 문제가 있었던 것 같습니다*. **UserInformation**으로 전환하니 구조가 괜찮아 진 것 같습니다."
|
|
55
|
+
|
|
56
|
+
리뷰어 (Dealer.kt에 답변): "*유저정보가 되서 더 좋아졌다고 생각하셨지만... 사실 Information이라는 이름은 객체지향 설계에 굉장한 피곤함을 주는 이름*입니다. 왜냐하면 *만능*이거든요. *정보에는 모든게 다 들어갈 수 있고, 모든 게 다 있으니 아무런 코*..."
|
|
57
|
+
|
|
58
|
+
→ **PR #135 (ijh1298) `PlayerBetInfo`와 동일 안티패턴**. *형식 규칙(3변수 제한)*이 *인공 객체* 만들어냄. 게다가 *Wallet → UserInformation* 명명 변경도 *Information은 만능 이름*이라 또 다른 안티패턴. *`Player.betAmount`* 자연 표현이 두 번 우회됨.
|
|
59
|
+
|
|
60
|
+
### 4. `Wallet.balance` `var` + `setMoney()` — 변경 불필요
|
|
61
|
+
|
|
62
|
+
리뷰어: "*현재 요구사항에서는 돈이 동적으로 변경될 일이 없는 것 같은데요. 상태를 동적으로 변경할 수 있도록 만든 이점이 있을까요?*" — 게임 1회당 *베팅 한 번 + 결과 계산*. *Mutable balance는 가능성 시나리오를 위한 과잉*. `val balance: Int` + *생성 시 결정*이 자연.
|
|
63
|
+
|
|
64
|
+
### 5. `Proceeds(name, proceeds)` — 모호한 명사
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
class Proceeds(val name: String, val proceeds: Int)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
리뷰어: "*이 객체는 무슨 역할을 하는지 알려주세요. 🙇🏻 객체 이름과 상태를 봐도 모르겠어서 질문 드립니다.*"
|
|
71
|
+
|
|
72
|
+
학생: "*한 게임에 대한 수익을 가지고 있습니다. 이름에 대한 뜻이 너무 많아서 **revenue** 로 전환*하였습니다."
|
|
73
|
+
|
|
74
|
+
→ `Proceeds`/`Revenue`도 *클래스 = 속성*과 다름. `PlayerProfit(player, amount)`가 자연. `name`과 `proceeds` 두 변수면 *플레이어와 그 수익*인데 *이름*이 *모호 명사*로 가려짐. (`Information` 회피와 같은 결.)
|
|
75
|
+
|
|
76
|
+
### 6. `BlackJack`과 `HandCard` 두 곳에서 점수 계산
|
|
77
|
+
|
|
78
|
+
```kotlin
|
|
79
|
+
class BlackJack {
|
|
80
|
+
private val handCard = HandCard()
|
|
81
|
+
private fun updateGameStateWithScore() {
|
|
82
|
+
val score = handCard.getTotalCardsSum()
|
|
83
|
+
when (getGameScoreWithAceCount(score)) { ... }
|
|
84
|
+
}
|
|
85
|
+
private fun getGameScoreWithAceCount(score: Int): Int {
|
|
86
|
+
val transferScore = score + Denomination.TRANSFER_ACE_SCORE
|
|
87
|
+
return if (handCard.checkStateWithAceCount() && transferScore <= BLACK_JACK_SCORE) transferScore else score
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
리뷰어: "*카드들의 점수 합을 계산하는 규칙을 두개로 나눈 이유가 무엇일까요?* 핸드에서도 *총합 점수가 계산*되고 블랙잭에서도 *총합점수가 계산*이 됩니다. [...] *이미 핸드 자체가 블랙잭 도메인에 깊게 관여*를 하고 있기에 *핸드에서 계산을 해도 충분*하다고 생각하는데요. 카드들의 점수 합을 계산하고 *이를 테스트 하려면, 반드시 블랙잭 객체로만 테스트를 해야 하기 때문에 굉장히 난이도가 올라가지는 않았을까요?*" — *점수 계산 = Hand 단일 책임*. *Bust/BlackJack 판정*만 BlackJack에. *테스트 단순화*가 부수 효과.
|
|
93
|
+
|
|
94
|
+
### 7. `HandCard`의 `private set` 오용
|
|
95
|
+
|
|
96
|
+
```kotlin
|
|
97
|
+
class HandCard {
|
|
98
|
+
private var _cards: List<Card> = listOf()
|
|
99
|
+
var cards: List<Card>
|
|
100
|
+
get() = _cards
|
|
101
|
+
private set(value) { _cards = value } // 외부 setter는 막혔으나 _cards와 중복
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
리뷰어: "*`private set` 을 사용하는 올바른 사례가 아닙니다.* https://kotlinlang.org/docs/properties.html *backing property랑 비교했을 때 어떤 차이*인지 고민해보시면 좋겠습니다." — *backing property*는 `private val _cards` + `val cards: List<Card> get() = _cards`. `private set`은 *같은 프로퍼티의 setter만 private*. *외부 변경 차단 + 클래스 내부에서만 변경*. **두 패턴이 다른 목적**. 학생이 *둘을 섞어* `private var _cards` + `private set`을 동시에 노출 — 의도 불명.
|
|
106
|
+
|
|
107
|
+
### 8. `CardDeck(cards: List<Card> = emptyList())` — *빈 덱이면 셔플* 분기
|
|
108
|
+
|
|
109
|
+
```kotlin
|
|
110
|
+
class CardDeck(cards: List<Card> = emptyList()) {
|
|
111
|
+
init {
|
|
112
|
+
if (this.cards.isEmpty()) { cardShuffle() }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
리뷰어: "*다른 사람이 봤을 때, 아래 코드가 논리적으로 좋은 방법일까요..?* ```val cardDeck = CardDeck(cards = emptyList()) // 비어있는 덱을 만들어야지! cardDeck.draw() // A 스페이드``` 테스트로 만든다면, 아래와 같은 케이스가 나올 것 같은데요 🤔 > *비어있는 덱을 만들면 셔플한다*"
|
|
118
|
+
|
|
119
|
+
→ *`cards = emptyList()` 인자*가 *셔플 트리거*. *호출자 의도*(빈 덱)와 *실제 동작*(셔플 후 52장) 불일치. `CardDeck()` no-arg 생성자 = *셔플된 새 덱*, `CardDeck(cards)` = *주어진 카드들로 덱*. 두 의도 분리.
|
|
120
|
+
|
|
121
|
+
### 9. `BlackJack.applyGameStateWithAceCount` 깊은 분기 vs 단순 룰
|
|
122
|
+
|
|
123
|
+
```kotlin
|
|
124
|
+
// Before (학생)
|
|
125
|
+
private fun applyGameStateWithAceCount(totalScore: Int) {
|
|
126
|
+
if (handCard.updateGameStateWithAceCount(totalScore)) {
|
|
127
|
+
state = State.Finish.BlackJack
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
리뷰어 권고: ```kotlin
|
|
133
|
+
val score = handCard.getTotalScore()
|
|
134
|
+
when {
|
|
135
|
+
score == 21 && handCard.size == 2 -> State.Finished.BlackJack
|
|
136
|
+
score == 21 -> State.Finished.Stay
|
|
137
|
+
score > 21 -> State.Finished.Bust
|
|
138
|
+
else -> State.Action.Hit
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
리뷰어: "*점수를 계산하는 것은 내부에서 알아서 할 일인데, 에이스가 포함되어있는지 여부가 밖에서 알 필요가 없지 않을까* 생각해요. *함수의 깊이가 깊어지는 것도 한 가지 이 코드의 아쉬운 점*이라고 생각합니다." — *Ace 보정*은 `HandCard.getTotalScore()` 내부. *외부에서는 보정 후 점수*만 봄. *상태 결정*은 *점수 + 카드 수* 단순 분기.
|
|
143
|
+
|
|
144
|
+
### 10. `21점일 때 Stay 자동 진입` vs *유저 의지로 Hit 유지* — 학생 자가 의문
|
|
145
|
+
|
|
146
|
+
리뷰어: "*21점일 때 이 함수로 빠지는데, 카드가 2장이 아니면 어떤 상태가 되는건가요?*"
|
|
147
|
+
|
|
148
|
+
학생: "*Stay 상태가 되는게 맞나요?* 저는 *21점인지 판단은 유저가 해서 Hit 상태를 유지하는게 맞다*고 봤습니다. *이는 너무 현실세계에 몰입한 것일까요?* 자동으로 Stay 상태가 되는 것이 아닌 *유저가 본인의 점수 계산을 실수할 수도 있다*고 생각했습니다. *어쩌면 블랙잭 규칙을 제대로 모르는 것일 수도 있겠군요.. 수정*하였습니다."
|
|
149
|
+
|
|
150
|
+
→ *현실 비유 충실*(유저가 카드 계산 실수)과 *도메인 룰*(21점이면 Stay) 충돌. *도메인이 정확한 점수를 안다면* 자동 진입이 자연. PR #112와 같은 *현실 비유 vs 객체지향 자율성* 토론.
|
|
151
|
+
|
|
152
|
+
### 11. `Dealer.settleBettingMoneys(gameResult: GameResult): List<Proceeds>` — *수익률을 딜러가 계산*
|
|
153
|
+
|
|
154
|
+
```kotlin
|
|
155
|
+
class Dealer(...) : Participant(...) {
|
|
156
|
+
fun settleBettingMoneys(gameResult: GameResult): List<Proceeds> {
|
|
157
|
+
return gameResult.getResultPlayers().map { player ->
|
|
158
|
+
val payout = gameResult.getPlayerResult(player)?.let { ... } ?: 0
|
|
159
|
+
val playerBettingResultMoney = player.getBettingMoney() * payout.toInt()
|
|
160
|
+
Proceeds(player.getName(), playerBettingResultMoney)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
private fun settleBettingPayout(result: Result, isBlackJackState: Boolean): Float {
|
|
164
|
+
return when (result) {
|
|
165
|
+
Result.WIN -> if (isBlackJackState) 1.5f else 1f
|
|
166
|
+
Result.DRAW -> if (isBlackJackState) 1.5f else 1f // ⚠ DRAW도 1.5배?
|
|
167
|
+
Result.LOSE -> -1f
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
리뷰어: "1. *딜러가 게임결과를 의존해서 수익률을 계산*하는 것 2. *게임 결과를 통해 수익률을 판단*하는 것 같은 기능에 대해 *어떻게 의존성을 가지도록 하는게 적절*하다고 생각하시나요? *코드가 복잡하게 만들어졌기 때문에 책임과* ..."
|
|
174
|
+
|
|
175
|
+
→ *Dealer가 GameResult 의존*하면 *Dealer 역할 비대*. *수익률 계산*은 *베팅 + 결과* 별도 객체(`BetRecords` 같은). PR #135와 같은 결.
|
|
176
|
+
|
|
177
|
+
또 *DRAW도 1.5배* 룰은 *블랙잭 룰 위반*. DRAW는 *원금 반환*(0배 또는 push). 학생 *룰 오해*. 후속 단위 테스트 권고에 *왜 단위 테스트가 없는지* 지적.
|
|
178
|
+
|
|
179
|
+
### 12. `Dealer.settleBettingMoneys`에 대한 단위 테스트 부재
|
|
180
|
+
|
|
181
|
+
리뷰어: "*2단계의 핵심 기능입니다. 왜 단위 테스트를 작성하지 않았을까요?* 아마 *아래 테스트를 짜야 한다면, 머리가 아파지실 거*라고 생각이 듭니다. 😱 > *블랙잭 상태라면 수익률은 1.5배이다* / *스테이 상태는 수익률이 1배이다.* / *버스트 상태는 수익률이 0배이다.* / *히트 상태는 수익률 ?????*"
|
|
182
|
+
|
|
183
|
+
→ **테스트가 어려운 것 = 책임이 잘못 배치된 신호**. *Dealer가 모든 시나리오*(상태 × 결과)를 다 가지면 *조합 테스트 폭증*. *책임 분리*가 테스트 단순화 신호.
|
|
184
|
+
|
|
185
|
+
### 13. `UserInputValidator.makeParticipants` — *Validator가 Participants 생성*
|
|
186
|
+
|
|
187
|
+
```kotlin
|
|
188
|
+
object UserInputValidator {
|
|
189
|
+
fun makeParticipants(): Participants {
|
|
190
|
+
val dealer = Dealer()
|
|
191
|
+
val players = InputView.inputPlayers()
|
|
192
|
+
return Participants(dealer = dealer, players = players)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
리뷰어: "*여러번 같은 질문을 드리는 것 같은데, `UserInputValidator`와 `InputView` 역할이 섞이지 않았나요?* 단순히 *컨트롤러 코드가 길어지는 것을 피하려고 옮긴 것 같은데 저는 결론적으로 이 객체가 왜 필요한가 의문*이 드네요. 🤔" — *Validator*가 *입력 + 도메인 생성 + 검증* 셋. *역할 흡인기*. PR #63에서 받은 같은 지적이 *반복*. 학생이 *이름만 바꿔* 같은 객체를 유지.
|
|
198
|
+
|
|
199
|
+
또: "*플레이어의 이름을 잘못 정한다면, 오류가 발생하는 것은 View*이고 *입력을 잘못해서 참가자 생성에 실패하면 컨트롤러에서 발생*하고 있네요. *InputValidator라는 역할이 반쪽처럼 느껴지지 않을까요?*" — *검증 책임이 두 곳에 분산*.
|
|
200
|
+
|
|
201
|
+
### 14. `Dealer.openInitCards(): List<Card>` *비어있으면 오류* — Player와 일관성 없음
|
|
202
|
+
|
|
203
|
+
```kotlin
|
|
204
|
+
dealer.openInitCards()
|
|
205
|
+
.also { cards -> if (cards.isEmpty()) println(ERROR_CARD_INDEX) }
|
|
206
|
+
.forEach { firstCard -> OutputView.outputDealerCurrentHandCard(...) }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
리뷰어: "*딜러가 처음 공개하는 카드를 왜 한장씩 출력하는것일까요?* 또한 *비어있을 때 오류로 판단하는 것도 궁금*합니다. 1. *딜러는 비어있는게 오류인데 플레이어는 없기 때문에 일관성이 맞지 않습니다*. 2. *딜러도 참가자도 모두 처음 공개하는 카드들을 받는데, 로직을 분리할 필요가 있는까요?*" — *Dealer.openInitCards() = 1장 / Player.openInitCards() = 2장*인 *비즈니스 룰 차이*면 *공통 추상 메서드*면 충분. *비어있으면 오류*는 *호출 시점에 카드 분배 완료* invariant 보장 누락. PR #135와 같은 결.
|
|
210
|
+
|
|
211
|
+
### 15. `let` 범위 지정 함수 indent 증가
|
|
212
|
+
|
|
213
|
+
```kotlin
|
|
214
|
+
fun outputPlayerCurrentHandCard(player: Participant) {
|
|
215
|
+
player.openInitCards()?.let { playerInitCards ->
|
|
216
|
+
println(
|
|
217
|
+
OUTPUT_MESSAGE_PARTICIPANTS_CURRENT_HAND_CARD
|
|
218
|
+
.format(
|
|
219
|
+
player.getName(),
|
|
220
|
+
joinCardsInfo(playerInitCards),
|
|
221
|
+
),
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
리뷰어: "*let과 같은 범위 지정 함수는, 코드를 편하게 작성할 수 있지만 적절하게 사용하지 않으면 오히려 가독성을 해칠수도 있습니다.* 범위 지정 함수의 여러 레퍼런스를 찾아 보시고, *프로그래밍 요구사항의 indent를 늘리지 않도록 하는 것*을 지켜보도록 해보세요" — `let` 안에서 *3단계 indent*. *let의 가치 = null 처리 + 한 표현식*. *여러 라인 + 깊은 indent*면 *if let != null*이 더 명확.
|
|
228
|
+
|
|
229
|
+
### 16. `GameManager.draw(participant): Boolean` — *Boolean 반환의 의미 불명*
|
|
230
|
+
|
|
231
|
+
리뷰어: "*저는 왜 이 함수가 boolean을 반환하는게 계속 어색하게 느껴질까요?* 마치 *draw 함수에서만 오류가 발생할 수 있는 것 처럼*... 현재 구조에서는 *만약 GameManager에 문제가 발생해 false를 반환한다면 모든 플레이어가 갑자기 카드를 받지 않고 게임이 정상 종료되는 이상한 시나리오*가 되겠네요" — *Boolean이 무엇을 의미하는지* 함수명에 없음. *성공/실패 vs 카드를 더 받을 수 있는지 vs Bust 여부* 등 *호출자가 추측*. *명시적 결과 타입* 또는 *예외* 또는 *Optional*.
|
|
232
|
+
|
|
233
|
+
## 리뷰어 의견 요지
|
|
234
|
+
|
|
235
|
+
- ***호출 순서 invariant 책임 = Controller, main이 아님*** — *컨트롤러와 뷰 없이도 게임 진행 가능한가* 자가 점검.
|
|
236
|
+
- ***void 함수 시퀀스 + 멤버 필드 공유 = 사이드 이펙트 의존*** — *return 값 전달*.
|
|
237
|
+
- ***형식 규칙(3변수)이 만든 Wallet → UserInformation → 만능 이름 함정***.
|
|
238
|
+
- ***`Mutable balance`는 동적 변경 가능성 시나리오 없으면 과잉***.
|
|
239
|
+
- ***점수 계산 = Hand 단일 책임, BlackJack은 상태 결정만***.
|
|
240
|
+
- ***`private set` vs `backing property` 목적 차이***.
|
|
241
|
+
- ***`CardDeck(emptyList())`가 셔플 트리거 = 의도 ≠ 동작***.
|
|
242
|
+
- ***Ace 보정은 Hand 내부, 외부는 보정 후 점수***.
|
|
243
|
+
- ***DRAW에 1.5배 = 룰 오해***.
|
|
244
|
+
- ***테스트 어려움 = 책임 잘못 배치 신호***.
|
|
245
|
+
- ***`UserInputValidator`가 *입력 + 도메인 생성 + 검증* 셋 = 역할 흡인기***.
|
|
246
|
+
- ***Dealer 1장 / Player 2장 = 공통 추상 메서드의 다른 구현***.
|
|
247
|
+
- ***`let` 깊은 indent = 범위 지정 함수 오용***.
|
|
248
|
+
- ***`Boolean` 반환의 의미 불명*** — 함수명에 결과 의미.
|
|
249
|
+
|
|
250
|
+
## 대표 인용
|
|
251
|
+
|
|
252
|
+
> 컨트롤러는 도메인 로직의 상태를 판단하고, 그에 맞춰 함수를 작성하는 반면 *메인 클래스는 어떻게 해야 할까요?* [...] 결론적으로 *컨트롤러와 뷰 없이도 게임을 진행할 수 있는가?* 라는 목표를 예로 둘 수 있겠습니다.
|
|
253
|
+
> — @laco-dev on `Application.kt`
|
|
254
|
+
|
|
255
|
+
> 원래 함수란, 무언가를 반환하도록 설계되었습니다. *만약 아무것도 반환하지 않는다면 사이드 이펙트를 발생시킨다는 것을 의미*할 수 있으니까요.
|
|
256
|
+
> — @laco-dev on `BlackJackController.kt`
|
|
257
|
+
|
|
258
|
+
> 참가자가 이름을 가지지 않고, *지갑에 이름을 붙이는게 맞나요? 인스턴스 변수 3개 조건을 억지로 지키려고 만들어진 것 같은 느낌이 듭니다.*
|
|
259
|
+
> — @laco-dev on `Wallet.kt`
|
|
260
|
+
|
|
261
|
+
> Information이라는 이름은 *객체지향 설계에 굉장한 피곤함을 주는 이름*입니다. 왜냐하면 *만능*이거든요. *정보에는 모든게 다 들어갈 수 있*고 [...]
|
|
262
|
+
> — @laco-dev on `Dealer.kt` (`Wallet → UserInformation` 명명 변경 후 답변)
|
|
263
|
+
|
|
264
|
+
> 2단계의 핵심 기능입니다. *왜 단위 테스트를 작성하지 않았을까요?* 아마 *아래 테스트를 짜야 한다면, 머리가 아파지실 거*라고 생각이 듭니다. 😱
|
|
265
|
+
> — @laco-dev on `Dealer.kt` (`settleBettingMoneys`)
|
|
266
|
+
|
|
267
|
+
## 얻은 교훈
|
|
268
|
+
|
|
269
|
+
- ***호출 순서 invariant는 Controller의 책임*** — main은 *어떤 게임을 띄울지*만. *컨트롤러와 뷰 없이도 게임이 진행되는가*가 *책임 분리 자가 점검 질문*.
|
|
270
|
+
- ***void 함수 + 멤버 필드 공유 = 사이드 이펙트 의존*** — *return 값으로 다음 함수에 전달*하면 *데이터 흐름이 시그니처에 명시*.
|
|
271
|
+
- ***형식 규칙(3변수 제한)이 만든 Wallet은 인공 객체*** — PR #135 (ijh1298) `PlayerBetInfo`와 동일. *형식 규칙*은 *코드 단순화 도구*이지 *목적*이 아님.
|
|
272
|
+
- ***`Information` / `Manager` / `Util` 같은 *만능 명사*는 책임 흡인기*** — 모든 것이 들어갈 수 있으므로 *책임 경계 무너짐*. (STYLE_GUIDE §1-2 `vague-class-name` 룰과 같은 결.)
|
|
273
|
+
- ***`Mutable balance` + setter는 동적 변경 가능성 시나리오가 있을 때만*** — 게임 1회당 베팅 한 번이면 `val` + 생성 시 결정.
|
|
274
|
+
- ***점수 계산 = Hand 단일 책임*** — *BlackJack/Player에서 또 계산*하면 *테스트가 BlackJack 객체로만 가능*해져 난이도 ↑.
|
|
275
|
+
- ***`private set` ≠ `backing property`*** — `private set`은 *같은 프로퍼티의 setter만 차단*, `backing property`는 *외부 노출 타입을 좁힘*. 둘을 섞으면 의도 불명.
|
|
276
|
+
- ***`CardDeck(emptyList())`가 셔플 트리거 = 호출자 의도 ≠ 실제 동작*** — *no-arg = 셔플된 새 덱 / 명시 cards = 그대로*. 분기를 인자 값이 아닌 *생성자 다중 정의*로.
|
|
277
|
+
- ***Ace 보정은 Hand 내부*** — 외부에서 *Ace 여부*를 알 필요 없음. `hand.score()`만 노출.
|
|
278
|
+
- ***DRAW에 1.5배 = 블랙잭 룰 오해*** — *블랙잭 룰 충실히 읽기*. DRAW는 push (0배 또는 원금 반환).
|
|
279
|
+
- ***단위 테스트 작성이 머리 아프면 책임이 잘못 배치된 신호*** — *Dealer.settleBettingMoneys(상태 × 결과)* 조합 폭증 = 책임 분리 신호.
|
|
280
|
+
- ***`UserInputValidator`는 PR #63·#92 두 번 같은 지적*** — *이름 바꿔서 유지*는 안티패턴 회피 X. *역할 자체*가 InputView/도메인에 흡수되어야.
|
|
281
|
+
- ***Dealer 1장 / Player 2장 공개 = 공통 추상 메서드 + 다른 구현*** — *Dealer만 비어있으면 오류*는 invariant 누락. PR #135와 같은 결.
|
|
282
|
+
- ***`let` 안 깊은 indent = 범위 지정 함수 오용*** — `let의 가치 = null 처리 + 한 표현식*. 여러 라인이면 `if (x != null)`이 명확.
|
|
283
|
+
- ***`Boolean` 반환의 의미는 함수명에*** — *카드를 더 받을 수 있는지*, *오류 없이 진행됐는지*, *Bust인지* 호출자가 추측하면 위험.
|