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);
    }

}