Step 289. ★ CTF #6: 중간 평가 대회 — 상위 50% 목표, 점수 구조를 읽는 팀이 배점을 주운다
Level 3 — CTF 대회 사이클 | 난이도 ★★★☆☆ | 예상 소요 시간 2일 (대회 참가 + 분석 반일)
전제: Step 279~288의 대회 3~5회와 복기-특훈 사이클 완료, 파이썬 3(스코어보드 분석기용).
- 준비물: 팀이 참가할 CTF 대회 1개, 팀 공유 문서(치트시트·복기 기록), 타이머, 파이썬 3. 이 챕터의 대회 장면은 화면 예시, 스코어보드 분석기 실행은 실측(2026-09-09, Python 3.12)으로 표시했습니다.
- ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
- 이 챕터는 평가 챕터입니다 — 새 기법이 아니라, 지금까지의 훈련이 점수로 환산되는지 재는 날입니다.
여섯 번째 대회는 성적표입니다. Step 279부터 다섯 번의 대회를 치르고, 매번 복기하고, 약점 유형을 특훈으로 메웠습니다. 그 사이클이 실전 점수로 환산되는지 확인하는 중간 결산이 오늘의 대회입니다.
목표는 상위 50%입니다. 이 숫자가 의미하는 것은 "Beginner 졸업"입니다 — 참가 팀의 절반은 대회 내내 한두 문제도 못 풀고 자리를 지키다 끝납니다. 그 절반을 확실히 넘었다는 것은, 팀의 루틴이 최소한의 실전 체계를 갖췄다는 객관적 신호입니다.
그리고 상위 50%를 노리려면 먼저 점수가 어떻게 매겨지는지 알아야 합니다. 같은 문제를 풀어도 언제 풀었는가, 몇 팀이 풀었는가에 따라 점수가 달라지는 대회가 있기 때문입니다. 오늘은 그 구조부터 분해합니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- 고정 배점과 다이내믹 스코어링(dynamic scoring)의 차이와 풀이 전략상의 의미를 설명한다
- 스코어보드 데이터에서 우리 팀의 순위·상위 %·커트라인까지의 거리를 계산한다
- "기본 점수 확보 → 특훈 유형 필수 득점 → Hard 도전"의 3단 운영 순서를 대회에 적용한다
- 대회 절반 시점에 순위를 확인하고 남은 시간의 배분을 조정한다
- 반년 전 첫 대회와의 비교 보고서로 절대 성장을 측정한다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | CTF 대회 플랫폼(CTFd류), 팀 공유 문서, 파이썬 3(분석기) |
| 오늘의 명령 | python step289_scoreboard.py — 순위·커트라인 계산 |
| 필요한 개념 | 다이내믹 스코어링, 상위 백분위, 분야 커버리지, 중간 점검 |
| 오늘의 산출물 | 최종 순위 기록 + 분야별 득점표 + 반년 비교 보고서 |
2-1. 점수 산출 구조 — 배점은 고정이 아닐 수 있다
CTF의 배점 방식은 크게 두 가지입니다.
고정 배점(static)은 문제마다 점수가 정해져 있고 누가 언제 풀든 같습니다. 100점 문제는 첫 풀이든 마지막 풀이든 100점입니다.
다이내믹 스코어링(dynamic scoring)은 푼 팀이 늘수록 배점이 내려갑니다. CTFd 플랫폼의 기본 공식은 대략 이렇습니다 — 최고 배점 500, 최소 배점 100, 감쇠(decay) 15일 때 풀이 수에 따른 배점을 실제로 계산해 봤습니다.
실측 (2026-09-09, Python 3.12 — 3-2의 스크립트 실행 결과 중 일부):
=== 다이내믹 스코어링: 풀이 수에 따른 배점 하락 ===
풀이 0팀 → 배점 500
풀이 1팀 → 배점 499
풀이 3팀 → 배점 484
풀이 5팀 → 배점 456
풀이 10팀 → 배점 323
풀이 15팀 → 배점 100
풀이 20팀 → 배점 100
읽는 법: 초반에는 천천히 떨어지다가 10팀을 넘으면 급락하고, 15팀 부근에서 최소 배점에 도달합니다. 전략상 의미는 명확합니다 — 많은 팀이 풀 것 같은 쉬운 문제는 빨리 풀수록 비쌉니다. 반대로 아무도 못 푸는 문제는 끝까지 고배점으로 남습니다. "쉬운 것부터"라는 평소 루틴이 다이내믹 대회에서는 점수 전략이기도 한 것입니다.
2-2. 상위 50%의 의미 — 커트라인은 점수가 아니라 순위다
"상위 50%"는 점수 목표가 아니라 순위 목표입니다. 40개 팀이면 20위, 200개 팀이면 100위가 커트라인입니다. 그래서 대회 중간에 확인해야 할 것은 우리 점수가 아니라 우리 순위와 커트라인 팀의 점수 차이입니다.
분포를 아는 것도 중요합니다. CTF 스코어보드는 보통 상위 소수가 점수를 쓸어가고, 중위권은 촘촘하고, 하위 절반은 저득점에 몰립니다. 이 구조에서는 중위권에서 문제 하나가 순위 다섯 칸입니다. 50점 차이로 20위와 25위가 갈리는 일이 흔합니다.
2-3. 중간 평가가 측정하는 것 — 사이클의 환산율
이 대회가 재는 것은 세 가지입니다.
| 측정 대상 | 확인 방법 | 기대 신호 |
|---|---|---|
| 복기 루틴의 효과 | 전회 대비 같은 유형의 재실패 여부 | 틀린 유형이 반복되지 않음 |
| 특훈의 환산 | 특훈한 약점 유형 문제의 득점 | 특훈 유형 문제 1개 이상 해결 |
| 운영의 안정성 | 시간 배분, 문제 선택의 일관성 | 기본 점수(쉬운 문제) 전수 확보 |
순위는 이 셋이 합쳐진 결과일 뿐입니다. 순위가 목표에 못 미쳐도 셋 중 무엇이 무너졌는지 알면 그것이 다음 사이클의 과제입니다. 반대로 순위만 달성했는데 셋이 엉망이었다면 — 운이 좋았던 것이고, 다음 대회에서 무너집니다.
2-4. 3단 운영 순서 — 점수는 위에서부터 쌓는다
중간 평가 대회의 운영 순서는 이렇게 고정합니다.
- 기본 점수 확보 — 전 분야의 최저 배점 문제부터 전수 확인. 쉬운 문제를 놓치는 것은 실력 문제가 아니라 운영 사고입니다.
- 특훈 유형 필수 득점 — Step 288에서 특훈한 유형의 문제가 출제됐다면 반드시 잡습니다. 특훈의 환산율을 재는 곳입니다.
- Hard 도전 — 위 둘을 확보한 후 남은 시간의 절반만 Hard에 씁니다. 나머지 절반은 풀다 만 문제의 마무리와 검산입니다.
이 순서가 무너지는 전형적인 패턴이 하나 있습니다 — 대회 초반에 Hard 문제에 매달려 기본 점수 수집이 늦어지는 것. 중간 평가는 화려한 한 방이 아니라 누락 없는 수확으로 통과합니다.
3. 따라 하기
3-1. 사전 점검 — 치트시트와 복기 기록을 공유한다
대회 전날, 팀 공유 문서에 두 가지를 올립니다.
공유 체크리스트 (대회 전날):
[ ] Step 288의 특훈 유형 치트시트 — 개념 → 도구 → 명령 → 함정 순서로 1페이지
[ ] 지난 5개 대회의 복기 기록 요약 — "우리가 자주 틀리는 것 TOP 3"
[ ] 대회 시간표 — 시작/중간 점검/종료 시각, 점심 시간대
[ ] 역할 확인 — 누가 어느 분야의 1차인가 (로테이션 실험은 다음 대회에서)
왜: 대회 중에 찾는 문서는 없는 것과 같습니다. 대회 중에는 검색할 시간이 없고, 있어도 집중을 깹니다. 전날의 1시간 준비가 대회 당일의 30분을 여러 번 아낍니다.
3-2. 스코어보드 분석기 — 순위를 숫자로 읽는다
대회 중간 점검과 종료 후에 쓸 분석기를 미리 만들어 둡니다. 아래 코드를 step289_scoreboard.py로 저장하세요.
# CTF 스코어보드 분석기 — 순위와 상위 % 계산
import math
def dynamic_value(maximum=500, minimum=100, decay=15, solves=0):
"""CTFd식 다이내믹 스코어링: 풀이 수가 늘수록 배점 하락"""
if solves == 0:
return maximum
value = (((minimum - maximum) / (decay ** 2)) * (solves ** 2)) + maximum
return math.ceil(max(value, minimum))
teams = { # 스코어보드를 베낀 데이터 — 실제 대회 것으로 교체
"alpha": 4310, "bravo": 3980, # ... (중략) ...
"우리팀": 1820, "uniform": 1750, # ... 총 40팀 ...
}
def report(scoreboard, my_team):
ranked = sorted(scoreboard.items(), key=lambda kv: kv[1], reverse=True)
n = len(ranked)
rank = next(i for i, (name, _) in enumerate(ranked, 1) if name == my_team)
print(f"참가 팀 수: {n}")
print(f"순위: {rank} / {n} → 상위 {rank / n * 100:.1f}%")
cutoff = math.ceil(n / 2)
median_score = ranked[cutoff - 1][1]
print(f"상위 50% 커트라인: {cutoff}위 (점수 {median_score})")
gap = median_score - scoreboard[my_team]
print(f"커트라인까지 부족한 점수: {gap}" if gap > 0
else f"커트라인 통과: +{-gap}점 여유")
python step289_scoreboard.py로 실행합니다.
실측 (2026-09-09, Python 3.12 — 40팀 예시 데이터):
참가 팀 수: 40
우리팀 점수: 1820
순위: 21 / 40 → 상위 52.5%
상위 50% 커트라인: 20위 (점수 1870)
커트라인까지 부족한 점수: 50
읽는 법: 이 예시의 팀은 아깝게 21위 — 상위 52.5%로 커트라인에 50점 모자랍니다. 2-2에서 말한 "중위권에서 문제 하나가 순위 다섯 칸"이 바로 이 장면입니다. 남은 시간에 100점짜리 misc 문제 하나라도 잡으면 통과인 상황 — 이 계산이 중간 점검 때 나와야 마지막 2시간의 방향이 정해집니다.
3-3. 대회 운영 — 3단 순서의 실행
대회가 시작되면 첫 30분은 전수 스캔입니다. 모든 문제의 제목·배점·분야·풀이 수를 표로 적습니다. 그다음 2-4의 순서대로 움직입니다.
화면 예시 (중간 점검 시점의 운영 표):
=== 대회 중간 점검 (24시간 중 12시간 경과) ===
현재: 21위 / 40팀, 1820점
커트라인(20위): 1870점 — 50점 부족
[확보 완료] web 3, crypto 2, rev 2, pwn 1 = 기본 점수 전수 완료
[진행 중] 특훈 유형 문제(web SQLi) — 팀원 A 담당, 70% 진척
[미착수] misc 2문제(각 100점) — 아무도 안 봄
[버림] Hard pwn(500점) — 풀이 0팀, 우리 역량 밖
조정: 특훈 문제 마무리 후 misc 2개로 100점 확보 → 커트라인 통과
Hard는 그 다음에 남는 시간만
읽는 법: 중간 점검의 산출물은 감상이 아니라 조정 결정입니다. "misc 미착수 → 100점 확보 가능 → 배정"처럼 남은 시간의 배분이 문장으로 나와야 합니다.
3-4. 종료 직후 — 분야별 득점표를 기록한다
종료되면 기억이 살아 있을 때 기록합니다. 분석기의 분야 표 기능을 쓰면 빠릅니다.
실측 (2026-09-09 — 예시 데이터로 실행):
분야 | 해결/출제 | 득점
-----|----------|-----
web | 3/5 | 600
crypto | 2/4 | 550
pwn | 1/4 | 300
rev | 2/4 | 370
forensic | 0/3 | 0
misc | 0/2 | 0
합계 득점: 1820
분야 커버리지: 4/6 분야
읽는 법: 득점보다 먼저 보는 것이 0점 분야입니다. forensic과 misc가 0 — 둘 다 출제됐는데 손도 못 댔다면 시간 운영의 문제, 봤는데 못 풀었다면 역량의 문제입니다. 이 구분이 다음 특훈 주제를 정합니다.
3-5. 반년 비교 보고서 — 순위가 아니라 성장을 본다
마지막 산출물입니다. 첫 대회(Step 279)의 기록과 나란히 놓습니다.
=== 반년 비교 보고서 (서식) ===
첫 대회 6회차 대회 변화
점수 320 1820 +1500
순위 58/70 (하위) 21/40 (상위 52.5%) 상위권 진입
푼 문제 수 2 8 4배
분야 커버리지 1/6 4/6 +3분야
반복 실패 유형 SQLi, 힙 (해소됨) 특훈 효과 확인
한 줄 결산: (예) "복기-특훈 사이클이 점수로 환산되기 시작했다.
다음 과제는 0점 분야(forensic) 개척"
왜: 순위는 대회마다 참가 수준이 달라 흔들립니다. 이번에 상위 50%를 못 넘었어도 점수·문제 수·커버리지가 전부 우상향이면 사이클은 정상 작동 중입니다. 진짜 지표는 "전회 대비 우리의 절대 성장" — 소재 원문의 지적 그대로입니다.
4. 미션과 연습문제
미션 — 중간 평가 대회 완주와 비교 보고서
- 팀이 참가할 대회를 정하고, 전날에 치트시트·복기 요약·시간표를 공유 문서에 올립니다.
- 3-2의 분석기를 팀 환경에 맞게 만들어 둡니다 — 스코어보드를 베끼는 방법(복사 또는 정기 캡처)까지 정합니다.
- 대회를 2-4의 3단 순서로 운영합니다. 절반 시점에 중간 점검을 하고 조정 결정을 문장으로 남깁니다.
- 종료 후 분야별 득점표를 기록하고, 0점 분야의 원인(시간/역량)을 구분합니다.
- 첫 대회와의 비교 보고서를 작성합니다 — 점수/순위/문제 수/커버리지 4개 지표 필수.
- 상위 50% 진입 여부를 기록합니다 — 미달성이면 측정 대상 3개(2-3) 중 무엇이 무너졌는지 원인 분석으로 대체합니다.
연습문제
문제 1. 다이내믹 스코어링 대회에서 "쉬운 문제를 빨리 푸는 것"이 점수 전략이 되는 이유를, 배점 하락 곡선의 관점에서 설명해 보세요.
문제 2. 중간 점검에서 확인해야 할 두 숫자는 "우리 점수"와 "우리 순위"가 아니라 다른 조합이라고 했습니다. 무엇이며, 왜 그 조합이어야 하나요?
문제 3. 중간 평가가 측정하는 세 가지(복기 효과·특훈 환산·운영 안정성) 중 하나만 무너진 대회가 있었다고 합시다 — 특훈 유형 문제가 출제됐는데 못 풀었습니다. 다음 사이클의 과제는 무엇이 되어야 하나요?
문제 4. 소재의 지적 — "순위에 일희일비하지 말 것, 진짜 지표는 전회 대비 절대 성장" — 은 어떤 함정을 막기 위한 것인가요? 순위만 보고 사이클을 평가하면 어떤 오판이 생기나요?
5. 모범 답안과 완료 기준
미션 모범 답안
검증 기준으로 확인하세요.
- 사전 공유의 흔적: 대회 시작 전 시각에 치트시트·복기 요약이 공유 문서에 올라와 있는가 — 대회 중에 쓴 문서는 사전 점검이 아닙니다.
- 중간 점검의 산출물: "misc 미착수 → 배정" 같은 조정 결정이 문장으로 남아 있는가. 순위만 캡처하고 결정이 없으면 점검이 아니라 구경입니다.
- 3단 순서의 준수: 기본 점수(최저 배점 전수)가 Hard 도전보다 먼저 처리됐는가 — 로그의 시간 순서로 확인합니다.
- 득점표의 완결: 분야별 해결/출제/득점과 커버리지가 표로 있고, 0점 분야의 원인 구분이 있는가.
- 비교 보고서: 4개 지표가 첫 대회와 나란히 있고, "한 줄 결산"이 다음 과제를 가리키는가.
- 목표 판정: 상위 50% 진입 또는 원인 분석 문서 — 둘 중 하나는 반드시 있어야 합니다. "아쉬웠다"는 문장은 원인 분석이 아닙니다.
연습문제 해답
문제 1 해답. 풀이 수가 늘수록 배점이 내려가므로, 많은 팀이 풀 문제는 늦게 풀수록 손해이기 때문입니다. 3-2의 실측에서 500점 문제는 10팀이 풀면 323점, 15팀이면 100점이 됩니다. 쉬운 문제는 전 팀이 풀 것이므로 하락이 확정된 문제 — 빨리 풀수록 높은 배점에서 고정됩니다. 반대로 어려운 문제는 풀이 수가 안 늘어 끝까지 고배점이 유지되므로, 서두를 이유가 없습니다.
문제 2 해답. "우리 순위"와 "커트라인 팀의 점수"입니다. 상위 50%는 점수 목표가 아니라 순위 목표이므로, 점수의 절대값은 의미가 없고 커트라인과의 거리가 의미입니다. 50점 부족인지 50점 여유인지에 따라 남은 시간의 배분이 갈립니다 — 부족하면 저배점 문제라도 긁어야 하고, 여유가 있으면 Hard에 걸 수 있습니다.
문제 3 해답. 특훈의 환산이 무너진 것이므로, 과제는 특훈의 방식 재점검입니다. 가능한 원인은 ① 특훈 10문제가 대회 출제 경향과 어긋났다(문제 수집의 문제), ② 풀 수 있었는데 시간 배분에서 밀렸다(운영의 문제), ③ 특훈이 패턴 암기에 그쳐 변형에 무너졌다(깊이의 문제). ③이면 치트시트의 "개념" 칸을 두껍게 하는 방향으로 다음 특훈을 설계합니다.
문제 4 해답. 대회마다 참가 수준이 달라 순위는 외생 변수에 흔들린다는 것을 막기 위한 것입니다. 강팀이 몰린 대회에서 하락한 순위는 실력 퇴보가 아닐 수 있고, 약팀 대회의 상승은 성장이 아닐 수 있습니다. 순위만 보면 정상 작동하는 사이클을 버리거나, 무너진 사이클을 유지하는 오판이 생깁니다. 점수·문제 수·커버리지의 절대 비교가 있어야 판정이 흔들리지 않습니다.
완료 기준 체크리스트
- [ ] 대회 전날 치트시트·복기 요약·시간표를 팀에 공유했다
- [ ] 스코어보드 분석기로 순위·상위 %·커트라인 거리를 계산할 수 있다
- [ ] 3단 운영 순서(기본 점수 → 특훈 유형 → Hard)를 적용했다
- [ ] 대회 절반 시점에 중간 점검과 조정 결정을 문장으로 남겼다
- [ ] 분야별 득점표와 0점 분야 원인 구분을 기록했다
- [ ] 첫 대회와의 4개 지표 비교 보고서를 작성했다
- [ ] 상위 50% 진입 여부를 기록했다 (미달 시 원인 분석 포함)
6. 흔한 실수와 해결
벽 1. 대회 초반에 Hard 문제를 잡고 싶은 유혹을 못 이겨요
증상: 500점 문제가 너무 풀고 싶어서 쉬운 문제 수집이 늦어집니다.
원인: Hard 해결의 성취감이 크고, 쉬운 문제는 "언제든 풀 수 있다"는 착각이 있습니다.
해결: 다이내믹 스코어링에서는 그 착각이 곧 손해입니다 — 쉬운 문제의 배점은 기다리는 동안 떨어집니다. 그리고 Hard는 남는 시간의 절반만 쓰는 규칙이 있으니, 욕심은 3단계로 미루세요. 순서를 지키는 것이 실력입니다.
벽 2. 중간 점검을 했는데 아무 결정도 안 나왔어요
증상: "지금 21위네요"에서 끝. 이후 운영이 그대로입니다.
원인: 점검 양식이 없어서 확인이 감상으로 끝났습니다.
해결: 3-3의 표를 양식으로 고정하세요 — 현재 순위, 커트라인과의 거리, 미착수 문제 목록, 그리고 마지막 줄에 반드시 "조정:" 으로 시작하는 문장 하나. 조정 문장이 안 써지면 정보가 부족한 것이니 미착수 문제라도 다시 훑습니다.
벽 3. 스코어보드가 실시간이라 정신이 없어요
증상: 순위 변동을 계속 새로고침하며 문제에 집중하지 못합니다.
원인: 스코어보드는 확인 시점이 정해져 있지 않으면 무한히 봅니다.
해결: 확인 시각을 미리 고정하세요 — 시작 후 2시간, 중간 점검, 종료 2시간 전의 세 번이면 충분합니다. 그 사이에는 스코어보드 탭을 닫습니다. 여러분의 점수는 스코어보드를 볼 때가 아니라 문제를 풀 때 오릅니다.
벽 4. 상위 50%에 50점 차로 떨어졌는데 팀 분위기가 가라앉았어요
증상: "반년 했는데 이것밖에 안 되나" 하는 말이 나옵니다.
원인: 순위 하나로 반년을 판정했습니다.
해결: 3-5의 비교 보고서를 펼치세요. 점수·문제 수·커버리지가 전부 우상향이었다면 사이클은 정상이고, 50점은 "misc 미착수" 같은 운영 사고 하나의 값입니다. 다음 대회에서 회수 가능한 점수입니다. 반대로 지표가 정체라면 — 그때는 순위가 아니라 사이클을 수술해야 합니다. 어느 쪽이든 감정이 아니라 표가 판정합니다.
벽 5. 분석기를 만들었는데 스코어보드를 어떻게 베낄지 몰라요
증상: 플랫폼 화면을 어떻게 데이터로 옮기는지 막힙니다.
원인: 대회 플랫폼마다 형식이 다르고, API가 열려 있지 않은 곳도 많습니다.
해결: 수동이 정답입니다 — 커트라인 근처 5팀과 우리 팀의 점수만 손으로 옮겨도 중간 점검 계산은 됩니다. 전체 순위 계산이 필요하면 스코어보드 페이지를 통째로 복사해 텍스트 에디터에서 팀명: 점수 형태로 다듬으세요. 정교한 자동 수집은 대회가 끝난 뒤의 취미이지, 대회 중의 필수가 아닙니다.
7. 정리
오늘의 개념
| 개념 | 한 줄 설명 |
|---|---|
| 다이내믹 스코어링 | 풀이 수가 늘수록 배점 하락 — 쉬운 문제는 빨리 풀수록 비싸다 |
| 상위 50% | 점수 목표가 아니라 순위 목표 — 커트라인과의 거리로 운영한다 |
| 3단 운영 순서 | 기본 점수 전수 → 특훈 유형 필수 → Hard(남은 시간의 절반) |
| 중간 점검 | 순위 확인이 아니라 조정 결정을 내리는 행사 |
| 분야 커버리지 | 0점 분야의 유무가 시간 운영과 역량 공백을 드러낸다 |
| 절대 성장 | 순위는 대회마다 흔들린다 — 전회 대비 4개 지표가 진짜 성적표 |
오늘의 도구·서식
| 도구·서식 | 하는 일 |
|---|---|
| 스코어보드 분석기 | 순위·상위 %·커트라인 거리의 즉시 계산 |
| 사전 공유 체크리스트 | 대회 중 검색을 없애는 전날 1시간 |
| 중간 점검 운영 표 | 감상을 "조정:" 문장으로 바꾸는 양식 |
| 분야별 득점표 | 0점 분야의 원인(시간/역량)을 구분하는 표 |
| 반년 비교 보고서 | 순위가 아니라 성장으로 사이클을 판정하는 문서 |
명령어보다 중요한 감각
중간 평가의 진짜 산출물은 순위가 아니라 판정 능력입니다. 커트라인까지 50점이라는 문장을 대회 도중에 스스로 계산해 낼 수 있는 팀은, 이기든 지든 다음 수를 압니다. 그 계산이 없는 팀은 대회가 끝난 뒤에야 결과를 알고, 그때는 바꿀 수 있는 것이 아무것도 없습니다.
그리고 기억하세요 — 상위 50%는 도착지가 아니라 졸업장입니다. Beginner 구간을 나갔다는 신호일 뿐, 사이클 자체는 계속 돕니다. 다음 두 스텝(복기와 라이브러리 정리)이 이 대회의 점수를 자산으로 바꾸는 과정입니다.
전부 체크되면 Step 289 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.