[java] 주사위 게임 객체지향으로 개발
🦥 요건 정의
- 2인 이상에 게임을 한다.
- 게이머가 주사위를 3번 던져 나온 수를 합한다.
- 10이하이면, 1번 더 던져 나온 수를 합해준다.
- 이번엔 상대방이 주사위를 3번 던져 나온 수를 합한다.
- 동일하게 10이하이면 1번 더 던져 나온 수를 합한다.
- 15에 가장 가까운 사람이 승리한다.
- 동점이 나온 경우, 1등이 나올때까지 다시 던진다.
-
console 로 결과를 출력한다.
- 먼저 주사위 객체를 정의한다.
- enum 을 통해 싱글톤 객체로 만들었다.
- 랜덤수 생성시, jdk7 부터는 ThreadLocalRandom 을 사용하는것이 좋습니다.
/**
* 주사위 객체
*
*/
public enum Dice {
INSTANCE;
private static int MAX_NUM = 6;
private static int MIN_NUM = 1;
public int drawOneDiceNumber() {
return ThreadLocalRandom.current().nextInt(MIN_NUM, MAX_NUM+1);
}
}
- 유저 객체를 정의한다.
public class User {
private String id;
private String name;
private int score;
List<Integer> scores = new ArrayList<>();
public User(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
//주사위를 던질때마다 점수를 더한다.
public void addScore(int score) {
scores.add(score);
this.score += score;
}
//목표 점수를 계산한다.
public int diffScore(int number) {
return Math.abs(this.score - number);
}
//쌓인 점수 이력을 저장
public List<Integer> getScores(){
return this.scores;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", score=" + score + "]";
}
}
- 주사위게임 객체를 정의한다.
- 유저그룹과 게임룰을 변수로 갖는다.
public class DiceGame implements Game<User>{
private final DiceRule rule;
private final List<User> users;
public DiceGame(DiceRule rule, List<User> users) {
this.rule = rule;
this.users = users;
}
@Override
public void play() {
this.rule.process(users);
}
}
// 게임 인터페이스
public interface Game<T> {
void play();
}
- 다음은 게임 룰을 정의한다.
- 템플릿메소드 패턴을 이용하여, 자식클래스에서 추가 되는 룰을 정의한다.
public abstract class DiceRule{
protected static int MIN_SCORE = 10; //최저 점수
protected static int BOUNCE_SCORE = 15; //목표 점수
protected static int DEFAULT_COUNT = 3; //기본 횟수
Dice dice = Dice.INSTANCE; //주사위
//사용자가 주사위를 1번 던진다.
protected User draw(User user) {
user.addScore(dice.drawOneDiceNumber());
return user;
}
//사용자 그룹이 주사위를 1번씩 던진다.
protected void draw(List<User> users) {
users.stream().forEach((u) ->{
draw(u);
});
}
//사용자 그룹을 조회하여, 10이하인 경우, 1번씩 더 던진다.
protected void oneMore(List<User> users) {
while(true) {
if(users.stream().filter(u -> u.getScore() <= MIN_SCORE).map(u->draw(u)).count()==0) break;
}
}
//동점자 존재 유무를 리턴한다.
protected boolean retry(List<User> users){
int min = Integer.MAX_VALUE;
for(User user: users) {
int result = user.diffScore(BOUNCE_SCORE);
if(min == result) return true;
if(min > result) min = result;
}
return false;
}
//우승자를 찾는다.
protected User decideWinner(List<User> users) {
int min = Integer.MAX_VALUE;
User winnerUser = null;
for(User user: users) {
int result = user.diffScore(BOUNCE_SCORE);
if(min > result) {
min = result;
winnerUser = user;
}else if(min == result) {
throw new IllegalStateException("동일한 점수입니다.");
}
}
return winnerUser;
}
/**
* 게임을 진행한다.
* @param users
*/
public void process(List<User> users) {
List<User> result = new ArrayList<>(users);
for (int i = 0; i < DEFAULT_COUNT; i++) {
draw(result);
}
oneMore(result);
addProcess(result); // 추가 룰 구현
printResult(result);
}
private void printResult(List<User> result) {
for(User user : result) {
System.out.println(user.getId() + " - "+ user.getScores());
}
System.out.println(result);
System.out.println(decideWinner(result));
}
//추가적인 룰은 아래 메서드를 구현한다. (템플릿 패턴)
public abstract void addProcess(List<User> users);
}
- DiceRuleVer2를 통해 동점자가 있는 경우, 주사위를 한번씩 더 던지는 룰을 추가
public class DiceRuleVer2 extends DiceRule {
@Override
public void addProcess(List<User> users) {
while(true) { if(!retry(users)) break; draw(users); }
}
}
- 게임 실행
public class App {
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("11","sk"),new User("12","uo"), new User("13","kk") );
DiceGame game = new DiceGame(new DiceRuleVer2() , users);
try {
game.play();
}catch(IllegalStateException e) {
System.out.println("무승부");
}
}
}
Leave a comment