Skip to content

Commit

Permalink
refactor:
Browse files Browse the repository at this point in the history
- rename winning number form
- separate lotto calculate(processor) logics
- change winningnumbers type (from object to array)
- remove logics from Lotto object
  • Loading branch information
zigsong committed Feb 27, 2021
1 parent 23e8efa commit b140cd6
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 137 deletions.
48 changes: 22 additions & 26 deletions cypress/integration/lottoTest/lottoTest.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import {
getRandomNumber,
compareNumbers,
calculateEarningRate,
} from '../../../src/js/utils/utils.js';
import { getRandomNumber } from '../../../src/js/utils/utils.js';
import LottoProcessor from '../../../src/js/utils/lottoProcessor.js';
import Lotto from '../../../src/js/Lotto.js';

describe('로또 게임 테스트', () => {
Expand Down Expand Up @@ -33,19 +30,19 @@ describe('로또 게임 테스트', () => {
it('프로그램을 시작하면 구입금액 입력폼만 보인다.', () => {
cy.get('#input-price-form').should('be.visible');
cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
cy.get('#winning-numbers-form').should('not.be.visible');
});

it('사용자는 로또 구입 금액을 입력하면, 확인 버튼을 누르면 사용자가 구매한 로또와 지난 주 당첨 로또 입력폼이 보인다.', () => {
clickAfterTypePrice();
cy.get('#purchased-lottos').should('be.visible');
cy.get('#input-lotto-nums').should('be.visible');
cy.get('#winning-numbers-form').should('be.visible');
});

it('사용자는 로또 구입 금액을 입력하면, Enter를 누르면 사용자가 구매한 로또와 지난 주 당첨 로또 입력폼이 보인다.', () => {
cy.get('#input-price').type(`${price}{enter}`);
cy.get('#purchased-lottos').should('be.visible');
cy.get('#input-lotto-nums').should('be.visible');
cy.get('#winning-numbers-form').should('be.visible');
});

it('사용자가 구매한 로또의 개수와 개수 만큼의 로또 이모지를 보여준다.', () => {
Expand All @@ -56,7 +53,7 @@ describe('로또 게임 테스트', () => {
cy.get('#lotto-icons')
.children('.lotto-wrapper')
.should('have.length', lottoTotalCount);
cy.get('#input-lotto-nums').should('be.visible');
cy.get('#winning-numbers-form').should('be.visible');
});

it('번호 보기 스위치 off 상태에서는 로또 아이콘들이 가로로, on에서는 세로로 정렬된다.', () => {
Expand Down Expand Up @@ -115,42 +112,41 @@ describe('로또 게임 테스트', () => {
[27, 13, 39, 29, 35, 16], // 5등 (3개 일치)
];

const winningNumbers = { 1: 21, 2: 6, 3: 43, 4: 29, 5: 35, 6: 16, 7: 17 };
const winningNumbers = [21, 6, 43, 29, 35, 16, 17];

it('로또 당첨 결과를 올바르게 계산한다.', () => {
const lottos = [];
const rankings = [1, 2, Infinity, Infinity, 5, 5];
const rankCounts = [1, 1, 0, 0, 2];

lottoNumsArr.forEach(lottoNums => {
const lotto = new Lotto();
lotto.numbers = new Set(lottoNums);
lotto.inputManualNumbers(new Set(lottoNums));
lottos.push(lotto);
});

compareNumbers(lottos, winningNumbers);
lottos.forEach(lotto => lotto.updateRank());
lottos.forEach((lotto, idx) => {
expect(lotto.rank).to.be.equal(rankings[idx]);
});
const lottoProcessor = new LottoProcessor(lottos, winningNumbers);
lottoProcessor.checkMatchingNums();

expect(lottoProcessor.rankCounts).to.deep.equal(rankCounts);
});

it('수익률을 올바르게 계산한다.', () => {
const lottos = [];
const rankingCount = [1, 1, 0, 0, 2];
const sum = 2030010000;
const purchasedPrice = 6000;
const earningRate = (sum / purchasedPrice - 1) * 100;

lottoNumsArr.forEach(lottoNums => {
const lotto = new Lotto();
lotto.numbers = new Set(lottoNums);
lotto.inputManualNumbers(new Set(lottoNums));
lottos.push(lotto);
});

compareNumbers(lottos, winningNumbers);
lottos.forEach(lotto => lotto.updateRank());
const sum = 2030010000;
const purchasedPrice = 6000;
const earningRate = (sum / purchasedPrice - 1) * 100;
const lottoProcessor = new LottoProcessor(lottos, winningNumbers);
lottoProcessor.checkMatchingNums();
lottoProcessor.calculateEarningRate(purchasedPrice);

expect(calculateEarningRate(rankingCount, 6000)).to.be.equal(earningRate);
expect(lottoProcessor.earningRate).to.be.equal(earningRate);
});

it('다시 시작하기 버튼을 누르면 초기화 되서 다시 구매를 시작할 수 있다.', () => {
Expand All @@ -167,7 +163,7 @@ describe('로또 게임 테스트', () => {
cy.get('#input-price').should('have.value', '');

cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
cy.get('#winning-numbers-form').should('not.be.visible');
cy.get('.winning-number').each(winningNumber => {
cy.wrap(winningNumber).should('have.value', '');
});
Expand Down
6 changes: 3 additions & 3 deletions cypress/integration/lottoTest/lottoValidation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,20 @@ describe('로또 금액 입력 예외 처리 테스트', () => {
checkInvalid(200, '값은 1000 이상이어야 합니다.');

cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
cy.get('#winning-numbers-form').should('not.be.visible');
});

it('로또 구입 금액은 최대 100,000원으로 제한한다.', () => {
checkInvalid(120000, '값은 100000 이하여야 합니다.');

cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
cy.get('#winning-numbers-form').should('not.be.visible');
});

it('로또 구입 금액은 1,000원 단위여야 한다.', () => {
exceptionAlert(1200, '로또 구입 금액을 1,000원 단위로 입력해 주세요.');
cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
cy.get('#winning-numbers-form').should('not.be.visible');
});

it('로또 당첨 번호에는 중복된 숫자를 입력할 수 없다.', () => {
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ <h1 class="text-center">🎱 행운의 로또</h1>
<ul id="lotto-icons" class="d-flex flex-wrap"></ul>
</section>

<form class="mt-9" id="input-lotto-nums">
<form class="mt-9" id="winning-numbers-form">
<label class="flex-auto d-inline-block mb-3"
>지난 주 당첨번호 6개와 보너스 넘버 1개를 입력해주세요.</label
>
Expand Down
44 changes: 4 additions & 40 deletions src/js/Lotto.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ export default class Lotto {

constructor() {
this._numbers = new Set();
this.matchingNumbers = 0;
this.isMatchBonus = false;
this._rank = Infinity;

this.initNumbers();
}

Expand All @@ -18,47 +14,15 @@ export default class Lotto {
}
}

inputManualNumbers(numbers) {
this._numbers = new Set(numbers);
}

get numbers() {
return this._numbers;
}

get numberDetail() {
return [...this._numbers.values()].join(', ');
}

get rank() {
return this._rank;
}

// Test를 위한 setter 생성
set numbers(numsArray) {
this._numbers = numsArray;
}

addMatchNumbers() {
this.matchingNumbers++;
}

setMatchBonus() {
this.isMatchBonus = true;
}

updateRank() {
switch (this.matchingNumbers) {
case 6:
this._rank = 1;
break;
case 5:
this._rank = this.isMatchBonus ? 2 : 3;
break;
case 4:
this._rank = 4;
break;
case 3:
this._rank = 5;
break;
default:
this._rank = Infinity;
}
}
}
22 changes: 9 additions & 13 deletions src/js/LottoController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import {
isUniqueWinningNumber,
} from './utils/lottoValidation.js';
import { $ } from './utils/dom.js';
import {
compareNumbers,
calculateEarningRate,
countByRank,
} from './utils/utils.js';
import LottoProcessor from './utils/lottoProcessor.js';

import WinningResultView from './views/WinningResultView.js';
import InputPriceView from './views/InputPriceView.js';
Expand All @@ -20,7 +16,7 @@ export default class LottoController {
constructor() {
this.inputPriceView = new InputPriceView($('#input-price-form'));
this.purchasedLottosView = new PurchasedLottosView($('#purchased-lottos'));
this.winningResultView = new WinningResultView($('#input-lotto-nums'));
this.winningResultView = new WinningResultView($('#winning-numbers-form'));
}

init() {
Expand All @@ -31,7 +27,6 @@ export default class LottoController {
reset() {
this.lottos = [];
this.purchasedPrice = 0;
this.rankCounts = Array(5).fill(0);
this.isResultCalculated = false;

this.inputPriceView.show().resetInputPrice();
Expand Down Expand Up @@ -71,21 +66,22 @@ export default class LottoController {
}

inputNumbersHandler(winningNumbers) {
console.log(winningNumbers);
if (!isUniqueWinningNumber(winningNumbers)) {
alert(ALERT_MESSAGES.DUPLICATE_NUMS);
return;
}

const lottoProcessor = new LottoProcessor(this.lottos, winningNumbers);
if (!this.isResultCalculated) {
compareNumbers(this.lottos, winningNumbers);
this.lottos.forEach(lotto => lotto.updateRank());
countByRank(this.lottos, this.rankCounts);
lottoProcessor.checkMatchingNums();
lottoProcessor.calculateEarningRate(this.purchasedPrice);
this.isResultCalculated = true;
}
this.isResultCalculated = true;

this.winningResultView.showModal(
this.rankCounts,
calculateEarningRate(this.rankCounts, this.purchasedPrice)
lottoProcessor.rankCounts,
lottoProcessor.earningRate
);
}
}
51 changes: 51 additions & 0 deletions src/js/utils/lottoProcessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { LOTTO_NUMBERS, LOTTO_WINNING_PRICE } from './constants.js';

export default class LottoProcessor {
constructor(lottos, winningNumbers) {
this.lottos = lottos;
this.winningNumbers = winningNumbers.slice(
0,
LOTTO_NUMBERS.WINNING_NUMBER_COUNT - 1
);
this.bonusNumber = winningNumbers[LOTTO_NUMBERS.WINNING_NUMBER_COUNT - 1];
this.rankCounts = Array(5).fill(0);
this.earningRate = 0;
}

checkMatchingNums() {
this.lottos.forEach(lotto => {
const matchNumbers = [...lotto.numbers].filter(number =>
this.winningNumbers.includes(number)
);
const isMatchBonus = lotto.numbers.has(this.bonusNumber);
this.updateRankCounts(matchNumbers.length, isMatchBonus);
});
}

updateRankCounts(matchCount, isMatchBonus) {
switch (matchCount) {
case 6:
this.rankCounts[0]++; // 1등
break;
case 5:
isMatchBonus ? this.rankCounts[1]++ : this.rankCounts[2]++; // 2등 or 3등
break;
case 4:
this.rankCounts[3]++; // 4등
break;
case 3:
this.rankCounts[4]++; // 5등
break;
default:
this.rankCounts;
}
}

calculateEarningRate(purchasedPrice) {
const totalProfit = this.rankCounts.reduce((sum, rankCount, idx) => {
return sum + rankCount * LOTTO_WINNING_PRICE[idx + 1];
}, 0);

this.earningRate = (totalProfit / purchasedPrice - 1) * 100;
}
}
3 changes: 1 addition & 2 deletions src/js/utils/lottoValidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ export const isCorrectPurchaseUnit = input => {
};

export const isUniqueWinningNumber = input => {
const uniqueNums = new Set(Object.values(input));
return uniqueNums.size === LOTTO_NUMBERS.WINNING_NUMBER_COUNT;
return new Set(input).size === LOTTO_NUMBERS.WINNING_NUMBER_COUNT;
};
45 changes: 1 addition & 44 deletions src/js/utils/utils.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,5 @@
import { LOTTO_NUMBERS, LOTTO_WINNING_PRICE } from './constants.js';
import { LOTTO_NUMBERS } from './constants.js';

export function getRandomNumber() {
return Math.floor(Math.random() * LOTTO_NUMBERS.LOTTO_MAX_NUM) + 1;
}

export function compareNumbers(lottos, winningNumbers) {
checkMatchingNums(lottos, winningNumbers);
checkBonus(lottos, winningNumbers);
}

function checkMatchingNums(lottos, winningNumbers) {
let i = 0;
while (i++ < 6) {
const currNum = winningNumbers[i];
lottos.forEach(lotto => {
if (lotto.numbers.has(currNum)) {
lotto.addMatchNumbers();
}
});
}
}

function checkBonus(lottos, winningNumbers) {
const bonusNumber = winningNumbers[7];

lottos.forEach(lotto => {
if (lotto.numbers.has(bonusNumber)) {
lotto.setMatchBonus();
}
});
}

export function countByRank(lottos, rankCounts) {
lottos.forEach(lotto => {
if (lotto.rank !== Infinity) {
rankCounts[lotto.rank - 1] += 1;
}
});
}

export function calculateEarningRate(rankCounts, purchasedPrice) {
const totalProfit = rankCounts.reduce((sum, rankCount, idx) => {
return sum + rankCount * LOTTO_WINNING_PRICE[idx + 1];
}, 0);

return (totalProfit / purchasedPrice - 1) * 100;
}
Loading

0 comments on commit b140cd6

Please sign in to comment.