카카오 신입 공채 1차 코딩 테스트에 있는 알고리즘 문제를 풀어봅니다.
다트 게임(난이도: 하) [상편 - 필수 문자열에 해당하는 객체 생성]
상편
“점수|보너스|[옵션]”으로 이루어진 문자열 3세트. 이므로,
"1S","1D","1T"와 같은 "점수|보너스"는 반드시 존재합니다.
점수객체, 보너스객체, 점수객체+보너스객체(Object Compoistion[조합 객체])를 만들어 역할을 담당하게 합니다.
1. 다트 포인트 객체 생성 ("2S","2D","2T") - 앞쪽 숫자
알고리즘 규칙 2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.
먼저 테스트 코드를 만들어봅니다. (10점이지만 20점 까지로 해보았습니다.)
package kakao.dart;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
public class BasicPointTest {
@Test
public void 포인트_제한_0에서_20() {
for (int i = 0; i < 20; i++) {
new PointNumber(String.valueOf(i));
}
}
@Test (expected = IllegalArgumentException.class)
public void 포인트_최대값_초과_21() {
new PointNumber("21");
}
}
해당 조건에 부합하는 객체를 만듭니다.
package kakao.dart;
public class PointNumber {
private static final Long MIN_NUMBER = 0l;
private static final Long MAX_NUMBER = 20l;
private Long number;
public PointNumber(String numeric) {
if (numeric == null) throw new IllegalArgumentException();
Long number = Long.valueOf(numeric);
if (outOfNumber(number)) throw new IllegalArgumentException();
this.number = number;
}
private boolean outOfNumber(Long number) {
return number < MIN_NUMBER || MAX_NUMBER < number;
}
public long toLong() {
return number;
}
}
기본 점수 객체를 만들어 놓으면, 이후에 객체 사용시 validation check(null, invalid value)에 대한 부담을 줄일 수 있습니다.
다트 게임은 0~20까지의 점수를 기준으로 했습니다. (bull (Single bull, Double bull)은 제외했습니다.)
outOfNumber() : 생성시 핵심 로직으로 작동합니다.
2. 다트 보너스 객체 생성 ("2S","2D","2T") - 뒷쪽 문자
알고리즘 규칙 3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수^1 , 점수^2 , 점수^3 )으로 계산된다.
@Test
public void 보너스_계산() {
assertThat(2l, is(Bonus.SINGLE.calculate(2)));
assertThat(4l, is(Bonus.DOUBLE.calculate(2)));
assertThat(8l, is(Bonus.TRIPLE.calculate(2)));
}
계산을 했을경우 왼쪽의 값과 같도록 테스트코드를 만들었습니다.
package kakao.dart;
import java.util.Arrays;
import java.util.function.Function;
public enum Bonus {
SINGLE("S", value -> value),
DOUBLE("D", value -> (long) Math.pow(value, 2)),
TRIPLE("T", value -> (long) Math.pow(value, 3));
private String shortName;
private Function<Long, Long> expression;
Bonus(String shortName, Function<Long, Long> expression) {
this.shortName = shortName;
this.expression = expression;
}
public long calculate(long value) {return expression.apply(value);}
public static Bonus getByShortName(String shortName) {
return Arrays.asList(Bonus.values()).stream()
.filter(bonus -> bonus.shortName.equals(shortName))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
java8에서 개발했기 때문에 Function<Long, Long>이 가능케 되는데요.
자세한 내용은 우아한 형제의 이동욱님께서 작성한 Java Enum 활용기를 참고하세요~
java 7에서 하는 방법도 나와있답니다 :)
calculate() : 핵심로직으로 제곱 연산을 담당합니다.
3. 조합 객체 만들기
“점수|보너스|[옵션]”으로 이루어진 문자열
3세트.알고리즘 규칙 8. Single(S), Double(D), Triple(T)은 점수마다 하나씩 존재한다.
다트 포인트와 보너스는 항상 붙어 다니므로, 1개의 객체로 취급합니다.
@Test (expected = IllegalArgumentException.class)
public void 포인트_보너스_부재() {
new BasicPoint("1");
}
@Test
public void 포인트_계산() {
assertThat(2L, is(new BasicPoint("2S").calculate()));
assertThat(4L, is(new BasicPoint("2D").calculate()));
assertThat(8L, is(new BasicPoint("2T").calculate()));
}
package kakao.dart;
import java.util.Optional;
public class BasicPoint {
private static final String POINT_MATCH = "[^\\d]{1,2}";
private PointNumber pointNumber;
private Bonus bonus;
public BasicPoint(String text) {
if (text == null || text.isEmpty()) throw new IllegalStateException();
pointNumber = matchPoint(text);
bonus = matchArea(text);
}
private PointNumber matchPoint(String text) {
return new PointNumber(Optional.of(text.split(POINT_MATCH)).orElseThrow(IllegalArgumentException::new)[0]);
}
private Bonus matchArea(String text) {
return Bonus.getByShortName(text.substring(text.length()-1));
}
public Long calculate() {
return bonus.calculate(pointNumber.toLong());
}
}
optional.of()는 단순히 if문을 줄이기 위해 사용하였습니다.
matchPoint, matchArea 매쏘드 에서 의도한 값이 들어오지 않으면 IllegalStateException을 던지도록 하였습니다.
이렇게 해서 다트 게임의 필수 값을 구현했습니다.
객체를 객체답게 사용하기위해
규칙 1: 한 메서드에 오직 한 단계의 들여쓰기만 한다.
규칙 2: else 예약어를 쓰지 않는다.
규칙 3: 모든 원시값과 문자열을 포장한다.
규칙 6: 모든 엔티티를 작게 유지한다.
규칙 7: 2개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
규칙 8: 일급 콜렉션을 쓴다.
규칙 9: 게터/세터/프로퍼티를 쓰지 않는다.
'프로그래밍 > 알고리즘' 카테고리의 다른 글
캐시(난이도: 하) [하편] (0) | 2018.02.23 |
---|---|
캐시(난이도: 하) [상편] (0) | 2018.02.22 |
다트 게임(난이도: 하) [하편] (0) | 2018.02.14 |
비밀 지도(난이도: 하) JAVA (0) | 2018.02.14 |