Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# javascript-baseball-precourse
# javascript-baseball-precourse

기능 요구 사항
1. 랜덤 수 생성 : 1부터 9까지 서로 다른 임의의 3자리 수를 생성한다.
2. 사용자 입력 받기: 입력된 수가 3자리이고 각 자리가 중복되지 않는지 확인한다.
3. 게임 진행 : 정답과 입력된 숫자를 비교하여 스트라이크와 볼을 판단하고 결과를 표시한다.
4. 게임 종료 : 결과가 3 스트라이크인 경우 게임이 종료되고 재시작 버튼을 표시한다.
105 changes: 105 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
body {
font-family: "Nanum Gothic", sans-serif;
font-size: 16px;
line-height: 1.4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f2f2f2;
}

strong {
font-weight: bold;
}

button {
cursor: pointer;
border: none;
background-color: #6b9fff;
color: white;
border-radius: 50px;
padding: 10px 20px;
font-size: 16px;
}

button:hover {
background-color: #588bf7;
}

.container {
background: white;
width: 360px;
height: 330px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
border-radius: 10px;
}

.container h1 {
font-size: 30px;
font-weight: bold;
margin-bottom: 20px;
color: #333333;
text-align: center;
}

.container .description {
font-size: 17px;
margin: 10px 0;
color: #666666;
}

.container .answer {
display: flex;
gap: 25px;
width: 100%;
}

.container .answer input {
width: 220px;
padding: 10px 20px;
border-radius: 5px;
border: 1px solid #dddddd;
font-size: 16px;
}

.container .answer button{
width: 75px;
}

.error-text {
color: red;
font-size: 17px;
}

.result {
margin-top: 20px;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}

.result h2 {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
color: #333333;
width: 100%;
text-align: left;
}

.result .result-text {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
height: 30px;
color: #333333;
}

.result button {
width: 150px;
margin: 0 auto;
}
48 changes: 44 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<title>숫자 야구 게임</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/reset-css@5.0.1/reset.min.css"
/>
<link
href="https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
/>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<div class="container">
<!-- 제목 -->
<div class="title">
<h1>⚾ 숫자 야구 게임</h1>
</div>
<!-- 설명 -->
<div class="description">
<p>
<strong>1~9까지의 수</strong>를 중복없이
<strong>3개</strong> 입력해주세요
</p>
<p>올바른 예) 139</p>
<p>틀린 예) 122</p>
</div>
<!-- 사용자 입력 -->
<div class="answer">
<input type="text" id="user-input" placeholder="입력하세요" />
<button id="check-button">확인</button>
</div>
<!-- 에러 메세지 -->
<p id="error-message" class="error-text"></p>
<!-- 결과 -->
<div class="result">
<h2>📋 결과</h2>
<p id="result-message" class="result-text"></p>
<button id="restart-button" style="display: none">게임 재시작</button>
</div>
</div>
<script type="module" src="src/main.js"></script>
</body>
</html>
24 changes: 24 additions & 0 deletions src/checkNumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default function checkNumber(userInput) {
const errorMessageElement = document.getElementById("error-message");

errorMessageElement.textContent = "";

// 입력이 3자리 숫자인지 확인
if (!/^\d{3}$/.test(userInput)) {
showError("3자리 수로 입력해주세요");
return false;
}

// 입력에 중복된 숫자가 있는지 확인
if (new Set(userInput).size !== 3) {
showError("중복 없이 입력해주세요");
return false;
}

return true;
}

function showError(message) {
const errorMessageElement = document.getElementById("error-message");
errorMessageElement.textContent = message;
}
24 changes: 24 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import generateRandomNumber from './randNumber.js';
import checkNumber from './checkNumber.js';
import result from './result.js';
import restartGame from './restart.js';

// 정답 랜덤 수 생성
let resultNum = generateRandomNumber(false);

document.getElementById("check-button").addEventListener("click", function () {
// 사용자의 입력을 가져옴
const userInput = document.getElementById("user-input").value;
if (checkNumber(userInput)) {
// 입력된 수가 조건에 맞으면 결과 출력
result(userInput, resultNum);
} else {
// 입력된 수가 조건에 맞지 않으면 결과 초기화
document.getElementById("result-message").textContent = "";
}
});

document.getElementById("restart-button").addEventListener("click", function () {
// 게임 재시작
resultNum = restartGame();
});
29 changes: 29 additions & 0 deletions src/randNumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export default function generateRandomNumber(restart = false) {
// 기존의 resultNum이 localStorage에 있는지 확인
let resultNum = localStorage.getItem("resultNum");

// 게임 재시작이 아닌 경우와 resultNum이 이미 있는 경우 그대로 반환
if (!restart && resultNum) {
return resultNum;
}

// 새로운 정답 생성
resultNum = generateUniqueNumber();
localStorage.setItem("resultNum", resultNum);
console.log(resultNum);
return resultNum;
}

function generateUniqueNumber() {
const answerArr = [];

// 중복되지 않는 3자리 숫자 생성
while (answerArr.length < 3) {
const num = Math.floor(Math.random() * 9) + 1;
if (!answerArr.includes(num)) {
answerArr.push(num);
}
}

return answerArr.join('');
}
21 changes: 21 additions & 0 deletions src/restart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import generateRandomNumber from './randNumber.js';

export default function restartGame() {
// 게임 재시작을 위해 resultNum 제거
clearLocalStorage();
// 입력 및 메시지 초기화
resetInputs();
// 새로운 정답 생성
return generateRandomNumber(true);
}

function clearLocalStorage() {
localStorage.removeItem("resultNum");
}

function resetInputs() {
document.getElementById("user-input").value = "";
document.getElementById("error-message").textContent = "";
document.getElementById("result-message").textContent = "";
document.getElementById("restart-button").style.display = "none";
}
47 changes: 47 additions & 0 deletions src/result.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export default function result(userInput, targetNumber) {
// 결과를 계산
const { strikes, balls } = calculateScore(userInput, targetNumber);
// 결과를 화면에 표시
showResult(strikes, balls);
}

function calculateScore(userInput, targetNumber) {
let strikes = 0;
let balls = 0;

// 입력된 수와 정답을 비교하여 스트라이크와 볼의 개수를 계산
for (let i = 0; i < 3; i++) {
if (userInput[i] === targetNumber[i]) {
strikes++;
} else if (targetNumber.includes(userInput[i])) {
balls++;
}
}

return { strikes, balls };
}

function showResult(strikes, balls) {
const resultMessage = document.getElementById("result-message");
const restartButton = document.getElementById("restart-button");
restartButton.style.display = "none";

if (strikes === 3) {
// 스트라이크가 3개인 경우 정답 메시지를 표시
resultMessage.textContent = "🎉 축하합니다! 정답을 맞추셨습니다! 🎉";
restartButton.style.display = "inline-block";
} else if (strikes > 0 || balls > 0) {
// 스트라이크나 볼이 있는 경우 해당 개수를 표시
let message = "";
if (balls > 0) {
message += ` ${balls} 볼`;
}
if (strikes > 0) {
message += `${strikes} 스트라이크`;
}
resultMessage.textContent = message;
} else {
// 스트라이크와 볼이 모두 없는 경우 낫싱 메시지를 표시
resultMessage.textContent = "낫싱";
}
}