본문으로 건너뛰기

도장 계산기 만들기

자바스크립트 목차반복레슨 25 / 76

목차

도장 계산기는 12일 동안 하루 한 잔씩 도장을 찍다가, 도장이 열 개가 되는 날 무료 한 잔을 알리고 도장을 0으로 되돌리는 9줄 프로그램입니다. 1~5단원에서 배운 이름 붙이기 · 템플릿 문자열 · 조건 · 반복을 한 프로그램에 모아 처음부터 끝까지 만듭니다.

지금까지는 짧은 코드를 읽고 빈칸을 채웠습니다. 이번에는 할 일을 하위 목표 넷으로 나누고 하나씩 코드로 옮겨, 쓸모 있는 프로그램 하나를 끝까지 조립합니다. 폰으로 보고 있다면 확인 문제의 순서 맞추기로 조립하고, 컴퓨터가 있다면 직접 쳐서 돌려 봅니다.

55단계 중 1단계. 12일 동안 하루 한 잔씩 도장을 찍습니다. 하위 목표 넷을 차례로 따라갑니다.

1무엇을 만드나 — 하위 목표 넷

만들 계산기가 하는 일을 실행 모습으로 먼저 정합니다. 12일 동안 날마다 한 잔씩 마시면 이렇게 찍혀야 합니다.

10일 무료
도장 2개

10일째에 도장이 열 개가 되어 무료 한 잔을 받고, 11일 · 12일에 다시 찍은 도장 둘이 남습니다. 이 일을 하위 목표 넷으로 나눕니다.

하위 목표하는 일몇 번
1. 도장을 0으로도장 수 stamps를 0에 붙인다한 번
2. 날마다 하나 찍기날마다 stamps에 1을 더한다날마다
3. 열 개면 무료·0으로도장이 10이면 무료인 날을 찍고 0으로 되돌린다날마다 본다
4. 끝나고 쓰기남은 도장 수를 찍는다한 번

2 · 3은 날마다 되풀이하고 1 · 4는 한 번씩입니다. 날 수가 12로 정해져 있으니 for로 되풀이합니다. 날을 세는 이름은 day가 읽기 좋지만, 그러면 반복 머리가 폰 화면 폭을 넘어서 반복을 세는 이름으로 흔히 쓰는 i를 씁니다. i는 며칠째인지 받는 걸음꾼이고, stamps는 도장을 모으는 값입니다.

2날마다 하나 찍기

하위 목표 1 · 2와 4를 먼저 쓰고 돌려 봅니다.

let stamps = 0;
for (let i = 1; i <= 12; i++) {
  stamps = stamps + 1;
}
console.log(`도장 ${stamps}개`);
실행 결과
도장 12개

합 모으기와 세기의 틀과 같은 꼴이라, 12일 동안 하나씩 모여 12가 됐습니다. 이제 열 개가 되는 날을 골라내야 합니다.

3열 개면 무료·0으로

하위 목표 3을 반복 안, 도장을 찍은 바로 다음에 넣으면 계산기가 완성됩니다.

let stamps = 0;
for (let i = 1; i <= 12; i++) {
  stamps = stamps + 1;
  if (stamps === 10) {
    console.log(`${i}일 무료`);
    stamps = 0;
  }
}
console.log(`도장 ${stamps}개`);
실행 결과
10일 무료
도장 2개

4번 줄은 날마다 도장이 10인지 봅니다. 10이면 5번 줄이 그날을 찍고, 6번 줄이 도장을 0에 다시 붙입니다. 그래서 11일부터 도장을 다시 1부터 셉니다. 열째 날 한 바퀴만 추적 표로 따라가면 이렇습니다.

줄바뀐 이름값출력
2i10
2조건 i <= 12true
3stamps10
4조건 stamps === 10true
510일 무료
6stamps0

이 9줄에 1~5단원에서 배운 도구가 모두 들었습니다.

예제

하위 목표 주석을 단 완성본

하위 목표마다 주석 머리줄을 달면 코드를 다시 읽을 때 어디서 무엇을 하는지 바로 보입니다. 이번에는 날 수를 25로 바꿨습니다. 몇 줄이 무엇으로 찍힐지 정한 뒤 펼쳐 보세요.

