Backend/Spring & JPA
[Spring] 220729 7차 과제 : 로또 번호 배분/추첨/당첨자 발표 시스템 🎰
JOKUN
2022. 8. 1. 22:26
특수한 규칙을 가진 로또 시스템🎰
📑문제
https://cafe.naver.com/eddicorp/875
Collections 문제 [ 1 ]
굉장히 특수한 규칙을 가진 로또 시스템을 만들어봅시다. 로또 번호는 총 6가지로 각각의 숫자를 랜덤으로 생성해줍니다. 추가적으로 사용자에게 이름(별명)을 부여해주도록 합니다....
cafe.naver.com
🔍풀이
com.example.demo.controller.basic.seventh
SeventhLottoController
package com.example.demo.controller.basic.seventh;
import com.example.demo.entity.basic.seventh.LottoCardManager;
import com.example.demo.entity.basic.seventh.Player;
import com.example.demo.entity.basic.seventh.WinnerManager;
import com.example.demo.utillity.basic.seventh.Score;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/seventh")
public class SeventhLottoController {
private List<Player> players;
private LottoCardManager lottoManager;
private final int MAX_PLAYER = 100;
private Score scoreManager;
private WinnerManager winnerManager;
@GetMapping("/lotto-game")
public String lottoGame() {
log.info("lottoGame()");
allocPlayer();
lottoManager = new LottoCardManager(players.size());
//lottoManager에 랜덤한 숫자 넣기
lottoManager.allocLottoCardNumber();
// 플레이어 수 만큼 i lottoManager에 저장한 인덱스 값 card로 저장
for (int i = 0; i < players.size(); i++) {
players.get(i).acquireLottoCard(lottoManager, i);
}
//scoreManager = new ScoreManager(players.size());
//scoreManager.calcScore(lottoManager);
winnerManager = new WinnerManager();
// player리스트 넣어서 위너 Map으로 정렬
List winner = winnerManager.sortWinner(players);
//winner, 우승상금 발표
winnerManager.doReward(winner);
return "승자 선출이 완료되었습니다!";
}
/**
* MAX_PLAYER 수 만큼 ArrayList에 플레이어 생성
*/
private void allocPlayer() {
players = new ArrayList<>();
for (int i = 0; i < MAX_PLAYER; i++) {
players.add(new Player());
}
}
}
com.example.demo.entity.basic.seventh
LottoCard
package com.example.demo.entity.basic.seventh;
import com.example.demo.utillity.basic.third.CustomRandom;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class LottoCard {
private int[] numbers;
private final int LOTTO_NUMBER_LENGTH = 6;
private final int BIAS = 1;
private final int MIN = 0;
private final int MAX = 99 + BIAS;
public LottoCard() {
numbers = new int[LOTTO_NUMBER_LENGTH];
}
public int generateLottoNumber(int curIdx) {
int tmpNum = CustomRandom.makeIntCustomRandom(MIN, MAX);
numbers[curIdx] = tmpNum;
return tmpNum;
}
}
LottoCardManager
package com.example.demo.entity.basic.seventh;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@Getter
public class LottoCardManager {
private List<LottoCard> cards;
private final int LOTTO_CARD_LENGTH = 6;
private final int DUPLICATE_LIMITATION = 100;
/**
* cards ArrayList에 플레이어 수 만큼 로또 번호 여러개를 가진 int형 배열 추가
* @param playerNum
*/
public LottoCardManager(int playerNum) {
cards = new ArrayList<>(playerNum);
for (int i = 0; i < playerNum; i++) {
cards.add(new LottoCard());
}
}
/**
* 난수를 저장하는 메서드
*/
public void allocLottoCardNumber() {
int tmpNum;
int people = cards.size();
//로또 카드 길이만큼 (6)
for (int j = 0; j < LOTTO_CARD_LENGTH; j++) {
// 플레이어 수 만큼 (100)
for (int i = 0; i < people; i++) {
// 플레이어 수가 100을 넘으면 실행
if (people > DUPLICATE_LIMITATION) { cards.get(i).generateLottoNumber(j); }
else { // 100 아래면 실행
do {
// tmpNum은 카드 i번째 인덱스에 배열 number j번째에 랜덤한 값
tmpNum = cards.get(i).generateLottoNumber(j);
} while (verifyDuplicateLottoCard(i, j, cards));
}
}
}
}
public void allocNonDuplicateLottoCardNumber() {
int tmpNum;
for (int j = 0; j < LOTTO_CARD_LENGTH; j++) {
for (int i = 0; i < cards.size(); i++) {
do {
tmpNum = cards.get(i).generateLottoNumber(j);
} while (verifyDuplicateLottoCard(i, j, cards));
}
}
}
/**
* 같은 위치에 같은 값이 올 수 없는 중복을 걸러내는 메서드
* @param curPersonIdx 플레이어 수
* @param curLottoColumnIdx
* @param cards
* @return
*/
private Boolean verifyDuplicateLottoCard(
int curPersonIdx, int curLottoColumnIdx, List<LottoCard> cards) {
if (curPersonIdx == 0) { return false; }
int compareTarget = cards.get(curPersonIdx).getNumbers()[curLottoColumnIdx];
for (int i = 0; i < curPersonIdx; i++) {
int eachNumber = cards.get(i).getNumbers()[curLottoColumnIdx];
System.out.printf("curPersonIdx: %d, compareTarget: %d, eachNumber: %d\n",
curPersonIdx, compareTarget, eachNumber);
if (eachNumber == compareTarget) {
return true;
}
}
return false;
}
public void allocDuplicateLottoCardNumber() {
int tmpNum;
for (int j = 0; j < LOTTO_CARD_LENGTH; j++) {
for (int i = 0; i < cards.size(); i++) {
cards.get(i).generateLottoNumber(j);
}
}
}
}
Player
package com.example.demo.entity.basic.seventh;
import com.example.demo.utillity.basic.seventh.NicknameGenerator;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class Player {
private LottoCard card;
private String nickName;
/**
* 생성자가 쓰이면 닉네임을 만들어주는 메서드를 불러와 닉네임을 생성시킴
*/
public Player() {
nickName = NicknameGenerator.generateRandomNickname();
}
public void acquireLottoCard(LottoCardManager manager, int idx) {
card = manager.getCards().get(idx);
}
}
WinnerManager
package com.example.demo.entity.basic.seventh;
import com.example.demo.utillity.basic.seventh.Score;
import lombok.Getter;
import lombok.ToString;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Getter
@ToString
public class WinnerManager {
private Map<Player, Integer> winnerScoreMap;
public WinnerManager() {
winnerScoreMap = new HashMap<>();
}
/**
* Winner 정렬해주는 메서드
* @param players
* @return
*/
public List sortWinner(List<Player> players) {
Score.calcPlayersScore(players);
// key = 플레이어 닉네임, value = 연산된 값
for (int i = 0; i < players.size(); i++) {
winnerScoreMap.put(players.get(i), Score.getScore(i));
}
// Map담긴 위너 정렬
List<Map.Entry<Player, Integer>> winner = winnerScoreMap.entrySet().stream().sorted(Map.Entry.comparingByValue())
.collect(Collectors.toList());
System.out.println(winner);
return winner;
}
/**
* 최고점을 가진 동점자가 있는지 구분하고 상금을 배분하는 메서드
* @param winner
*/
public void doReward(List winner) {
Map.Entry<Player, Integer> first = (Map.Entry<Player, Integer>) winner.get(winner.size() - 1);
int top = first.getValue();
int cnt = 0;
for (int i = winner.size() - 2; i >= 0; i--) {
if (top == ((Map.Entry<Player, Integer>) winner.get(i)).getValue()) {
cnt++;
}
else {
System.out.println("단일 우승 - 승자명: " + first.getKey().getNickName());
return;
}
}
BigInteger reward = new BigInteger("10000000000");
// 동점자 카운트해서 나누기
reward.divide(BigInteger.valueOf(cnt)).toString();
System.out.println("reward: " + reward);
// 승리한 사람 닉네임과 점수 보기
for (int i = winner.size() - cnt - 1; i < winner.size(); i++) {
System.out.println("승자명: " + ((Map.Entry<Player, Integer>) winner.get(i)).getKey().getNickName());
}
}
}
com.example.demo.utillity.basic.seventh
NicknameGenerator
package com.example.demo.utillity.basic.seventh;
import com.example.demo.utillity.basic.third.CustomRandom;
import java.util.ArrayList;
import java.util.List;
public class NicknameGenerator {
private static final int UPPER_LOWER_MIN = 0;
private static final int UPPER_LOWER_MAX = 2;
private static final int NICKNAME_MIN = 5;
private static final int NICKNAME_MAX = 10;
private static final int ALPHABET_LENGTH = 26;
private static final int UPPER_CHAR_START = 65;
private static final int UPPER_CHAR_END = UPPER_CHAR_START + ALPHABET_LENGTH;
private static final int LOWER_CHAR_START = 97;
private static final int LOWER_CHAR_END = LOWER_CHAR_START + ALPHABET_LENGTH;
private static final int UPPER_LOWER_DICISION_FACTOR = 2;
private static final int LOWERCASE = 1;
private static final int UPPERCASE = 0;
private static List<String> nickNames = new ArrayList<>();
public static String generateRandomNickname() {
String tmpNickname;
int nickNameLength = CustomRandom.makeIntCustomRandom(
NICKNAME_MIN, NICKNAME_MAX);
do {
tmpNickname = generateCustomLengthRandomNickname(nickNameLength);
} while(verifyNickname(tmpNickname));
nickNames.add(tmpNickname);
return tmpNickname;
}
public static Boolean verifyNickname(String nickname) {
if (nickNames.size() == 0) { return false; }
for (int i = 0; i < nickNames.size(); i++) {
if (nickNames.get(i).equals(nickname)) {
return true;
}
}
return false;
}
public static String generateCustomLengthRandomNickname(int nickNameLength) {
String tmpNickname = "";
char singleChar = 0;
int upperLowerDecision;
for (int i = 0; i < nickNameLength; i++) {
upperLowerDecision = CustomRandom.makeIntCustomRandom(
UPPER_LOWER_MIN, UPPER_LOWER_MAX);
if (upperLowerDecision % UPPER_LOWER_DICISION_FACTOR == UPPERCASE) {
singleChar = (char) CustomRandom.makeIntCustomRandom(
UPPER_CHAR_START, UPPER_CHAR_END);
} else if (upperLowerDecision % UPPER_LOWER_DICISION_FACTOR == LOWERCASE) {
singleChar = (char) CustomRandom.makeIntCustomRandom(
LOWER_CHAR_START, LOWER_CHAR_END);
}
tmpNickname += singleChar;
}
return tmpNickname;
}
}
Score
package com.example.demo.utillity.basic.seventh;
import com.example.demo.entity.basic.seventh.LottoCard;
import com.example.demo.entity.basic.seventh.Player;
import java.util.ArrayList;
import java.util.List;
public class Score {
private static List<Integer> score = new ArrayList<>();
private static int currentAlloc = 0;
/**
* 배열에 담긴 숫자 연산해주는 메서드
* @param players [ (숫자1 + 숫자2 + 숫자3 + 숫자4) * 숫자5 ] / 숫자6
*/
public static void calcPlayersScore(List<Player> players) {
for (int i = 0; i < players.size(); i++) {
LottoCard card = players.get(i).getCard();
int[] numbers = card.getNumbers();
if (numbers[5] == 0) {
score.add(0);
} else {
score.add((numbers[0] + numbers[1] + numbers[2] + numbers[3]) *
numbers[4] / numbers[5]);
}
currentAlloc++;
}
}
/**
* 인덱스 번호를 받으면 해당 인덱스 번호에 있는 score 불러오는 메서드
* @param idx
* @return
*/
public static int getScore(int idx) {
return score.get(idx);
}
}