14. 작은 프로그램 만들기
지금까지 배운 것을 모아 성적표, 숫자 맞히기, 할 일 목록을 처음부터 만들어 봐요.
이 장에서 배울 것
- 만들고 싶은 것을 작은 조각으로 나누는 법
- 조각을 하나씩 만들고 실행해 보면서 조금씩 키우는 법
- 세 가지 작은 프로그램: 성적표, 숫자 맞히기, 할 일 목록
프로그램은 한 번에 만들지 않아요
처음부터 끝까지 한 번에 써 내려가는 사람은 거의 없어요. 대부분 이렇게 만들어요.
- 무엇을 만들지 말로 적어 본다.
- 그것을 작은 조각으로 나눈다.
- 가장 쉬운 조각부터 만들고 바로 실행해 본다.
- 잘 되면 다음 조각을 붙인다.
조각마다 실행해 보면 오류가 나도 방금 고친 몇 줄만 보면 되니까 찾기 쉬워요. 이 장의 예제도 단계마다 실행 버튼을 눌러 보면서 따라와 보세요.
1. 성적표 만들기
만들 것: 학생들의 점수를 보고 각자의 등급과 반 평균, 1등을 알려 주는 프로그램이에요.
조각 나누기
- 점수를 담아 둔다 → 사전 (7장)
- 점수로 등급을 정한다 → 조건문 (5장) + 함수 (9장)
- 학생마다 출력한다 → 반복문 (8장)
- 평균과 1등을 구한다 → 반복하면서 합계와 가장 큰 값 기억하기
1단계: 등급 함수
가장 작은 조각부터 만들어요. 점수를 받아서 등급 글자를 돌려주는 함수예요. 만들고 나면 몇 가지 점수로 시험해 봐요.
<등급>을 만들자 ('점수'):
만약 ('점수'가 90 이상이다) 라면:
"A"를 돌려주자
그렇지 않고 만약 ('점수'가 80 이상이다) 라면:
"B"를 돌려주자
그렇지 않고 만약 ('점수'가 70 이상이다) 라면:
"C"를 돌려주자
"D"를 돌려주자
(<등급>(95))를 출력하자
(<등급>(80))를 출력하자
(<등급>(42))를 출력하자
A, B, D가 나오면 성공이에요. 경계에 있는 값(80처럼 딱 기준인 점수)을 꼭 넣어 보세요. 실수가 가장 많이 숨어 있는 곳이에요.
마지막
"D"를 돌려주자앞에그렇지 않다면:이 없어도 돼요. 앞에서돌려주자를 만나면 그 자리에서 함수가 끝나니까, 여기까지 왔다는 건 70점 미만이라는 뜻이에요.
2단계: 학생마다 출력하기
이제 점수를 사전에 담고, 학생마다 반복하면서 1단계의 함수를 써요.
<등급>을 만들자 ('점수'):
만약 ('점수'가 90 이상이다) 라면:
"A"를 돌려주자
그렇지 않고 만약 ('점수'가 80 이상이다) 라면:
"B"를 돌려주자
그렇지 않고 만약 ('점수'가 70 이상이다) 라면:
"C"를 돌려주자
"D"를 돌려주자
'성적'을 {"민지": 92, "서준": 78, "하은": 85, "도윤": 64}로 정하자
'성적'의 '이름'마다 반복하자:
'점수'를 '성적'의 '이름'으로 정하자
틀"{'이름'}: {'점수'}점 ({<등급>('점수')})"를 출력하자
3단계: 평균과 1등
반복하면서 두 가지를 기억해 둬요.
'합계': 점수를 계속 더해요. 다 돌면 학생 수로 나누면 평균이에요.'최고점'과'1등': 지금까지 본 점수보다 크면 바꿔 둬요.
<등급>을 만들자 ('점수'):
만약 ('점수'가 90 이상이다) 라면:
"A"를 돌려주자
그렇지 않고 만약 ('점수'가 80 이상이다) 라면:
"B"를 돌려주자
그렇지 않고 만약 ('점수'가 70 이상이다) 라면:
"C"를 돌려주자
"D"를 돌려주자
'성적'을 {"민지": 92, "서준": 78, "하은": 85, "도윤": 64}로 정하자
'합계'를 0으로 정하자
'인원'을 0으로 정하자
'최고점'을 0으로 정하자
'1등'을 ""으로 정하자
"===== 성적표 ====="을 출력하자
'성적'의 '이름'마다 반복하자:
'점수'를 '성적'의 '이름'으로 정하자
틀"{'이름'}: {'점수'}점 ({<등급>('점수')})"를 출력하자
'합계'에 '점수'를 더하자
'인원'에 1을 더하자
만약 ('점수'가 '최고점'보다 크다) 라면:
'최고점'을 '점수'로 정하자
'1등'을 '이름'으로 정하자
"=================="을 출력하자
틀"반 평균: {'합계' / '인원'}점"을 출력하자
틀"1등: {'1등'} ({'최고점'}점)"을 출력하자
'인원'을 따로 세는 이유는 사전에는 '길이'가 없기 때문이에요(7장).
더 해 보기: 학생을 한 명 더 넣어 보세요. 코드는 하나도 안 고쳐도 성적표가 알아서 길어져요. 이게 반복문과 함수로 나눠 만든 덕분이에요.
2. 숫자 맞히기 게임
만들 것: 컴퓨터가 1부터 100 사이의 수를 하나 정하면, 사용자가 맞힐 때까지 추측해요. 틀릴 때마다 “더 커요” / “더 작아요”라고 알려 주고, 맞히면 몇 번 만에 맞혔는지 알려 줘요.
조각 나누기
- 정답 정하기 →
[무작위]의<정수>(11장) - 추측 받기 →
입력받자(2장) - 비교해서 알려 주기 → 조건문
- 맞힐 때까지 계속 →
동안 반복하자(8장) - 횟수 세기 → 반복할 때마다 1 더하기
1단계: 입력 없이 규칙부터
입력을 받으면 실행할 때마다 직접 쳐야 해서 시험하기 번거로워요. 그래서 정답을 고정하고, 추측도 목록에 미리 적어 두고 규칙부터 확인해요.
'정답'을 42로 정하자
'추측들'을 [50, 25, 37, 43, 40, 42]로 정하자
'횟수'를 0으로 정하자
'추측들'의 '추측'마다 반복하자:
'횟수'에 1을 더하자
만약 ('추측'이 '정답'보다 작다) 라면:
틀"{'추측'}: 더 커요!"를 출력하자
그렇지 않고 만약 ('추측'이 '정답'보다 크다) 라면:
틀"{'추측'}: 더 작아요!"를 출력하자
그렇지 않다면:
틀"{'추측'}: 정답! {'횟수'}번 만에 맞혔어요."를 출력하자
반복을 끝내자
'추측들'의 숫자를 바꿔 가며 “더 커요”와 “더 작아요”가 맞게 나오는지 확인해 보세요. 규칙이 맞으면 이제 진짜 입력으로 바꾸기만 하면 돼요.
2단계: 진짜 게임
바뀐 곳은 세 군데예요.
- 정답을
<정수>(1, 100)으로 뽑아요. - 목록 대신
동안 반복하자로 맞힐 때까지 돌아요.'맞혔다'가거짓인 동안 계속해요. - 추측을
[숫자]로 입력받자로 받아요.
[무작위]에서 <정수>를 가져오자
'정답'을 <정수>(1, 100)으로 정하자
'횟수'를 0으로 정하자
'맞혔다'를 거짓으로 정하자
"1부터 100 사이의 수를 하나 정했어요. 맞혀 보세요!"를 출력하자
('맞혔다'가 거짓과 같다)인 동안 반복하자:
"추측: "을 이어출력하자
'추측'을 [숫자]로 입력받자
'횟수'에 1을 더하자
만약 ('추측'이 '정답'보다 작다) 라면:
"더 커요!"를 출력하자
그렇지 않고 만약 ('추측'이 '정답'보다 크다) 라면:
"더 작아요!"를 출력하자
그렇지 않다면:
틀"정답! {'횟수'}번 만에 맞혔어요."를 출력하자
'맞혔다'를 참으로 정하자
실행 버튼을 누르면 결과 칸에 입력 칸이 생겨요. 반씩 나눠 가며(50 → 25 또는 75 → …) 추측하면 7번 안에 꼭 맞힐 수 있어요.
3단계: 튼튼하게 만들기
지금은 숫자 대신 글자를 넣으면 프로그램이 오류로 멈춰요. 10장의 안전망으로 감싸면 다시 물어볼 수 있어요. 1부터 100 밖의 수도 걸러 볼게요.
[무작위]에서 <정수>를 가져오자
'정답'을 <정수>(1, 100)으로 정하자
'횟수'를 0으로 정하자
'맞혔다'를 거짓으로 정하자
"1부터 100 사이의 수를 하나 정했어요. 맞혀 보세요!"를 출력하자
('맞혔다'가 거짓과 같다)인 동안 반복하자:
"추측: "을 이어출력하자
'추측'을 0으로 정하자
일단 해보자:
'추측'을 [숫자]로 입력받자
오류가 발생했다면:
"숫자로 입력해 주세요."를 출력하자
만약 ('추측'이 1보다 작다) 또는 ('추측'이 100보다 크다) 라면:
"1부터 100 사이의 수만 돼요."를 출력하자
그렇지 않다면:
'횟수'에 1을 더하자
만약 ('추측'이 '정답'보다 작다) 라면:
"더 커요!"를 출력하자
그렇지 않고 만약 ('추측'이 '정답'보다 크다) 라면:
"더 작아요!"를 출력하자
그렇지 않다면:
틀"정답! {'횟수'}번 만에 맞혔어요."를 출력하자
'맞혔다'를 참으로 정하자
'추측'을 안전망 앞에서 먼저 0으로 정해 둔 것을 눈여겨보세요. 글자를 넣어 입력이 실패하면 '추측'은 0인 채로 남아서 “1부터 100 사이의 수만 돼요.“로 넘어가요. 오류가 발생했다면: 묶음 안에서 처음 정한 이름표는 그 묶음이 끝나면 사라지니까, 바깥에서 쓸 이름표는 바깥에서 먼저 정해 두는 게 안전해요. 잘못된 입력은 '횟수'에 세지 않아요.
3. 할 일 목록
만들 것: 할 일을 추가하고, 다 한 일을 표시하고, 목록을 보여 주는 프로그램이에요.
조각 나누기
- 할 일 하나 = “내용”과 “다 했는지”를 함께 담은 사전
- 할 일 전체 = 그 사전들을 담은 목록
- 추가하기 / 완료하기 / 보여 주기 = 각각 함수 하나씩
1단계: 데이터 모양 정하기
할 일 하나는 이렇게 생겼어요.
'할일'을 {"내용": "장보기", "완료": 거짓}으로 정하자
('할일'의 "내용")을 출력하자
('할일'의 "완료")를 출력하자
이런 사전을 목록에 여러 개 담으면 할 일 목록이 돼요. 무엇을 어떤 모양으로 담을지를 먼저 정해 두면 나머지 코드가 쉬워져요.
2단계: 함수 세 개
'목록'을 []로 정하자
<추가하기>를 만들자 ('내용'):
'목록'에 {"내용": '내용', "완료": 거짓}을 추가하자
틀"추가했어요: {'내용'}"을 출력하자
<완료하기>를 만들자 ('번호'):
만약 ('번호'가 1보다 작다) 또는 ('번호'가 '목록'의 '길이'보다 크다) 라면:
틀"{'번호'}번 할 일은 없어요."를 출력하자
돌려주자
'할일'을 '목록'의 '번호'번째로 정하자
'할일'의 "완료"를 참으로 정하자
틀"다 했어요: {'할일'의 "내용"}"을 출력하자
<보여주기>를 만들자 ():
만약 ('목록'의 '길이'가 0과 같다) 라면:
"할 일이 없어요."를 출력하자
돌려주자
'번호'를 1로 정하자
'목록'의 '할일'마다 반복하자:
'표시'를 "[ ]"로 정하자
만약 ('할일'의 "완료") 라면:
'표시'를 "[v]"로 정하자
틀"{'번호'}. {'표시'} {'할일'의 "내용"}"을 출력하자
'번호'에 1을 더하자
<보여주기>()를 실행하자
<추가하기>("장보기")를 실행하자
<추가하기>("숙제하기")를 실행하자
<추가하기>("방 청소")를 실행하자
<완료하기>(2)를 실행하자
<완료하기>(9)를 실행하자
<보여주기>()를 실행하자
눈여겨볼 곳:
- 함수 안에서 바깥의
'목록'을 읽고 바꿀 수 있어요(9장). '할일'을'목록'의'번호'번째로 정한 뒤'할일'의"완료"를 바꾸면, 목록 안의 그 사전도 바뀌어요. 사전은 복사되지 않고 같은 것을 함께 가리키니까요(7장).돌려주자만 쓰면 아무것도 돌려주지 않고 그 자리에서 함수를 끝내요. 잘못된 번호일 때 더 진행하지 않으려고 썼어요.
3단계: 명령으로 움직이기
이제 사용자가 추가 우유 사기, 완료 1, 보기, 끝 같은 명령을 입력하게 만들어요. 명령 글자를 <분리하기>(" ")로 쪼개면 첫 단어가 명령이에요(4장). 함수는 2단계와 같아요.
'목록'을 []로 정하자
<추가하기>를 만들자 ('내용'):
'목록'에 {"내용": '내용', "완료": 거짓}을 추가하자
틀"추가했어요: {'내용'}"을 출력하자
<완료하기>를 만들자 ('번호'):
만약 ('번호'가 1보다 작다) 또는 ('번호'가 '목록'의 '길이'보다 크다) 라면:
틀"{'번호'}번 할 일은 없어요."를 출력하자
돌려주자
'할일'을 '목록'의 '번호'번째로 정하자
'할일'의 "완료"를 참으로 정하자
틀"다 했어요: {'할일'의 "내용"}"을 출력하자
<보여주기>를 만들자 ():
만약 ('목록'의 '길이'가 0과 같다) 라면:
"할 일이 없어요."를 출력하자
돌려주자
'번호'를 1로 정하자
'목록'의 '할일'마다 반복하자:
'표시'를 "[ ]"로 정하자
만약 ('할일'의 "완료") 라면:
'표시'를 "[v]"로 정하자
틀"{'번호'}. {'표시'} {'할일'의 "내용"}"을 출력하자
'번호'에 1을 더하자
"명령: 추가 (내용) / 완료 (번호) / 보기 / 끝"을 출력하자
'계속'을 참으로 정하자
('계속'이 참과 같다)인 동안 반복하자:
"> "를 이어출력하자
'입력'을 입력받자
'단어들'을 '입력'의 <분리하기>(" ")로 정하자
'명령'을 '단어들'의 1번째로 정하자
'나머지'를 '입력'의 <자르기>('명령'의 '길이' + 2, '입력'의 '길이')로 정하자
만약 ('명령'이 "추가"와 같다) 라면:
<추가하기>('나머지')를 실행하자
그렇지 않고 만약 ('명령'이 "완료"와 같다) 라면:
일단 해보자:
<완료하기>(<숫자로>('나머지'))를 실행하자
오류가 발생했다면:
"번호를 숫자로 적어 주세요."를 출력하자
그렇지 않고 만약 ('명령'이 "보기"와 같다) 라면:
<보여주기>()를 실행하자
그렇지 않고 만약 ('명령'이 "끝"과 같다) 라면:
"안녕히 가세요!"를 출력하자
'계속'을 거짓으로 정하자
그렇지 않다면:
"모르는 명령이에요."를 출력하자
'나머지'는 명령 뒤의 글자 전부예요. 추가 우유 사기라면 "추가"(2글자) 다음의 띄어쓰기 한 칸을 건너뛰어 3번째 글자부터 끝까지, 즉 우유 사기가 돼요. <분리하기>로 쪼갠 단어를 다시 붙이지 않아도 돼서 편해요.
막혔을 때 써 볼 방법
- 중간 값 출력하기: 이상하다 싶은 이름표를 그 자리에서
출력하자로 찍어 보세요. 생각한 값과 다른 곳이 문제가 시작된 곳이에요. - 더 작게 줄이기: 코드 일부를 지우거나
(참고)로 막아 두고(줄 앞에(참고)를 붙이면 그 줄은 실행되지 않아요), 문제가 남는 가장 작은 모양을 찾아요. - 입력을 고정하기: 숫자 맞히기 1단계처럼 입력 대신 정해진 값으로 시험하면 같은 상황을 몇 번이고 다시 볼 수 있어요.
- 오류 메시지 읽기: 몇 번째 줄인지, 어떤 종류인지 알려 줘요. 종류별 뜻은 부록. 자주 만나는 오류에 있어요.
정리
| 단계 | 하는 일 |
|---|---|
| 말로 적기 | 무엇을 만들지 한두 문장으로 |
| 조각 나누기 | 데이터는 무엇에 담을지, 어떤 함수가 필요할지 |
| 작게 시작 | 가장 쉬운 조각부터, 만들 때마다 실행 |
| 입력은 나중에 | 정해진 값으로 규칙부터 확인하고 입력으로 바꾸기 |
| 튼튼하게 | 잘못된 입력을 안전망과 만약으로 거르기 |
연습 문제
1. 성적표에 꼴찌(가장 낮은 점수)도 출력해 보세요. 처음 값을 무엇으로 정해야 할지 생각해 보세요.
정답 예시
최저점의 처음 값은 어떤 점수보다도 커야 해요. 점수는 100점까지니까 101로 시작하면 돼요.
'성적'을 {"민지": 92, "서준": 78, "하은": 85, "도윤": 64}로 정하자
'최저점'을 101로 정하자
'꼴찌'를 ""으로 정하자
'성적'의 '이름'마다 반복하자:
만약 ('성적'의 '이름'이 '최저점'보다 작다) 라면:
'최저점'을 '성적'의 '이름'으로 정하자
'꼴찌'를 '이름'으로 정하자
틀"가장 낮은 점수: {'꼴찌'} ({'최저점'}점)"을 출력하자
2. 숫자 맞히기 1단계 코드에 “10번 안에 못 맞히면 끝”이라는 규칙을 더해 보세요. 추측 목록을 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 42]로 두고, 10번째에서 실패! 정답은 42.가 나오면 돼요.
정답 예시
'정답'을 42로 정하자
'추측들'을 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 42]로 정하자
'횟수'를 0으로 정하자
'추측들'의 '추측'마다 반복하자:
'횟수'에 1을 더하자
만약 ('추측'이 '정답'과 같다) 라면:
틀"정답! {'횟수'}번 만에 맞혔어요."를 출력하자
반복을 끝내자
만약 ('횟수'가 10과 같다) 라면:
틀"실패! 정답은 {'정답'}."를 출력하자
반복을 끝내자
만약 ('추측'이 '정답'보다 작다) 라면:
틀"{'추측'}: 더 커요!"를 출력하자
그렇지 않다면:
틀"{'추측'}: 더 작아요!"를 출력하자
정답 검사를 먼저 해야 10번째에 맞힌 경우도 “정답!“이 돼요.
3. 할 일 목록에 남은 할 일 개수를 세는 <남은개수> 함수를 만들어 보세요. 2단계 예제 끝에서 부르면 2가 나와야 해요.
정답 예시
'목록'을 [{"내용": "장보기", "완료": 거짓}, {"내용": "숙제하기", "완료": 참}, {"내용": "방 청소", "완료": 거짓}]으로 정하자
<남은개수>를 만들자 ():
'개수'를 0으로 정하자
'목록'의 '할일'마다 반복하자:
만약 ('할일'의 "완료"가 거짓과 같다) 라면:
'개수'에 1을 더하자
'개수'를 돌려주자
(<남은개수>())를 출력하자
여기까지 왔다면 하리로 꽤 많은 것을 만들 수 있어요. 비슷한 것을 여러 개 다루는 프로그램이 커지면 객체지향 문법이 코드를 정리하는 데 도움이 돼요. 파일을 읽고 쓰거나 실행 파일로 묶고 싶다면 Hana 런타임을 보세요.