// 1. 도장을 0으로
let stamps = 0;
// 2. 날마다 하나 찍기
for (let i = 1; i <= 25; i++) {
  stamps = stamps + 1;
  // 3. 열 개면 무료·0으로
  if (stamps === 10) {
    console.log(`${i}일 무료`);
    stamps = 0;
  }
}
// 4. 끝나고 쓰기
console.log(`도장 ${stamps}개`);
실행 결과 보기
실행 결과
10일 무료
20일 무료
도장 5개

예상과 다르면 그곳이 배울 곳입니다. 10일에 0으로 되돌린 도장이 20일에 다시 열 개가 되어 무료가 두 번이고, 21일부터 25일까지 찍은 다섯 개가 남습니다. 날 수를 바꿔도 코드는 그대로입니다.

과목 끝의 할 일 앱에서도 남은 할 일의 개수를 세고(세기 틀), 끝낸 일이 하나라도 있는지 찾습니다(찾으면 멈추기). 개수가 틀리면 값을 찍어 보며 고칩니다.

자주 틀리는 곳

틀린 생각: 열 개가 차면 도장은 저절로 0으로 돌아간다.

카드에 도장 열 칸이 다 차면 새 카드를 받으니, 프로그램도 알아서 다시 셀 것 같습니다. 자바스크립트는 쓴 줄만 실행합니다.

3절 코드에서 0으로 되돌리는 6번 줄을 뺐습니다.

let stamps = 0;
for (let i = 1; i <= 12; i++) {
  stamps = stamps + 1;
  if (stamps === 10) {
    console.log(`${i}일 무료`);
  }
}
console.log(`도장 ${stamps}개`);
실행 결과
10일 무료
도장 12개

도장이 11, 12로 계속 늘어 남은 도장이 12개입니다. 날 수가 25라면 20일에도 다시 걸리지 않습니다. 거꾸로 stamps = 0;을 if 덩어리 밖(닫는 중괄호 다음)에 두면 날마다 0이 되어 무료는 한 번도 찍히지 않고 도장 0개가 찍힙니다.

맞는 규칙: 0으로 되돌리는 일도 쓴 줄이 있어야 일어나고, 그 줄이 든 덩어리가 실행될 때만 일어납니다. 열 개인 날에만 되돌리도록 if 덩어리 안에 씁니다(규칙 4).

틀린 생각: 도장을 0으로 두는 줄은 반복 안에 둬도 된다.

처음에 한 번 0으로 두는 일이라 어디에 두든 같아 보입니다. 그러나 let stamps = 0;을 반복의 중괄호 안(3번 줄 위)으로 옮기면 바퀴마다 새 stamps가 0에서 시작해 열 개에 닿지 못합니다. 반복이 끝나면 stamps도 사라져 마지막 줄에서 stamps is not defined⁠로 멈춥니다.

맞는 규칙: 날마다 이어서 모을 이름은 반복 앞에서 한 번 만듭니다. 반복 안에서 let으로 만든 이름은 그 중괄호 안에서만 삽니다(규칙 4).

틀린 생각: '열 개면'은 stamps > 10으로 써도 된다.

'열 개가 넘으면'과 '열 개면'은 말로는 비슷합니다. 그러나 > 연산자는 같을 때를 빼서, 도장이 11개가 된 날에야 걸립니다.

