항해99 1주차 과제이다.
- 컴퓨터는 0과 9 사이의 서로 다른 숫자 3개를 무작위로 뽑습니다. (ex) 123, 759
- 사용자는 컴퓨터가 뽑은 숫자를 맞추기 위해 시도합니다.
- 컴퓨터는 사용자가 입력한 세자리 숫자에 대해서, 아래의 규칙대로 스트라이크(S)와 볼(B)를 알려줍니다.
- 숫자의 값과 위치가 모두 일치하면 S
- 숫자의 값은 일치하지만 위치가 틀렸으면 B
- 기회는 무제한이며, 몇번의 시도 후에 맞췄는지 기록됩니다.
- 숫자 3개를 모두 맞춘 경우, 게임을 종료합니다.
1. Readline 불러와준다
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
};
Readline같은 경우에는 내가 지금 구덩이 파고 있는 주제 중 하나이다.
아마 오늘 내로 1차적 삽질리포트가 올라올 것이다.
2. 배열을 지정한다
var answer = []
이 배열은 나중에 랜덤값을 저장할 때 사용해줄 것이다
3.랜덤한 숫자 생성하기
var answer = [];
while(answer.length < 3){
var randomNum = Math.floor(Math.random()*10);
if(answer.indexOf(randomNum) > -1) continue;
answer.push(randomNum);
}
위 코드에서는 랜덤으로 숫자를 생성해 생성된 숫자가 4개 미만이라면 새로운 숫자가 생성되고,
중복되지 않는다고 하면 결괏값인 randomNum 에 저장이 된다.
조금 더 자세히 알아보도록 하자
- 생성되는 숫자 제어하기
while(answer.length < 3){
만약의 answer 배열의 길이가 3보다 작다면 ~ 으로 시작해서 작동하는 코드이다.
answer 배열의 길이가 3개 이상이라면 멈추게 된다
- 숫자를 정수화한 후 Randomnum에 넣기
var randomNum = Math.floor(Math.random()*10);
이때 math.random()으로 숫자를 생성하고,
이 숫자의 범위는 0~1이기 때문에 *10을 해줘서 1~10으로 바꿔준다.
그 후 Math.floor로 소숫점을 떨궈주고, randomNum으로 정의해준다.
- 코드의 중복 확인하기
if(answer.indexOf(randomNum) > -1) continue;
indexof: 지정된 요소의 인덱스를 검색하는 javascript의 내장 메서드이다.
호출한 배열에서 첫번째로 일치하는 요소의 인덱스변환, 일치하는 요소가 없는 경우 -1 을 반환한다.
만약 2번째 숫자가 같았으면 해당숫자의 인덱스인 1이 반환되고,
첫번째 숫자가 같았으면 해당 숫자의 인덱스인 0이 반환된다.
-1보다 작으면 continue로 계속해준다
indexof도 곧 포스팅할 예정이다!.
- 중복이 아니라면
answer.push(randomNum);
randomNum에 answer가 들어가게 된다
4. 세자리 숫자 입력받고 사용자 입력의 중복/글자수 이상 처리하기
function playGame() {
readline.question('세자리 숫자를 입력하세요.', (playerInput) => {
count++;
if(playerInput.length !== 3 || new Set(playerInput).size !== 3){
console.log("세자리의 서로 다른 숫자를 입력하세요.");
playGame();
return;
}
readline를 이용하여 세자리 숫자를 입력받았다.
그러나 만약 세 자리 숫자 안에 중복된 숫자가 있거나, 4자리라면 어떻게 되는 걸까?
당연히 프로그램 진행에 문제가 생긴다.
자세히 뜯어보자.
세 자리 숫자 입력받고 입력받을 때 마다 시도횟수 하나씩 증가시키기
function playGame() {
readline.question('세자리 숫자를 입력하세요.', (playerInput) => {
count++;
나는 playGame이라는 함수를 사용하기로 했다
제일 먼저 readline.question으로 사용자의 입력을 받았다
실행 결과의 이 부분이라고 생각하면 될 것 같다.
사용자가 입력한 값은 콜백 함수의 매개변수인 playerInput에 저장된다.
한번 입력을 받을 때 마다 count 횟수를 1씩 늘려준다
이는 마지막에 시도 횟수를 출력할때 사용된다
- 사용자 입력의 중복이 있거나 길이가 3이 아니라면
if(playerInput.length !== 3 || new Set(playerInput).size !== 3){
console.log("세자리의 서로 다른 숫자를 입력하세요.");
playGame();
return;
}
논리 OR 연산자
두 개의 피연산자중 하나 이상이 True이상인지를 확인하고, 결과로 True를 반환한다.
- 왼쪽 피연산자를 평가한 결과가 True이면 오른쪽 피연산자 평가 x 그냥 바로 True반한
- 왼쪽 피연산자를 평가한 결과가 False 이면 오른쪽 피연산자 평가하고 그 결과를 반환함
(추후 포스팅해볼 내용이 더 늘어나버렸네…;;
이걸 어떻게 적용했냐면
if(playerInput.length !== 3 || new Set(playerInput).size !== 3){
이 상황에서 playerInput.length이 3이 아니라면, 뒤에 중복 여부 결과는 보지 않고 바로 True를 반환한다.
숫자가 3개도 아닌데 굳이 중복 볼 필요가 있냐는거다.
그래서 먼저 앞의 숫자 갯수를 확인해본 후 playerInput을 Set 형태로 바꿔준다
*set은 중복이 존재할 수 없다
중복이 없는 상태에서 숫자의 갯수가 3개가 맞는지 확인하는 과정이였다.
논리 OR 연산자 쓰는 게 습관이 되어가고 있다 ! &ㅠ&
5. 기본 값 세팅하기
var strike = 0;
var ball = 0;
var checkResult = Array(3).fill(0);
strike 카운트와 Ball 카운트를 초기화해준다.
그리고 Array(3).fill(0)이라는 게 보이는데 이는 길이간 3인 배열을 생성하고, 그 배열의 모든 요소를 0으로 채우는 역할을 한다.
Array 생성자 함수에 문자 3을 인수로 넣어 배열의 길이를 설정하고, fill 메서드를 조합해서 쓰여진다.
나는 이것을 세 자리 수에 각각 비교하도록 구성해보려 하였다.
- array와 Fill을 사용하지 않고 작성한다면??
직접 배열 리터럴을 사용하여 배열을 생성하고 요소에 초기값을 할당한다
var checkResult = [0, 0, 0];
배열 생성 후에 반복문이나 인덱스 접근을 통해 각 요소에 초기값을 할당한다.
var checkResult = [];
for (var i = 0; i < 3; i++) {
arr[i] = 0;
}
빈 배열을 생성한 후에 반복문을 사용하여 각 요소에 초기값 0을 할당하는 법.
배열의 크기가 커지면 이 방향을 사용하여야 할듯
away.from 메서드를 사용하여 배열을 생성하고 초기값을 할당한다
var arr = Array.from({ length: 3 }, () => 0);
이러한 방법으로도 쓸 수 있다. array.fill이랑 다른 점이라면 여러 개의 매개변수를 받을 수 있다 정도?
- 현재 요소의 값
- 현재 요소의 인덱스
- 생성된 배열의 전체 길이
를 받을 수 있다.
비어있는 자리에는 value, index가 들어있다
추후 좀 더 공부해보고 이 주제만 단독으로 포스팅해보도록 하겠다 !
6. 볼과 스트라이크 구성/ 표현
for(var i=0; i<3; i++){
if(answer[i] == playerInput[i]){
checkResult[i] = 2;
} else if(answer.indexOf(parseInt(playerInput[i])) > -1){
checkResult[i] = 1;
}
}
i를 0으로 두었고, 세 자리 숫자이기에 세 번만 할 수 있도록 제한해준다.
한번 실행될따마 i에 하나씩 더해진다
- 스트라이크 구현
if(answer[i] == playerInput[i]){
checkResult[i] = 2;
만약 정답의 n번째 인덱스에 있는 숫자가 입력값의 n번째 인덱스에 있는 숫자와 같다면
checkResult[i]가 2가 된다
즉 strike 를 나타내는 표현으로 2를 둔 것이다
- 볼 구현
} else if(answer.indexOf(parseInt(playerInput[i])) > -1){
checkResult[i] = 1;
}
스트라이크는 조금 감이 잡혔는데 볼은 어떻게 구현해야 할 지 감이 잘 안 잡혔었다.
그래서 중복 찾기에서 진행했던 방식을 조금 활용해보기로 헀다.
playerinput이 지금 사용자가 입력한 문자열을 가지고 있기에 parseInt로 정수로 변환한다.
Indexof 메서드는 배열에서 특정값을 검색하고, 검색된 값의 첫 번째 인덱스를 보낸다.
만약에 Indexof 값이 -1을 넘는다면 특정 인덱스에서 겹친다는 것이다
따로 떼놓고 본다면, 어? 저렇게 되면 스트라이크도 볼이 될 수 있는 거 아니야? 라고 할 수 있는데
for(var i=0; i<3; i++){
if(answer[i] == playerInput[i]){
checkResult[i] = 2;
} else if(answer.indexOf(parseInt(playerInput[i])) > -1){
checkResult[i] = 1;
}
}
이렇게 전체를 보면 이해가 된다
if문에서 인덱스가 아예 같은건 다 스트라이크로 보내버리고
남은것들만 있기 때문이다
7.볼과 스트라이크 세기
strike = checkResult.filter(x => x === 2).length;
ball = checkResult.filter(x => x === 1).length;
checkresult.filter로 조건을 만족하는 요소들을 필터링하여 새로운 배열을 생성한다.
x는 현재 요소를 나타내는 매개변수이다
x가 2가 일치하는 경우로 배열을 만들어버리고 그 배열의 길이를 구하는 것이다.
strike,Ball을 숫자로 둔 이유가 그것이다
ball같은 경우에도 마찬가지다. result에 ball이 몇개가 있는지 확인하고 그 배열의 길이를 구해준다
- 여기서 질문: 새로 생긴 배열은 어디에 저장되는가 ? 저장하긴 하는가?
→ 저장 안 된다. 그냥 쓰고 버림. strike에 저장되는건 새로 만든 배열의 길이일 뿐임.
→ 그럼 이거는 그냥 날리는 건가요? 필요가 없어서 뒤에 사용을 안 했다면 날려버리는거죠?
8. 결과 출력하기
if(strike === 3){
console.log("축하합니다! " + count + "번만에 맞췄습니다.");
readline.close();
} else {
console.log(strike + "S " + ball + "B 입니다.");
playGame();
}
});
}
strike가 세 개면 종료 메세지를 출력한다.
세 개가 아니면 될 때 까지 출력해주고 스트라이크 갯수와 볼 갯수를 포함해 안내 메세지를 출력해준다.
그리고 Playgame 함수를 다시 출력해준다
구현화면
최종 코드
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
var answer = [];
while(answer.length < 3){
var randomNum = Math.floor(Math.random()*10);
if(answer.indexOf(randomNum) > -1) continue;
answer.push(randomNum);
}
var count = 0;
function playGame() {
readline.question('세자리 숫자를 입력하세요.', (playerInput) => {
count++;
if(playerInput.length !== 3 || new Set(playerInput).size !== 3){
console.log("세자리의 서로 다른 숫자를 입력하세요.");
playGame();
return;
}
var strike = 0;
var ball = 0;
var checkResult = Array(3).fill(0);
for(var i=0; i<3; i++){
if(answer[i] == playerInput[i]){
checkResult[i] = 2;
} else if(answer.indexOf(parseInt(playerInput[i])) > -1){
checkResult[i] = 1;
}
}
strike = checkResult.filter(x => x === 2).length;
ball = checkResult.filter(x => x === 1).length;
if(strike === 3){
console.log("축하합니다! " + count + "번만에 맞췄습니다.");
readline.close();
} else {
console.log(strike + "S " + ball + "B 입니다.");
playGame();
}
});
}
playGame();
- 참고한 자료 목록
- https://ourcstory.tistory.com/57 ( Readline)
'2023 공부한것들' 카테고리의 다른 글
[node.js] call stack (eng) (0) | 2023.06.17 |
---|---|
[TIL] 20230615 개발일지 (0) | 2023.06.16 |
[node.js] 자바스크립트의 연산자 8종 (0) | 2023.06.13 |
[node.js] 형변환 (1) | 2023.06.13 |
[node.js] js 언어의 특징| 객체지향프로그래밍/객체생성/동적타이핑/함수형프로그래밍 (0) | 2023.06.13 |