이번 Readme는 계산기 과제 할 때랑 포맷은 똑같다고 할 수 있는데 Level 별이 아닌 기능별 구현부로 나눠서 정리했다.
하지만 구현 의도는 둘째치고 구조를 파악하는데에는 크게 도움이 안될 것 같아서 순서도나 클래스 다이어그램 툴이라도 써서 적어볼까 했는데 영 납득할만한 구조를 짤 경험이 없어서 포기했다.
구현 기능이 딱 정해진 계산기랑 달리 야구 게임은 핵심 알고리즘이야 비슷하겠지만 구조를 짜는 부분에서 사람마다 워낙 달라질테니 튜터님의 객체지향적 숫자 야구 게임은 어떤지를 중점으로 봤다. 주로 원론적이지만 프로그램을 정의하는 순서를 아주 잘 설명해주셔서 그 프로세스대로 정리해봤다.
- 어떤 객체(등장인물)가 등장하면 좋은가?
- Main - 입력을 받을 것
- History - 게임 기록
- BaseballGame - 게임
- 어떻게 진행(대화)될 것인가?
- Main에서 사용자 입력을 무한루프로 받는다.
- 사용자가 게임을 하려고 하면 Main -> BaseballGame으로 요청을 보낸다.
- BaseballGame의 결과는 게임의 기록이고 Main은 이걸 History에 요청을 보낸다.
- 기록 조회시 Main은 History에 요청을 보낸다.
- 사용자가 종료 요청 보내면 무한루프를 탈출한다.
그 외에도 게임의 시나리오, 기록의 시나리오도 코드 말고 주석으로 먼저 작성하셨다.
튜터님과 차이점이라면:
비동기, Thread, Coroutine을 다루고 있던 5장은 과제에는 딱히 쓰지 않을테니 안듣고 있다가 오늘 과제 해설까지 다 듣고 마저 다 들었다.
사실 비동기의 개념은 실무에서도 아주 찔끔찔끔 써보기도 했고 사전캠프때 비동기만 따로 공부해서 발표까지 제대로 했을 정도인데 아무래도 진짜 쓸 때는 사용법 자체가 까다롭게 느껴질 때가 많았다.
그런데 개념도 이해할만 해지고 Coroutine도 실무때 갓 나온 기술이라 뭔 소린지 못알아먹겠던 때보다 훨씬 들을만 했고 꽤 수월하게 수강할 수 있었다.
(물론 실무에 적용할 노하우가 생긴 건 아니니 이럴 때 딱 써먹어야겠다 라는 감은 없다.)
오늘중으로 다음주부터 진행할 Spring 강의도 지급을 받아서 목차만 간략히 확인했다. 뭐라고 표현해야할지 모르겠는데 딱 모르겠다는 느낌으로 용어 자체가 앱 클라이언트 만지작거리던 내가 듣기엔 생소한 표현이 목차부터 많이 보였고 내가 API, GQL로 데이터 다룰 때 쓰던 것들을 제외하면 완전 새로 배우는 거니 내 멍청함이 돋보일까봐 걱정된다.
사실 1주차랑 겹치는 부분이 대부분이었지만 2주차에서는 새롭게 느껴지는 문제점이 있어 새로운 점만 추가로 적을 부분이 있었다.
Keep
Problem
Try
2주차는 1주차보다 어려웠던 만큼 팀원분들의 고생도 눈에 더 잘 보여서 내 아쉬움이 더 크게 적힌 KPT 회고가 된 것 같다. 튜터나 매니저로 팀에 들어온 건 아니니까 과제를 내주며 나대면 안된다는 선이 존재했었는데 사실 그러기보단 적극적으로 공부를 추진하는게 오히려 12시간을 힘들게 공부하시는 것보다 팀원으로서도 훨씬 도움이 됐을 거라고 생각한다.
오래전 유행했던 콜라 문제가 있습니다. 콜라 문제의 지문은 다음과 같습니다.
정답은 아무에게도 말하지 마세요.
콜라 빈 병 2개를 가져다주면 콜라 1병을 주는 마트가 있다. 빈 병 20개를 가져다주면 몇 병을 받을 수 있는가?
단, 보유 중인 빈 병이 2개 미만이면, 콜라를 받을 수 없다.
문제를 열심히 풀던 상빈이는 일반화된 콜라 문제를 생각했습니다. 이 문제는 빈 병 a
개를 가져다주면 콜라 b
병을 주는 마트가 있을 때, 빈 병 n
개를 가져다주면 몇 병을 받을 수 있는지 계산하는 문제입니다. 기존 콜라 문제와 마찬가지로, 보유 중인 빈 병이 a
개 미만이면, 추가적으로 빈 병을 받을 순 없습니다. 상빈이는 열심히 고심했지만, 일반화된 콜라 문제의 답을 찾을 수 없었습니다. 상빈이를 도와, 일반화된 콜라 문제를 해결하는 프로그램을 만들어 주세요.
콜라를 받기 위해 마트에 주어야 하는 병 수 a
, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 b
, 상빈이가 가지고 있는 빈 병의 개수 n
이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.
fun solution(a: Int, b: Int, n: Int): Int {
var answer: Int = 0
var calculatedColaCount = n
while (calculatedColaCount >= a) {
(calculatedColaCount / a * b).let {
answer += it
calculatedColaCount = it + (calculatedColaCount % a)
}
}
return answer
}
문제 자체는 조건만 잘 세우면 복잡한 시간복잡도 없이 풀 수 있게 매개변수가 잘 주어진 문제였다. 일단 작성하고 나서 아무리 그래도 최적화 할 방법이 있겠거니 다방면으로 생각해봤지만
어쨌든 짱구를 더 굴려봐도 답이 안나와서 제출하고 퍼포먼스상으론 정말 좋길래 문제 없다고 생각했는데 좋은 풀이가 있었다.
fun solution(a: Int, b: Int, n: Int): Int = (if (n > b) n - b else 0) / (a - b) * b
이게 순회 없이 풀 수 있는 문제였다니 놀랍다.
짱구를 굴려봤는데 일단 기본 예시의 a=3, b=1, n=20을 예로 들었을때
- n-b = 19
- 19 / (a-b) * b
- 19 / 2 * 1 = 9
결국 코드가 의미하는 연산의 의미에서
n-b 는 n중에서 실제로 교환 가능한 콜라의 갯수를 구하며
a-b는 콜라를 교환 받을 때 실제로 필요한 빈 병의 수 2병 을 의미하며
b는 교환시 교환비를 의미하니 (실제 계산가능 콜라) / (실제로 필요한 빈병 개수)를 해주고 마지막에 교환비를 곱해주면 받을 수 있는 콜라 양이 나온다.
이처럼 실제 교환 가능한 19병을 실제 필요 병 갯수와 교환비를 곱하는 수학적인 공식이 가능했다. a=3, b=2 처럼 바꿔보고 직접 풀어보느라 이해하는데 좀 걸리긴 했는데 많이 신기했다.