사실 프로그래밍적으로 무작위의 수를 생성할 수 있는 방법은 없습니다. 강의 초기에 살펴봤듯이 CPU는 2진법 수를 입력하면 CPU의 논리회로에 의해 계산된 2진법수가 출력되는데, 입력값이 같다면 출력값도 항상 같기 때문입니다. 즉 수학적으로 무작위 수를 만들 수 있는 방정식은 존재하지 않기 때문에 CPU는 무작위의 값을 구할 수 없습니다.
그래서 초기의 프로그래밍언어에서는 '난수표'라는 무작위 수들을 미리 기록해 둔 뒤, 숫자를 하나씩 가져오는 방식을 사용했습니다. 함수를 처음 실행하면 난수표에서 첫번째 수를 가져오고, 두번째 실행하면 두번째 수를 가져오는 방식으로 말이죠. 난수표에 기록된 수들을 모른다는 가정하에 무작위 수라고 할 수 있지만 진정한 무작위 수는 아닙니다. 난수표를 만든 사람은 다음번에 뭐가 나오는지 알 수 있죠.
이 문제는 굉장히 많은 난수표를 사용하므로 해결될 수 있습니다. 넉넉하게 1억개 정도 난수표를 만든 다음 이중에서 난수표 하나를 뽑아서 사용하면 난수표를 만든 사람도 다음에 뭐가 나올지 모르겠죠. 하지만.. '무작위 수'를 구하기 위해 여러 난수표 중의 하나를 '무작위'로 구해야 하는 딜레마가 생깁니다. 결국 여러 난수표 중에서 '무작위'로 하나를 뽑을 수 있는 방정식 역시 구할 수 없죠.
이 문제를 해결하기 위해 현재 시간을 사용할 수 있습니다. 60개의 난수표를 만든 다음, 현재시간이 12시 30분 23초라고 하면, 23번째 난수표를 사용하면 되겠죠. 대신 위에서 말했다시피 정확히 같은 초에서 함수가 실행된다면 같은 난수표를 사용하게 되고, 해당 초의 난수표를 알고있는 사람이 있다면 다음번에 무슨 수가 나올지 예상 가능하게 됩니다. 그렇다면 밀리초(1/1000초)를 사용합시다. 함수가 정확히 어떤 밀리초에서 실행되는지조차 알기 힘들기 때문에 이 방법은 꽤나 유용할 것입니다.
현재는 현재시간 등과 같은 특정한 값을 사용해서 랜덤한 수를 만들어주는 다양한 알고리즘들이 개발이 되어 사용되고 있지만 그 본질은 변하지 않습니다. 프로그래밍으로 진정한 무작위 수를 구할 수 없습니다. 무작위 수를 구하기 위해서 다양한 값들이 사용되는데, 이 입력값들이 같다면 결국 같은 값을 출력하게 됩니다. 결국 무작위같아 보이는 값을 구하는 방법인 것입니다.
이처럼 랜덤한 수를 만들기 위해서는 다양한 방법들이 동원되기 때문에 언어별로 랜덤한 수를 만드는 방법 역시 다양합니다. C언어에서는 아직도 현재시간을 사용해서 난수표 생성'-> '난수표에서 수 가져오기' 과정을 통해 랜덤한 수를 생성하기도 하고, 최신언어들은 일련의 과정을 알아서 처리해주는 함수를 재공하기도 합니다.
자바스크립트에서는 Math.random() 함수로 0 이상 1 미만인 무작위의 수를 만들 수 있습니다(0은 나올 수도 있지만 1은 절대 나오지 않는다고 합니다). 언어에 따라 무작위 수를 얻는 방법이 다르다는 것도 기억해 둡시다.
Math.random();
이런식으로 소수점이 있는 수가 생성됩니다.
이 함수를 이용해서 0 이상 10 미만인 랜덤한 수를 만들려면? 결과에 10을 곱해주면 되겠죠.
Math.random()*10;
소수점 없이 0, 1, 2, 3, 4, 5, 6, 7, 8, 9의 10가지 수 중에 하나를 얻고 싶다면 소수점 이하의 값을 버리면 됩니다.
Math.floor()함수로 소수점 이하의 값을 버릴 수 있습니다. 반올림이 아니라 소수점 이하의 값을 무조건 버리는 함수입니다.
Math.floor(Math.random()*10);
위 내용을 바탕으로 눈금이 1부터 6까지 있는 주사위 함수를 만들 수 있습니다.
function dice6(){ return Math.floor(Math.random()*6)+1; }
Math.floor(Math.random()*6)는 0부터 5까지의 정수가 나오므로 여기에 1을 더해주면 1부터 6까지의 값이 나오게되는 것이죠.
만약 어떤 게임을 개발하는데, 눈금이 1에서 6까지 있는 주사위와 1에서 10까지 있는 주사위 두 개를 사용한다면 함수를 어떻게 만들어야 할까요?
function dice6(){ return Math.floor(Math.random()*6)+1; } function dice10(){ return Math.floor(Math.random()*10)+1; }
이렇게 두가지 함수를 만들어서 사용할 수도 있겠지만, 위 두가지 기능을 모두 할 수 있는 하나의 함수만 만들 수도 있습니다.
function dice(maxNumber){ return Math.floor(Math.random()*maxNumber)+1; }
dice(6), dice(10)로 dice6과 dice10의 기능을 할 수 있습니다. 이때 dice 함수는 dice6, dice10함수에 비해 더 일반화가 되었다라고 표현합니다.
일반화된 코드는 여러 장점이 있습니다.
위에서 만든 dice함수를 사용해 주사위 게임 함수를 만들어 봅시다.
- 주사위는 눈금이 1에서 6까지입니다.
- 컴퓨터의 주사위 값을 구하여 "컴퓨터의 주사위는 x입니다."라고 콘솔에 출력합니다. x는 주사위 눈금의 값입니다.
- 사용자의 주사위 값을 구하여 "당신의 주사위는 x입니다."라고 콘솔에 출력합니다. x는 주사위 눈금의 값입니다.
- 컴퓨터의 주사위 값과 사용자의 주사위 값을 비교하여 "x의 승리입니다."를 출력합니다. 컴퓨터의 주사위 값이 높으면 x에 "컴퓨터", 아니라면 "당신" 이 들어갑니다.
- 비긴 경우 "비겼습니다."를 콘솔에 출력합니다.
// 주사위 값을 생성하는 함수 function dice(maxNumber){ return Math.floor(Math.random()*maxNumber)+1; } // 주사위 값을 출력하는 함수 function printDice(name, num){ console.log(name+"의 주사위는 "+num+"입니다."); } // 승자를 출력하는 함수 function printWinner(name){ console.log(name+"의 승리입니다."); } // 비겼음을 출력하는 함수 function printDraw(){ console.log("비겼습니다."); } /* 위의 함수들은 게임의 각 부분을 담당하는 함수들이며, 아래 게임 메인 함수는 전체적인 프로그램의 진행을 담당합니다. */ // 게임 메인 함수 function diceGame(){ var computerName = "컴퓨터"; var yourName = "당신"; var computerDice = dice(6); // 컴퓨터의 주사위 값 을 구함 printDice(computerName, computerDice); // 컴퓨터 주사위 값 출력 var yourDice = dice(6); // 사용자의 주사위 값을 구함 printDice(yourName, yourDice); // 사용자 주사위 값 출력 if(computerDice > yourDice){ // 만약 컴퓨터의 주사위 값이 더 크면, printWinner(computerName); // 컴퓨터 승리 문구 출력 } else if(computerDice < yourDice){ // 그렇지 않고 만약 사용자의 주사위 값이 더 크면, printWinner(yourName); // 사용자 승리 문구 출력 } else { // 다 아니라면, printDraw(); // 비겼음을 출력 } }
위 코드에서 //, /*, */라고 표시된 부분을 주석(comment)이라고 합니다. 코드를 읽는 사람에게 도움을 주기 위해 작성한 글로 프로그램에는 아무런 영향을 끼치지 않습니다.
//는 한 줄에서 // 뒷부분에 입력된 내용을 코드에 포함시키지 않는 역할을 하고, /*는 */가 나올 때까지 그 사이의 모든 내용을 무시합니다.
댓글
이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기