[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("무승부");
		}
	}
}

Reference

Leave a comment