- 상대편이 숫자 1~9 중에서 중복되지 않게 네 개의 숫자를 고른다.
- 10번의 기회가 주어지고 상대편이 고른 숫자 네 개를 맞히면 된다.
- 이때 숫자만 맞히는 것이 아니라 숫자의 순서까지 맞혀야 한다
- 만약에 상대방이 3 6 7 9 라는 숫자를 골랐다고 하고 내가 1 7 2 5 라는 숫자를 뽑았다고 가정한다면, 7이라는 숫자를 한개 맞췄지만 순서는 못맞췄으니 1볼이라는 힌트를 얻게 된다.
- 다시 6 3 7 8 이라는 숫자를 뽑았다고 가정한다면, 6과 3이라는 숫자는 맞지만 순서는 틀린 숫자 2개와, 7이라는 숫자도 맞고 순서도 맞는 숫자를 뽑은 것이므로, 1스트라이크 2볼이라는 힌트를 준다.
- 만약 숫자를 한개도 못맞춘다면 아웃이고 한번에 숫자를 6 3 7 8 이라고 맞춘다면 홈런이 되어서 문제를 맞추는 사람이 승리하게 된다. 10번 이내로 숫자를 못 맞추게 된다면 상대방이 승리하게 된다.
일단 1부터 10까지의 숫자 4개를 무작위로 뽑아서 빈 배열에 그 값들을 넣어줘야겠다고 생각했다.
document.addEventListener('DOMContentLoaded', () => {
let answer = [];
for(let i =1; i < 5; i++){
let num = Math.floor(Math.random() * 9) +1;
answer.push(num);
}
})
❗️ 하지만 이렇게 됐을때, 배열에 중복값이 발생하는 문제가 생겼다. 정답에 들어가는 숫자는 중복값이 없어야했다.
1~9까지 숫자가 들어가는 배열을 하나 만들어주고, 거기서 나오는 숫자를 빼주는 식으로 코드를 짰다.
document.addEventListener('DOMContentLoaded', () => {
// 정답 추출
let answer = [];
let numbers = [];
for(let i =1; i <=9; i++){
numbers.push(i);
}
for(let i = 0; i < 4; i++){
let index = Math.floor(Math.random() * 9)
answer.push(numbers[index]);
numbers.splice(index, 1);
}
console.log(answer);
})
❗️ 하지만 이렇게 하니까 콘솔창에서 undefiend라는 값이 나왔다 왜일까?
- 저기서 index 변수는 numbers 배열에 index로 들어가므로 만약에 랜덤으로 뽑은 숫자가 8이 나오고 또 8이 나왔을때, 그에 맞는 index값이 없으므로 undefined 값이 나온다.
// 개선 코드
document.addEventListener('DOMContentLoaded', () => {
// 정답 추출
let answer = [];
let numbers = [];
for(let i =1; i <=9; i++){
numbers.push(i);
}
for(let i = 0; i < 4; i++){
let index = Math.floor(Math.random() * numbers.length);
answer.push(numbers[index]);
numbers.splice(index, 1);
}
})
위 처럼 numbers.length를 해줌으로써 index가 줄어들때 numbers 배열에 맞는 길이에서 랜덤값을 뽑도록 했다.
중복값 없이 답이 잘 나온다.
const input = document.querySelector('#input'); // 값 넣는 인풋창
const button = document.querySelector('#button'); // 제출 버튼
const result = document.querySelector('#result'); // 결과창
// 숫자를 제대로 입력 했는가?
button.addEventListener('click', () => {
let inputValue = parseInt(input.value);
let strInputValue = inputValue.toString();
if(isNaN(inputValue) || inputValue == ''){
alert('숫자를 입력하세요');
} else if (strInputValue.length !==4){
alert('4자리 숫자를 입력하세요');
} else if(tries.includes(inputValue)){
alert('이미 시도한 값입니다.')
} else {
tries.push(inputValue);
result.textContent = inputValue;
}
❗️ 여기서 result창에 input값을 띄웠을때, 값이 입력되고 바로 화면이 초기화 되는 문제가 발생했는데 event.preventDefault() 를 통해서 문제를 해결할 수 있었다❗️
HTML 에서 a 태그나 submit 태그는 기본적으로 가지고 있는 동작들이 있다. a태그는 클릭시에 그 href 경로로 이동을 한다거나, submit 태그을 눌렀을때 화면이 무조건 새로고침이 되는 현상이 발생하는데
Event.preventDefault() 를 통해서 그 현상들을 막아줄 수 있다.
❗️ 여기서 스트라이크와 볼을 어떻게 검사할거냐가 문제였는데, 처음에는 filter 메서드를 이용하면 되지 않을까 했다. 하지만 filter 메서드는 요소만 반환해줄뿐, index 자리값까지 검사해주지는 못하는 문제가 발생했다 ❗️
const SB = answer.filter((x) => strInputValue.includes(x));
console.log('SB = ' + SB); // 요소만 반환함
홈런을 구현해볼수는 있지 않을까? 했지만 요소만 반환하는 것이었기 때문에, 정답이 만약 7, 8 ,1 ,2 라고 했을때 인풋값에 8 ,7, 2 ,1 을 입력해도 홈런처리가 됐기때문에 불가능 했다. 어쩔수 없이 filter 메서드 사용보다 다른 메서드를 사용할 수밖에 없었다.
let count = 0;
for(let i = 0; i < answer.length; i++){
if(answer[i] == strInputValue[i]){
count++;
}
if(count == 4){
result.textContent = ' 홈런 ! ';
}
}
count 변수를 선언해주고, 반복문을 돌려서 값들이 전부 다 같다면 count를 올려준다. 이 값이 4가 된다면 숫자와 인덱스값이 전부 같은 것이므로, 홈런 메세지를 띄어주었다!
let strike = 0;
let ball = 0;
for (let i = 0; i < answer.length; i++) {
let index = strInputValue.indexOf(answer[i]);
if (index > -1) {
if (index == i) {
strike++;
} else {
ball++;
}
}
}
result.textContent = strike + " 스트라이크 " + ball + " 볼 ";
❗️ 이렇게 하면 결과값이 줄바꿈이 되며 누적되지 않고, tries 배열에 10개의 값들이 채워지더라도 패배했다는 텍스트가 나오지 않았다 ❗️ if 문 안에 조건들을 다 넣어주고 호이스팅이 발생하지 않도록 코드 순서를 바꾸어주니 해결이 되었다.
for (let i = 0; i < answer.length; i++) {
let index = strInputValue.indexOf(answer[i]);
if (answer[i] == strInputValue[i]) {
count++;
}
if (index > -1) {
if (index == i) {
strike++;
} else {
ball++;
}
}
}
if (isNaN(inputValue) || inputValue == "") {
alert("숫자를 입력하세요");
} else if (strInputValue.length !== 4) {
alert("4자리 숫자를 입력하세요");
} else if (tries.includes(inputValue)) {
alert("이미 시도한 값입니다.");
} else if (duplicatedInput.size !== 4) {
alert("숫자를 중복되지 않게 입력해주세요");
} else if (count == 4) {
result.textContent = " 홈런 ! ";
} else {
result.textContent = strike + " 스트라이크 " + ball + " 볼 ";
tries.push(inputValue);
console.log(tries);
}
else {
result.append(inputValue + ' : ' + strike + " 스트라이크 " + ball + " 볼 ", document.createElement('br') );
tries.push(inputValue);
console.log(tries);
}
textContent 가 아닌 append 메서드를 사용함으로써 값이 연속적으로 나타나게 했고 document.createElement('br')를 추가해서 줄바꿈을 해주었다!
값이 잘 출력된다.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>숫자야구</title>
<script src="main.js"></script>
</head>
<body>
<form id="form">
<input type="text" id="input">
<button id="button"> 확인 </button>
</form>
<div id="result"></div>
</body>
<script>
document.addEventListener("DOMContentLoaded", () => {
// 정답 추출
let answer = []; // 정답
let numbers = []; // 1~9까지 숫자
let tries = []; // 시도한 숫자들 담을 배열
for (let i = 1; i <= 9; i++) {
numbers.push(i);
}
for (let i = 0; i < 4; i++) {
let index = Math.floor(Math.random() * numbers.length);
answer.push(numbers[index]);
numbers.splice(index, 1);
}
console.log(answer);
// 변수 선언
const input = document.querySelector("#input"); // 값 넣는 인풋창
const button = document.querySelector("#button"); // 제출 버튼
const result = document.querySelector("#result"); // 결과창
// 숫자를 제대로 입력 했는가?
button.addEventListener("click", (e) => {
e.preventDefault(); // 초기화 해결
let count = 0;
let strike = 0;
let ball = 0;
let inputValue = parseInt(input.value); // 인풋값 숫자로 변경
let strInputValue = inputValue.toString().split("").map(Number);
let duplicatedInput = new Set(strInputValue);
for (let i = 0; i < answer.length; i++) {
let index = strInputValue.indexOf(answer[i]);
if (answer[i] == strInputValue[i]) {
count++;
}
if (index > -1) {
if (index == i) {
strike++;
} else {
ball++;
}
}
}
//입력을 제대로 못했다면
if (isNaN(inputValue) || inputValue == "") {
alert("숫자를 입력하세요");
} else if (strInputValue.length !== 4) {
alert("4자리 숫자를 입력하세요");
} else if (tries.includes(inputValue)) {
alert("이미 시도한 값입니다.");
} else if (duplicatedInput.size !== 4) {
alert("숫자를 중복되지 않게 입력해주세요");
} else if (count == 4) {
result.textContent = " 홈런 ! ";
} else {
result.append(inputValue + ' : ' + strike + " 스트라이크 " + ball + " 볼 ", document.createElement('br'));
tries.push(inputValue);
console.log(tries);
}
// 패배 창 띄우기
if (tries.length >= 9) {
result.textContent = "패배! 정답은 " + answer.join("") + " 입니다.";
}
input.value = ""; // 인풋창 초기화
});
});
</script>
</html>