LearningJS-CH04.1-제어문의 기초

5 분 소요

크라운 앤 앵커 게임 구현하기

우리는 크라운 앤 앵커 게임을 통해서 JS의 제어문을 배워보고자 한다.

크라운 앤 앵커 게임의 규칙부터 알아보자. 평평한 면 위에 여섯 개의 사각형이 있고, 그 위에는 크라운, 앵커, 하트, 클럽, 스페이드, 다이아몬드를 나타내는 그림이 있다. 게임을 하는 선원은 사각형에 돈을 걸 수 있고, 돈을 건 다음에는 6면체의 주사위를 굴린다. 주사위가 사각형 번호에 일치하는 숫자에 멈추면, 선원은 거기 건 만큼의 돈을 딸 수 있다.

자 이제 규칙을 통해서 우리는 이것을 코드로 만들어보자.

우선, 기본 조건부터 만들어보자. 시작조건, 그리고 종료조건이다.

기본적은 자본은 50으로 하고, 자본이 2배가 된다면, 게임을 종료한다. 만약 돈이 떨어질때까지 자본이 2배가 되지못하면, 자본을 다 잃을 때까지 게임은 종료되지 않는다.

코드에서 사용할 변수, 그리고 동작들의 제한은 다음과 같은 것만 사용한다.

funds = 50, bets = {}, hand = [] // 변수
rand(1, 6) // m이상, n이하의 무작위 정수
randFace() // 하트, 크라운등을 결정할 무작위 문자열
bets["heart"] = 5, bets[randFace()] = 5 // 객체 프로퍼티 할당
hand.push(randFace()) // 배열에 요소 추가
// 그 외 간단한 사칙연산

조건의 따라 결정되는 부분은 다음과 같이 제한한다.

funds>0, funds< 100 // 숫자비교
totalBet === 7 // 일치 비교
funds > 0 && funds < 100 // 논리연산자순서

이제 우리는 코드를 직접적으로 구현해볼 것이다.

1. while문

우선 조건을 주고, 그 조건이 끝날때까지 계속 반복하는 while문을 사용한다. 조건은 funds > 1 && funds < 100이다.

let funds = 50; // 시작조건

while (funds > 1 && funds < 100){
    // 돈을 건다.
    
    // 주사위를 굴린다.
    
    // 그림을 맞췄으면, 돈을 가져온다.
}

2. 블록 문

블록 문은 엄밀히 제어문은 아니지만, 같이 사용되는 것이다. 블록문은 문 여러 개를 중괄호로 묶은 것이며 자바스크립트에서는 이들을 하나의 단위로 취급한다. 다음과 같이 제어문 없이 블록 문만 사용해도 되지만, 별 의미를 갖진 않는다.

{ // 블록 문
    console.log("statement1");
    console.log("statement2");
}

console.log("statement3" );

처음 두 console.log는 블록안에 있고, 유효한 문법이지만 별의미를 갖진않는다.

블록문이 유용하게 사용되는 것은 제어문과 함께 사용된 때이다. 다음 예시를 보며 이해하자

// while문에서 실행하는 루프는 블록문 전체를 실행하고 조건을 다시 테스트 한다. 
// 2보 전진후 1보 후퇴

step = 0;

while(step < 100){
    step += 2;
    step -= 1;
}

제어문에는 블록을 사용하는 것이 일반적이지만, 간단한 연산의 경우에는 꼭 그럴필요는 없다.

그러나 블록문을 사용하는 것이 보통 우리가 보고 구분하기에 편하고, 다음과 같은 실수도 방지할 수 있다.

while(funds>1)
    funds += 2;
    funds -= 1;

// 계산은 이렇게 된다.
while(funds>1)
    funds += 2;

funds -= 1; // while문이 끝난 뒤에 실행

그리고 if-else문 처럼 두 개를 써야할 때, 꼭 둘다 블록문을 써주거나, 쓰지 않거나 해야한다.. 헷갈려…

3. 보조함수

크라운 앤 앵커를 구현하기 위해서는 보조 함수 2개가 필요하다. 아직 제대로 배우지 않았으니, 일단 가져다 쓰자.

// m이상 n이하의 무작위 정수를 반환
function rand(m, n) {
    return m + Math.floor((n - m + 1) * Math.random());
}

// 크라운 앤 앵커 게임의 여섯가지 도형 중 무작위 하나를 반환하는 함수
function randFace(){
    return ["crown", "anchor", "heart", "spade", "club", "diamond"][rand(0, 5)];
}

4. if-else

이제 ‘돈을 거는’ 행동을 만들어보자. 우리의 게임 주인공은 럭키가이라서 우연히 7펜스가 나오면, 주머니에 있는 모든 돈을 하트에 올인(…)한다. 그렇지 않다면, 아무렇게나 돈을 건다. 코드로 만들자.

