본문 바로가기

Computer Programming/Javascript

JavaScript 숫자야구 - slice(), splice(), filter()의 차이와 문제점

영어로 하면 Bulls and Cows라고 한다고 한다...

컴퓨터가 숫자를 생성하였습니다. 답을 맞춰보세요!
1번째 시도 : 134
0B0S
2번째 시도 : 238
1B1S
3번째 시도 : 820
2B1S
4번째 시도 : 028
3B
5번째 시도 : 280
3S
4번만에 맞히셨습니다. 
게임을 종료합니다.

 

1. 문제점

자바스크립트로 간단한 숫자야구 프로그램을 개발하던 중, 컴퓨터가 생성한 랜덤 수와 유저가 입력한 랜덤 수 중에 동일한 숫자가 있는지 확인하는 함수에서 잠깐 막혔었다.

 

그 이유가, ball인지 확인할 때 그 해당 숫자를 제외한 다른 배열을 또 만들어 비교하고 싶어서 splice를 사용했더니 배열의 원본이 변경되어 원하는 결과를 얻지 못했기 때문이었다. 콘솔 계속 찍어보니 그게 문제였다.

 

아래는 고친 코드! 원하는 부분을 filter 메소드를 이용해 얻어냈다.

const matchNums = (rand, answer) => {
    let status = {
        strike: 0,
        ball: 0,
    }
    console.log("rand:", rand)
    for (let i =0; i < answer.length; i++) {
        if (answer[i] === rand[i]) {
            status.strike++;
            continue
        }
        const newArr = [...rand].filter((item,idx) => idx !== i)
        newArr.includes(answer[i]) && status.ball++;
    }
    console.log(`${status.strike}S${status.ball}B`)
    return status;
}

 

그래서 slice와 filter을 같이 알아봤고 이번 기회에 차이점에 대해 정리해보려고 한다.

 


2-1  slice()

- slice 메소드는 어떤 배열의 begin부터 end까지에 대한 얕은 복사본을 새로운 배열 객체로 반환하며 원본 배열은 바뀌지 않는다.

- slice(start, end) : start 부터 end 전 까지의 복사본을 새로운 배열 객체로 반환한다. 

for (let i =0; i < answer.length; i++) {
    if (answer[i] === rand[i]) {
        status.strike++;
        continue
    }
    const newArr = [...rand].slice(i, rand.length-i)
    newArr.includes(answer[i]) && status.ball++;
}

위의 코드는 당연히 안 되었던게, slice는 말 그대로 내가 슬라이스 해서 그 슬라이스 된 부분을 newArr에 담게 되는데, 내가 필요했던건 그 반대 (슬라이스 하고 남은 부분)이었기 때문에 실패했다.

 

2-2. splice()

- splice 메소드는 배열의 기존 요소를 삭제 또는 교체하거나 새로운 요소를 추가해 배열의 내용을 변경한다.

- 사실 처음 썼던 메소드가 splice 인데, 이 메소드는 기존 배열을 대체하기 때문에 원본 값이 변경된다. 

for (let i =0; i < answer.length; i++) {
    if (answer[i] === rand[i]) {
        status.strike++;
        continue
    }
    const newArr = [...rand].splice(i,1)
    //rand 배열에 변화가 생김
    newArr.includes(answer[i]) && status.ball++;
}

splice는 목적은 다양하지만 원본을 변경하기 때문에 주의가 필요함!

 

2-3. filter()

- 마지막으로 사용한 메소드이고 리턴된 배열 중 원하는 값을 얻어낼 수 있었다.

for (let i =0; i < answer.length; i++) {
    if (answer[i] === rand[i]) {
        status.strike++;
        continue
    }
    const newArr = [...rand].filter((item,idx) => idx !== i)
    newArr.includes(answer[i]) && status.ball++;
}

같은 인덱스를 가진 배열의 요소를 제외하고, 나머지 요소 중에서 비교한 다음, 그 요소가 존재하면 ball을 1씩 올리는 코드이다.

 

3. 전체코드

 

📑 Github: https://github.com/nayoung3669/BullsAndCows

 

GitHub - nayoung3669/BullsAndCows: 자바스크립트 숫자야구게임입니다.

자바스크립트 숫자야구게임입니다. Contribute to nayoung3669/BullsAndCows development by creating an account on GitHub.

github.com

const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
let count = 1;
let cmptNum = []

const generateRand = () => {
    let rand = ''
    while (rand.length < 3) {
        const randNum = Math.floor(Math.random() * 10);
        !rand.includes(randNum) && (rand += randNum)
    }
    return rand.split('').map(Number)
}

const answerCallback = (answer) => {
    let result = matchNums(cmptNum, answer.split('').map(Number))
    count ++;
    result.strike === 3 ? rl.close() : rl.question(`${count}번째 시도:`, answerCallback);
}

const matchNums = (rand, answer) => {
    let status = {
        strike: 0,
        ball: 0,
    }
    console.log("rand:", rand)
    for (let i =0; i < answer.length; i++) {
        if (answer[i] === rand[i]) {
            status.strike++;
            continue
        }
        const newArr = [...rand].filter((item,idx) => idx !== i)
        newArr.includes(answer[i]) && status.ball++;
    }
    console.log(`${status.strike}S${status.ball}B`)
    return status;
}
cmptNum = generateRand();

rl.question(
    `컴퓨터가 숫자를 생성하였습니다. 답을 맞춰보세요!
${count}번째 시도: `, answerCallback
)

rl.on('close', () => {
    process.exit()
});

 

- 콘솔창

 

 

이번 코드에서는 자바스크립트의 객체지향적인 특징을 최대한 적용해보려 노력했다. 함수도 화살표함수로만 구성했으며 변수 선언과 초기화도 스코프 생각하는데 시간을 들였다.

 

개발 공부를 처음 시작했을 때는 기능을 구현하는것에 바빴었는데, 다른 사람들 코드도 구경하고 많이 배우기도 하면서 자바스크립트가 어떻게 동작하는지에 관한 관심이 더욱 생겼다.

 

내가 매일 보고 작성하는 언어가 어떤 원리로 되는지, 왜 이렇게 생겼는지에 관한 질문을 하게 되었고 그러면서 CS 공부도 하고싶어졌다. 이번에 하기로 한 스터디 열심히 해야지..!