3절 코드의 4번 줄을 if (stamps > 10) {로 바꾸면 11일 무료와 도장 1개가 찍힙니다. 무료가 하루 늦어졌습니다.

맞는 규칙: 정확히 열 개인 날을 고르려면 stamps === 10처럼 === 연산자로 견줍니다. > 연산자는 같을 때 false입니다.

확인 문제

1. 3절 계산기를 다섯 개마다 무료로 바꿨습니다(4번 줄). 무엇이 찍히는지 줄마다 그대로 쓰세요.

let stamps = 0;
for (let i = 1; i <= 12; i++) {
  stamps = stamps + 1;
  if (stamps === 5) {
    console.log(`${i}일 무료`);
    stamps = 0;
  }
}
console.log(`도장 ${stamps}개`);
힌트

0으로 되돌린 뒤 다시 다섯 개가 차는 날이 12일 안에 또 있는지 봅니다.

정답
실행 결과
5일 무료
10일 무료
도장 2개

5일에 0으로 되돌린 도장이 10일에 다시 다섯 개가 됩니다. 11일 · 12일의 두 개가 남습니다.

흔한 오답은 5일 무료 한 줄만 쓰는 것입니다. 0으로 되돌린 뒤 다시 다섯 개가 차는 10일을 놓쳤습니다.

2. 계산기를 하위 목표 단위로 조립합니다.

(가) 하위 목표 넷의 차례가 섞였습니다. 처음부터 차례로 기호를 늘어놓으세요.

  • ㉠ 끝나고 쓰기
  • ㉡ 날마다 하나 찍기
  • ㉢ 도장을 0으로
  • ㉣ 열 개면 무료·0으로

(나) 반복 덩어리 안의 다섯 줄이 섞였습니다. 들여쓰기는 지웠으니 중괄호 줄로 덩어리를 가르세요. 차례로 기호를 늘어놓으세요.

㉠ stamps = 0;
㉡ stamps = stamps + 1;
㉢ if (stamps === 10) {
㉣ }
㉤ console.log(`${i}일 무료`);

(다) (가)·(나)를 다 놓은 뒤에 아래 '놓은 뒤 물음'을 펼쳐 고르세요.

힌트

(가)는 1절의 표를 떠올립니다. (나)는 '찍기'가 '보기'보다 먼저입니다 — 도장을 찍은 뒤에 열 개인지 봅니다.

놓은 뒤 물음

(나)에서 ㉠ stamps = 0;을 if 덩어리 안에 두는 까닭을 고르세요.

  • ① 도장이 열 개인 날에만 0으로 되돌려야 하기 때문
  • ② if 덩어리 밖에 두면 오류가 나기 때문
  • ③ 반복이 다 끝난 뒤에 0으로 만들어야 하기 때문
정답

(가) ㉢ ㉡ ㉣ ㉠ — 도장을 0으로 · 날마다 하나 찍기 · 열 개면 무료·0으로 · 끝나고 쓰기입니다.

(나) ㉡ ㉢ ㉤ ㉠ ㉣입니다. ㉤과 ㉠은 바꿔도 같은 결과입니다 — 5번 줄이 도장 수를 쓰지 않습니다. ㉡을 ㉢보다 뒤에 두면 10일에 도장이 아직 9라 무료가 하루 늦어집니다.

(다) ①입니다.

  • ② if 밖에 두어도 오류는 나지 않습니다. 날마다 0이 되어 무료가 한 번도 찍히지 않을 뿐입니다.
  • ③ 반복이 끝난 뒤의 일은 닫는 중괄호 밖에 씁니다. 되돌리기는 열 개인 날마다 해야 합니다.

3. 책 읽기 기록입니다. 9일 동안 하루 한 권씩 읽고, 네 권마다 선물을 받으려 합니다. 4일 선물 · 8일 선물 · 남은 책 1권이 찍혀야 하는데 이렇게 찍혔습니다. 몇 번 줄을 어떻게 고쳐야 할까요?

let books = 0;
for (let i = 1; i < 10; i++) {
  books = books + 1;
  if (books > 4) {
    console.log(`${i}일 선물`);
    books = 0;
  }
}
console.log(`남은 책 ${books}권`);
실행 결과
5일 선물
남은 책 4권
힌트

4번 줄의 조건이 books가 4일 때 true인지 봅니다.

정답

4번 줄을 if (books === 4) {로 고치면 바라는 세 줄이 찍힙니다.

books > 4는 4일 때 false라서 다섯 권째(5일)에야 선물이 나갔습니다. 0으로 되돌린 뒤 9일까지 네 권이 다시 쌓였지만, 다섯 권이 되기 전에 반복이 끝났습니다.

다르게 고쳐도 되는 곳: books >= 4도 같은 세 줄을 찍습니다(4에서 0으로 되돌려 4를 넘지 않으므로).

흔한 오답은 6번 줄을 지우는 것입니다. 그러면 5일부터 날마다 선물이 찍힙니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 3절 코드(아홉 줄)를 main.js에 저장해 돌립니다. 그다음 무료 잔 수를 세는 이름 free를 더해 끝에 무료 1잔도 찍도록 고쳐 봅니다. 세기 틀대로 반복 앞에서 0에 붙이고, if 덩어리 안에서 1을 더하고, 끝에서 찍습니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로