const bets = {
    crown: 0,
    anchor: 0,
    heart: 0,
    spade: 0,
    club: 0,
    diamond: 0
};
let totalBet = rand(1, funds);
if (totalBet === 7) {
    totalBet = funds;
    bets.heart = totalBet;
} else {
    // 해당 판에 걸 돈을 분배
}
funds -= totalBet;

5. do-while 루프

우리의 게임 주인공은 판돈을 걸때도 심상치 않은 사람이다! 오른손에 동전을 쥐고, 왼손으로 그 동전을 집지만, 세지는 않는다. 잡히는 대로 집어서 아무 사각형에 걸기 때문에, 때로는 동전 한 개를 걸 때도 있고 오른손에 쥔 동전 전부를 걸 때도 있다. 같은 사각형에 여러 번 걸 때도 있다.

이렇듯 무작위로 판돈을 나누는 행동을 우리는 또 구현해봐야한다…도대체 게임주인공은 무엇을 하는 사람인건가..

do-while루프는 while과 다르게, 루프 바디를 최소 한 번을 실행하려고 할 때 사용한다. 시작하면서 조건을 검사하지않고 무조건 한 번 실행한 뒤에, 마지막에 검사한다.

let remaining = totalBet;
do{
    let bet = rand(1, remaining);
    let face = randFace();
    bets[face] = bets[face] + bet;
    remaining = remaining - bet;
}while(remaining > 0);

6. for 루프

이제 우리는 판돈까지 걸었다! 이제 주사위를 굴리면된다.

for루프가 가장 잘 어울리는 부분은 바로 어떤 일을 정해진 숫자만큼 반복하려고 할 때, 특히 그 일을 지금 몇 번째 하는지 알아야할 때이다. 우리는 주사위를 정해진 숫자만큼 굴려야 하고, 이제 우리는 for루프를 써야한다 이말이다.

for루프를 3 부분으로 나눠야한다. 초기화, 조건, 마지막 표현식이다.

const hand = [];
for(let roll = 0; roll < 3; roll++){
    hand.push(randFace());
}

7. if 문

자! 이제 돈도 걸고 주사위도 굴렸다! 남은 건 딴 돈을 가져오는 것!

hand배열에는 무작위로 선택된 그림face가 3 개 있다. 따라서 for루프를 한 번 더 써서 이 중에 맞춘 것이 있는지 알아봐야한다. 이때 if문을 사용해주자.

let winnings = 0;
for(let die = 0; die < hand.length; die++){
    let face = hand[die];
    if(bets[face] > 0) winnings = winnings + bets[face];
}
funds = funds + winnings;

8. 하나로 합치기

합치는 건 쉽다.

// m이상 n이하의 무작위 정수를 반환
function rand(m, n) {
  return m + Math.floor((n - m + 1) * Math.random());
}

// 크라운 앤 앵커 게임의 여섯가지 도형 중 무작위 하나를 반환하는 함수
function randFace() {
  return ["crown", "anchor", "heart", "spade", "club", "diamond"][rand(0, 5)];
}

// 크라운 앤 앵커 게임과정을 js의 제어문으로 표현
let funds = 50; // 시작조건
let round = 0;

while (funds > 1 && funds < 100) {
  round++;
  console.log(`round ${round}:`);
  console.log(`\tstarting funds: ${funds}p`);
  // 돈을 건다.
  const bets = {
    crown: 0,
    anchor: 0,
    heart: 0,
    spade: 0,
    club: 0,
    diamond: 0
  };
  let totalBet = rand(1, funds);
  if (totalBet === 7) {
    totalBet = funds;
    bets.heart = totalBet;
  } else {
    // 해당 판에 걸 돈을 분배
    let remaining = totalBet;
    do {
      let bet = rand(1, remaining);
      let face = randFace();
      bets[face] = bets[face] + bet;
      remaining = remaining - bet;
    } while (remaining > 0);
  }
  funds -= totalBet;
  console.log(
    "\tbets: " +
      Object.keys(bets)
        .map(face => `${face}: ${bets[face]} pence`)
        .join(",") +
      `(total: ${totalBet} pence)`
  );

  // 주사위를 굴린다.
  const hand = [];
  for (let roll = 0; roll < 3; roll++) {
    hand.push(randFace());
  }
  console.log(`\thand: ${hand.join(", ")}`);
  // 그림을 맞췄으면, 돈을 가져온다.
  let winnings = 0;
  for (let die = 0; die < hand.length; die++) {
    let face = hand[die];
    if (bets[face] > 0) winnings = winnings + bets[face];
  }
  funds = funds + winnings;
  console.log(`\twinnings: ${winnings}`);
}
console.log(`\tending funds: ${funds}`);

댓글남기기