Compare / Branch / Control

5주차 2교시: 조건문

원의 크기를 비교하고, 조건에 따라 색과 형태를 바꿉니다.

여섯 원의 크기를 조건으로 검사해 윤곽 원, 채운 원, 사각형으로 바꾸는 전후 관계의 개념 이미지
조건 적용의 개념 · 위는 입력 크기, 아래는 선택한 표현

크기에 따른 색과 형태

핵심 개념
비교식, 조건문, 경계값
이전 학습
좌표·팔레트·반복문, 난수와 시드
학습 구성
8단계 · 비교식, 조건 적용, 오류 분석과 새 입력 검증
다음 학습
조건 규칙을 적용한 개인 포스터

학습 목표

  1. 색을 무작위로 선택하는 것만으로는 ‘크기가 60 이상인 원만 강조한다’는 규칙을 항상 충족할 수 없는 이유를 설명한다.
  2. 비교식의 결과가 True인지 False인지 예상하고, =의 대입과 ==의 비교가 어떻게 다른지 설명한다.
  3. if·else를 작성해 크기가 60 이상인 원은 산호색으로, 나머지 원은 녹색으로 그린다.
  4. elif를 추가해 크기 구간에 따라 사각형, 채운 원, 윤곽선만 있는 원을 그린다.
  5. 조건 순서 오류를 실행 경로와 이미지로 설명한다.
  6. 경계값을 바꾸고, 달라진 도형을 예상과 비교한다.
  7. 디자인 의도에 맞게 경계값을 설정하고 선택 근거를 설명한다.
  8. 새로운 크기 배열의 표현과 도형 개수를 검증한다.

학습 내용

각 단계는 개념 이해 → 전체 코드 실행 → 결과 확인 → 원리 설명으로 이어집니다. 여덟 단계로 진행하며, 비교 활동은 A·B 코드를 각각 실행합니다. 각 실습의 코드 하나를 새 Colab 셀에서 바로 실행할 수 있습니다. 실행한 코드 셀과 출력 결과를 비교 자료로 보관합니다. 7단계에서 자신의 의도에 맞게 경계를 정하고, 8단계에서 새로운 입력에도 규칙이 적용되는지 확인합니다. 실습 번호는 주요 학습 단계의 번호와 같습니다.

시작 안내: 동일한 크기 배열에 다른 규칙 적용

1교시에는 후보와 범위에서 값을 선택해 사각형의 색, 막대의 높이, 원의 위치를 바꿨습니다. 이번에는 선택한 크기에 따라 색과 형태를 결정합니다. 먼저 크기가 60 이상인 원을 산호색으로, 나머지 원을 녹색으로 그립니다. 다음 실습에서는 크기가 60 이상이면 사각형, 40 이상 60 미만이면 내부를 채운 원, 40 미만이면 윤곽선만 있는 원을 그립니다. 이 수업에서는 윤곽선만 있는 원을 ‘윤곽 원’이라고 부릅니다.

세 이미지에서 같은 순서에 놓인 도형의 크기와 위치는 같습니다. 색상·도형 종류·채움 방식이 달라진 이유를 크기 조건으로 설명하는 것이 목표입니다. 6·7단계에서는 경계값을 바꾸어 표현의 변화를 비교하고, 8단계에서는 새로운 크기 배열의 표현과 개수까지 검증합니다.

조건문의 필요성

크기가 60 이상인 원만 산호색으로 강조하려고 합니다. 색을 무작위로 고르면 작은 원에도 강조색이 나올 수 있습니다. 의도한 규칙을 구현하려면 먼저 크기를 검사하고, 검사 결과에 따라 색을 정해야 합니다.

조건문은 조건의 참·거짓에 따라 실행할 코드를 고르는 문장입니다. 조건에 따라 실행할 코드가 달라지는 것을 분기라고 합니다. 이번 수업에서는 크기 선택 → 조건 검사 → 색이나 형태 결정 → 그리기 순서로 코드를 작성합니다.

무작위 색 선택과 조건에 따른 색 선택 비교

아래 두 이미지의 크기는 왼쪽부터 30, 46, 64, 46, 60, 38로 같습니다. A는 크기와 관계없이 팔레트에서 색을 무작위로 선택합니다. B는 크기를 검사해 60 이상인 원에만 산호색을 사용합니다. 먼저 “60 이상인 원만 강조한다”는 의도와 다른 색으로 표시된 A의 원을 식별합니다.

A의 네 번째 원은 크기가 46인데 강조색입니다. 반대로 크기 64와 60인 원에는 강조색이 없습니다. 무작위 색 선택이 잘못 실행된 것이 아니라, 크기와 색의 관계를 아직 규칙으로 지정하지 않은 결과입니다. B처럼 관계를 정하려면 조건문이 필요합니다.

A의 실행 코드: 크기는 고정하고 색만 선택

크기 목록을 직접 지정해 색 선택을 추가해도 크기가 달라지지 않도록 했습니다. 시드 7은 이 비교 이미지의 색을 재현하기 위한 값이며, 아래 기준 배열 실습은 시드 21에서 시작합니다.

크기 목록을 직접 지정해 색 선택을 추가해도 크기가 달라지지 않도록 했습니다. 시드 7은 이 비교 이미지의 색을 재현하기 위한 값이며, 아래 기준 배열 실습은 시드 21에서 시작합
from PIL import Image, ImageDraw
from IPython.display import display
import random

sizes = [30, 46, 64, 46, 60, 38]
palette = [(37, 62, 78), (111, 143, 126), (201, 111, 93)]
image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(7)
for i in range(len(sizes)):
    size = sizes[i]
    x = 50 + i * 100
    color = random.choice(palette)
    draw.ellipse((x, 80, x + size, 80 + size), fill=color)

display(image)

조건문의 효과를 비교하려면 조건을 적용하기 전의 이미지가 필요합니다. 기준 이미지에서는 모든 원을 청회색으로 그립니다. 다음 실습에서는 크기가 60 이상인 원을 산호색으로, 나머지 원을 녹색으로 그립니다.

1. 비교할 기준 이미지 만들기

결과 1: 크기가 다른 청회색 원 여섯 개 · 이후 비교의 기준

1교시에서는 choice로 사각형의 색을 선택하고, randint로 막대 높이를 선택했습니다. 이번에는 선택한 정수를 원의 크기로 사용합니다. 이번 실습의 기본 코드는 660 × 220 캔버스에 원 여섯 개를 100 간격으로 배치합니다. 크기 범위는 20~80, 시드는 21이고, 색은 청회색으로 고정합니다.

size = random.randint(20, 80)으로 크기를 정하고, color = palette[0]으로 첫 번째 색을 사용합니다. 팔레트는 1교시에서 수정한 청회색·녹색·산호색을 사용하되, 각 원의 색은 이후 조건문으로 결정합니다. 1교시 막대 예제와 범위·반복 횟수·그리기 코드가 다르므로 같은 시드라도 이미지가 같지는 않습니다. 이번 시간의 기준 배열부터 조건 적용 결과까지 서로 비교합니다.

실습 준비

1교시 노트북 아래에 ‘5주차 2교시’라는 텍스트 셀을 추가합니다. 새 노트북을 사용한다면 이름을 week05_period2_이름으로 정합니다. 이 페이지의 이미지 실습 코드는 각각 모듈·팔레트·시드·캔버스를 준비합니다. 이전 셀의 실행 상태와 관계없이 해당 코드 전체를 실행하면 됩니다.

실습 1. 기준 이미지

실습 1 · 전체 코드

이 코드 하나를 새 셀에서 실행합니다. 원 여섯 개의 크기는 달라도 색은 같은지 확인합니다. 이후 실습에도 각각 전체 코드가 제공됩니다.

실습 1 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    color = palette[0]
    draw.ellipse((x, y, x + size, y + size), fill=color)

display(image)

01 기준 배열원 여섯 개 · 시드 21
01 기준 배열의 실행 결과
304664466038
시드 21에서 크기는 30, 46, 64, 46, 60, 38입니다. 큰 원도 작은 원도 같은 청회색입니다.

2. 비교식으로 참과 거짓 판단하기

핵심 질문: >와 >=의 비교 결과는 경계값 60에서 어떻게 다를까요?

큰 원을 구분하려면 먼저 “크기가 60 이상인가?”를 검사해야 합니다. 비교식은 두 값을 비교하는 식이며, 이 질문은 size >= 60으로 적습니다. >=는 ‘이상’을 뜻하므로 60도 포함합니다.

결과는 참을 뜻하는 True 또는 거짓을 뜻하는 False입니다. 두 값의 자료형은 2주차에 배운 bool이며 따옴표 없이 첫 글자를 대문자로 씁니다. 비교식은 저장된 크기를 바꾸지 않습니다.

크기를 분류하는 기준인 60을 경계값이라고 합니다. 먼저 이 경계값과 바로 앞뒤의 값을 비교합니다.

대입과 비교

size = 60은 변수에 60을 저장하는 대입이고, size >= 60은 저장된 값을 검사하는 비교입니다. ‘같음’을 검사하려면 등호 두 개를 사용한 size == 60으로 적습니다.

비교 연산자
비교 연산자의 의미와 결과
기호뜻size가 60일 때
>보다 큼size > 60 → False
>=이상size >= 60 → True
<보다 작음size < 60 → False
<=이하size <= 60 → True
==같음size == 60 → True
!=다름size != 60 → False

같은 값 60에 대해 size > 60은 False, size >= 60은 True입니다. 아래의 크기 구분 실습에서는 계속 ‘이상’을 뜻하는 >=를 사용합니다.

실습 2. 경계 앞뒤의 참·거짓

실습 2 · 59·60·61 비교 · 전체 코드

세 값에 대해 >, >=, ==의 결과를 먼저 예상합니다. 이 코드만 실행하면 아홉 비교 결과가 출력됩니다.

실습 2 · 59·60·61 비교 · 전체 코드
for size in [59, 60, 61]:
    print("크기:", size)
    print("60보다 큼:", size > 60)
    print("60 이상:", size >= 60)
    print("60과 같음:", size == 60)

결과 확인 60에서는 >만 False이고 >=와 ==는 True입니다. 비교식은 저장한 size를 바꾸지 않습니다.

비교식의 출력 결과
sizesize > 60size >= 60size == 60
59FalseFalseFalse
60FalseTrueTrue
61TrueTrueFalse
비교 결과 해설

size >= 60의 결과는 59에서 False, 60과 61에서 True입니다. 60은 ‘60 이상’에 포함됩니다.

지금까지는 비교 결과를 글자로 출력했습니다. 다음에는 True이면 강조색, False이면 기본색을 선택하도록 실행할 코드를 정합니다.

활동 2 · 확인 질문

“60도 강조색에 포함한다”는 요구에는 >와 >= 중 어떤 기호가 맞나요? size == 60을 쓰면 61도 포함될까요?

예상과 해설 비교

>=는 60과 그보다 큰 값을 포함합니다. ==는 60과 같은 값만 참이므로 61은 포함하지 않습니다.

3. 조건에 따라 두 색으로 나누기

핵심 질문: 참일 때와 거짓일 때 실행할 코드를 어떻게 고를까요?

if는 조건이 참일 때 실행할 코드를 정합니다. else는 조건이 거짓일 때 실행할 코드를 정합니다. 아래에서는 60 이상이면 ‘강조색’, 그보다 작으면 ‘기본색’을 변수 role에 저장합니다.

콜론과 들여쓰기

if와 else 줄은 콜론 :으로 끝냅니다. 각 조건에 속한 문장은 조건 줄보다 스페이스 네 칸 더 들여씁니다. 콜론 아래에서 같은 들여쓰기 수준으로 작성한 문장들을 코드 블록이라고 합니다. 들여쓰기가 줄어들면 해당 블록이 끝납니다.

별도 코드 셀 · 조건별 실행 결과

size가 60일 때 실행할 대입문을 예상한 뒤 실행합니다. 이어서 59로 바꾸어 출력이 달라지는지 비교합니다.

별도 코드 셀 · 조건별 실행 결과
size = 60
if size >= 60:
    role = "강조색"
else:
    role = "기본색"
print(role)

한 번의 실행에서는 두 대입문 중 하나만 실행합니다. print(role)은 들여쓰기가 끝난 조건문 바깥에 있으므로 조건이 참이든 거짓이든 실행합니다. else 뒤에는 별도의 조건을 적지 않습니다.

색상 적용

이미지 코드에서는 ‘강조색’이라는 글자 대신 RGB 값을 color에 저장합니다. palette[2]는 산호색, palette[1]은 녹색입니다. 조건문 뒤의 draw.ellipse()가 선택된 색으로 원을 채웁니다.

반복문 안의 조건문

원 여섯 개에 같은 규칙을 적용하려면 반복문 안에 조건문을 둡니다. for i in range(6):은 들여쓴 코드를 여섯 번 반복합니다. 각 반복에서 원 하나의 크기를 선택하고, if·else로 색을 정한 뒤 원을 그립니다. 반복문이나 조건문 안에 코드를 작성할 때마다 네 칸을 더 들여씁니다.

코드의 포함 관계
위치문장 예시역할
바깥 · 0칸for i in range(6):원 여섯 개의 반복 시작
반복문 안 · 4칸if size >= 60:, else:현재 원의 조건 검사
조건문 안 · 8칸color = palette[2]해당 조건에서 사용할 색 저장
반복문 안 · 4칸draw.ellipse(...)조건문이 정한 색으로 원 그리기

그리기 명령은 조건문 밖이지만 반복문 안에 있습니다. 따라서 어느 색을 선택하든 현재 원을 한 번 그리고, 다음 반복에서 새 크기를 검사합니다.

실습 3. 두 색 구분

실습 3. 두 색 구분 · 새 셀에서 실행 · 전체 코드

크기가 60 이상인 원은 산호색, 나머지는 녹색으로 그리는 전체 코드입니다. 실행 전에 60과 64의 색을 예상합니다.

실습 3. 두 색 구분 · 새 셀에서 실행 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 60:
        color = palette[2]
    else:
        color = palette[1]
    draw.ellipse((x, y, x + size, y + size), fill=color)

display(image)

결과 확인 산호색 두 개와 녹색 네 개가 나옵니다. 여섯 원의 크기·위치는 기준 이미지와 같습니다.

03 두 색 구분원 여섯 개 · 시드 21
03 두 색 구분의 실행 결과
304664466038
60 이상은 산호색, 60 미만은 녹색입니다. 크기와 위치는 기준 배열과 같습니다.

심화: 들여쓰기와 실행 범위

아래 도식의 세로선은 반복문과 조건문의 중첩 구조를 나타냅니다. for 안에서 크기를 고르고 조건을 검사합니다. 조건 안에서는 색만 정합니다. draw.ellipse()는 if와 같은 수준으로 들여쓰므로 조건의 참·거짓과 관계없이 실행합니다.

포함 관계를 보여 주는 발췌 도식입니다. 그리기는 반복마다 한 번, display는 반복이 끝난 뒤 한 번 실행합니다. 바로 앞 실습 3의 전체 코드에서 이 포함 관계를 확인할 수 있습니다.
예상 · 그리기 줄을 옮기면

draw.ellipse()를 else 아래의 여덟 칸 위치로 옮기면 어떤 크기의 원이 그려지지 않을까요? 모든 원이 그려지려면 이 줄은 몇 칸 들여써야 할까요?

해설: 색 지정과 그리기는 별개의 실행

else 안에 그리기를 두면 60 미만일 때만 원을 그립니다. 60 이상에서는 color에 산호색을 저장해도 그리기 명령을 실행하지 않으므로 원이 표시되지 않습니다. 두 경우 모두 그리려면 if·else가 끝난 뒤 반복문 안의 네 칸 위치에 둡니다.

4. 세 구간을 다른 형태로 그리기

핵심 질문: 세 크기 구간 중 하나로 분류하려면 조건을 어떤 순서로 검사할까요?

앞에서는 크기를 60 이상과 60 미만으로 구분했습니다. 60 미만을 다시 40 미만과 40 이상으로 나누려면 조건을 하나 더 추가해야 합니다. elif는 앞 조건이 거짓일 때 다음 조건을 검사합니다. 세 구간에 서로 다른 도형을 그리고, 각 크기에 대해 어떤 조건을 검사하는지 확인합니다.

Python은 위에서 아래로 검사하고 처음 참이 된 조건의 코드 블록만 실행합니다. 모든 조건이 거짓이면 else의 코드 블록을 실행합니다. size가 64라면 첫 조건의 코드 블록을 실행한 뒤 조건문 다음 코드를 실행합니다. 64는 40 이상이기도 하지만 다음 조건은 검사하지 않습니다.

조건 순서

이 예제는 ‘이상’ 조건을 사용하므로 큰 경계 60부터 검사합니다. 40 이상을 먼저 검사하면 60 이상의 값도 이 조건을 만족합니다. 따라서 그 아래에 있는 60 이상 조건은 검사하지 않아 60 이상의 값도 중간 구간으로 잘못 분류합니다. 두 번째 조건의 실제 범위는 앞 조건에서 제외된 값 중 40 이상인 40~59입니다.

채움과 윤곽

이제 각 조건의 코드 블록에 도형을 그리는 명령을 작성합니다. 큰 크기 구간에는 draw.rectangle(), 중간 크기 구간과 작은 크기 구간에는 draw.ellipse()를 사용합니다. 중간 크기 구간의 원은 내부를 채우고, 작은 크기 구간의 원은 윤곽선만 그립니다. 사각형·채운 원·윤곽 원은 도형 종류와 채움 방식으로 나눈 세 가지 표현 방식입니다.

크기별 표현
크기검사 순서표현
60~80if size >= 60산호색 사각형
40~59elif size >= 40녹색 채운 원
20~39else청회색 윤곽 원

원에 사용했던 좌표 (x, y, x + size, y + size)를 draw.rectangle()에 전달하면, 같은 위치와 크기의 경계 상자 안에 사각형을 그립니다. fill은 내부색, outline은 윤곽색, width=2는 윤곽선 두께를 2픽셀로 지정합니다. 윤곽 원은 fill을 생략하므로 원 내부에 기존 배경이 표시됩니다.

선택값의 재사용

크기는 반복마다 size = random.randint(20, 80)으로 한 번만 선택합니다. 조건 검사와 경계 상자 계산에 같은 size를 사용해야 선택한 크기와 표현 규칙이 일치합니다. 조건 안에서 난수를 다시 선택하지 않습니다.

실습 3에서는 색만 달라져서 조건문 뒤에 그리기 명령 하나를 두었습니다. 이번에는 도형의 종류와 채움 방식도 달라집니다. 따라서 각 조건의 코드 블록 안에서 해당 도형을 그립니다. 아래 전체 코드에는 조건문 뒤에 공통 그리기 명령이 없습니다.

실습 4. 세 가지 표현

실습 4. 세 가지 표현 · 새 셀에서 실행 · 전체 코드

60 이상은 사각형, 40 이상 60 미만은 채운 원, 나머지는 윤곽 원으로 그립니다. 각 조건 안에 그리기 명령까지 들어 있습니다.

실습 4. 세 가지 표현 · 새 셀에서 실행 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 60:
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= 40:
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)

display(image)

결과 확인 30·38은 윤곽 원, 46 두 개는 채운 원, 64·60은 사각형입니다. 같은 size를 조건과 좌표에 함께 사용합니다.

04 세 가지 표현도형 여섯 개 · 시드 21
04 세 가지 표현의 실행 결과
304664466038
크기가 30과 38인 도형은 윤곽 원, 크기가 46인 도형 두 개는 채운 원, 크기가 64와 60인 도형은 사각형입니다. 도형의 위치와 크기는 앞 실습과 같습니다.

심화: 입력값에 따른 조건 검사 과정

크기 버튼을 선택해 조건을 위에서 아래로 검사하는 순서를 확인합니다. 조건이 참이면 해당 코드 블록을 실행하고, 같은 if·elif·else 조건문의 나머지 조건은 검사하지 않습니다. ‘검사하지 않음’은 ‘검사했지만 거짓’과 다릅니다. 조건문 뒤의 코드는 이어서 실행됩니다.

입력 크기
  1. if size >= 6046 ≥ 60 → False · 다음 조건 검사
  2. elif size >= 4046 ≥ 40 → True · 이 블록 실행
  3. else앞선 조건이 참이므로 실행하지 않음
실행되는 블록
실행되는 블록
size = 46
if size >= 60:
    role = "사각형"
elif size >= 40:
    role = "채운 원"
else:
    role = "윤곽 원"
print(role)

크기 46: 첫 조건은 거짓, 두 번째 조건은 참이므로 채운 원을 선택합니다. else는 실행하지 않습니다.
대표 크기 세 개의 검사 경로
크기60 이상 검사40 이상 검사실행 결과
64참검사하지 않음사각형
46거짓참채운 원
30거짓거짓else의 윤곽 원
입력 원 카드, 윤곽 원·채운 원·사각형 도장 세 개와 선택된 녹색 원 도장의 출력 카드가 놓인 종이 작업대
검사한 값에 맞는 동작 하나를 선택입력 카드의 크기를 검사한 뒤 세 도장 중 하나를 골라 찍는 비유입니다. 중간 크기는 녹색 채운 원 도장에 대응합니다. 도장 작업대는 개념 일러스트이며 실제 Python 출력이나 크기 측정 도구는 아닙니다.

확인: 크기 구분

아래 코드는 4주차에 배운 리스트 반복으로 30·46·64를 하나씩 검사합니다. 크기는 이미 정해져 있으므로 난수 함수는 사용하지 않습니다. 먼저 각 값이 어느 조건에 해당하는지 예상합니다.

별도 코드 셀 · 세 구간의 출력
별도 코드 셀 · 세 구간의 출력
for size in [30, 46, 64]:
    if size >= 60:
        role = "큼"
    elif size >= 40:
        role = "중간"
    else:
        role = "작음"
    print(size, role)

실행 결과를 예상과 비교합니다. print(size, role)은 조건문 밖이자 반복문 안에 있으므로 크기마다 한 줄씩 출력합니다.

크기 구분 해설

30은 ‘작음’, 46은 ‘중간’, 64는 ‘큼’입니다. 46은 첫 조건에서 제외된 뒤 두 번째 조건을 만족합니다. 64는 첫 조건을 만족하므로 두 번째 조건을 검사하지 않습니다.

5. 조건 검사 순서의 오류 분석하기

핵심 질문: 오류 메시지 없이 실행되어도 의도한 결과가 아닐 수 있을까요?

아래 코드는 문법 오류 없이 실행되지만 의도한 결과를 만들지 못합니다. size가 64일 때 실행되는 대입문을 먼저 표시하고, ‘사각형’이 출력되도록 조건과 그 조건의 대입문을 한 쌍으로 옮깁니다.

예상 → 실행 → 수정 · 조건 순서
예상 → 실행 → 수정 · 조건 순서
size = 64
if size >= 40:
    role = "채운 원"
elif size >= 60:
    role = "사각형"
else:
    role = "윤곽 원"
print(role)

수정 후 size에 30·46·64를 차례로 대입해 결과를 확인합니다. 조건의 경계값만 바꾸고 role에 대입하는 값을 유지하면 표현 규칙이 뒤바뀌므로 두 줄의 관계를 함께 점검합니다.

해설: 검사되지 않는 조건

64는 40 이상이므로 첫 블록에서 ‘채운 원’으로 결정됩니다. 60 이상인 모든 값이 첫 조건에도 포함되어 두 번째 조건을 검사하지 않습니다. 60 이상과 ‘사각형’을 먼저, 40 이상과 ‘채운 원’을 그다음에 둡니다. 큰 수부터 검사해야 하는 것은 이 예제처럼 ‘이상’ 조건을 사용하는 구간 나누기의 경우입니다.

실습 5. 조건 순서의 오류 비교

시드·크기 범위·팔레트는 같습니다. A는 40 이상을 먼저, B는 60 이상을 먼저 검사합니다. 실행 전에 크기 60과 64가 각각 무엇으로 그려질지 적습니다.

실습 5-A · 잘못된 검사 순서 · 전체 코드

문법 오류 없이 실행되지만 “60 이상은 사각형”이라는 규칙을 충족하지 못하는 코드입니다.

실습 5-A · 잘못된 검사 순서 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 40:
        role = "채운 원"
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    elif size >= 60:
        role = "사각형"
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    else:
        role = "윤곽 원"
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)
    print(size, role)

display(image)

결과 확인 60과 64도 첫 조건인 40 이상을 만족해 채운 원으로 그려집니다. 사각형이 없습니다.

실습 5-B · 의도에 맞는 검사 순서 · 전체 코드

큰 경계부터 검사하는 전체 코드입니다. 조건과 해당 그리기 명령을 한 묶음으로 비교합니다.

실습 5-B · 의도에 맞는 검사 순서 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 60:
        role = "사각형"
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= 40:
        role = "채운 원"
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        role = "윤곽 원"
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)
    print(size, role)

display(image)

결과 확인 60과 64는 사각형입니다. 30·38은 윤곽 원, 46 두 개는 채운 원으로 유지됩니다.

활동 5 · 확인 질문

A에서 크기 64는 두 번째 조건을 검사했지만 거짓인 것인가요, 검사하지 않은 것인가요? 조건의 경계값만 바꾸고 그리기 명령을 유지하면 왜 규칙이 달라질까요?

예상과 해설 비교

첫 조건이 참이어서 두 번째 조건은 검사하지 않습니다. 조건과 그때 실행할 명령이 함께 표현 규칙을 이루므로 숫자만 바꾸면 크기 구간과 도형의 연결이 달라집니다.

심화: if 두 개와 if·elif

독립된 if 문 두 개는 각각 조건을 검사하므로 두 코드 블록이 모두 실행될 수 있습니다. if·elif는 하나의 조건문이므로 처음 참이 된 조건의 코드 블록만 실행합니다. 두 코드에서 ‘사각형’과 ‘채운 원’이 몇 줄 출력될지 먼저 예상합니다.

A · 각각 검사

A · 각각 검사
size = 64
if size >= 60:
    print("사각형")
if size >= 40:
    print("채운 원")

B · 연결된 조건 검사

B · 연결된 조건 검사
size = 64
if size >= 60:
    print("사각형")
elif size >= 40:
    print("채운 원")

해설: 두 번 그리기와 한 번 그리기

A는 두 조건이 모두 참이라 두 줄을 출력합니다. B는 ‘사각형’ 한 줄만 출력합니다. print 대신 그리기 명령을 쓰면 A에서는 같은 위치에 도형이 두 번 그려질 수 있습니다. 한 도형에 하나의 표현을 고르는 이번 규칙에는 if·elif·else를 사용합니다. 독립된 if 뒤에 else를 붙이면 그 else는 바로 앞의 들여쓰기 수준이 같은 if에 속하며, 두 if 전체의 나머지 경우를 뜻하지 않습니다.

6. 경계값을 조정하고 검증하기

핵심 질문: 경계 바로 아래 값과 경계값은 각각 어디에 포함될까요? · 실습 6-A·6-B

규칙이 맞는지 확인하려면 경계 바로 아래 값과 경계값을 비교합니다. 무작위 이미지에 39나 40이 나오지 않아도 값을 직접 대입해 검사할 수 있습니다. 앞의 크기 구분 코드처럼 정해진 값을 하나씩 검사하되, 이번에는 각 구간의 경계를 확인합니다.

확인: 조건별 결과

크기 20부터 80까지의 세 조건 구간20 이상 40 미만은 윤곽 원, 40 이상 60 미만은 채운 원, 60 이상 80 이하는 사각형입니다. 39는 윤곽 원, 40과 59는 채운 원, 60은 사각형입니다. 윤곽 원 · 20~39채운 원 · 40~59사각형 · 60~80 20406080 40과 60은 오른쪽의 새 구간에 포함됩니다. randint(20, 80)이 만드는 정수 범위 안에서 비교 세로로 읽는 세 크기 구간20부터 39까지 윤곽 원, 40부터 59까지 채운 원, 60부터 80까지 사각형입니다. 경계값 40과 60은 새 구간의 시작값입니다.20406080윤곽 원채운 원사각형20~3940~5960~8040과 60은 새 구간의 시작값입니다.크기 20~80의 정수를 비교합니다.
else 자체에 20이라는 하한이 있는 것은 아닙니다. 이 예제에서 크기를 20~80으로 선택하므로 else 블록에서 처리하는 값이 20~39가 됩니다. size에 10을 직접 대입해도 else가 실행됩니다.
별도 코드 셀 · 경계값 기록

경계 40과 60의 바로 아래 값까지 포함한 39·40·59·60의 형태를 예상하고, 실행 결과와 비교합니다.

별도 코드 셀 · 경계값 기록
for size in [39, 40, 59, 60]:
    if size >= 60:
        role = "사각형"
    elif size >= 40:
        role = "채운 원"
    else:
        role = "윤곽 원"
    print(size, role)

경계값 해설

차례로 윤곽 원, 채운 원, 채운 원, 사각형입니다. 40과 60은 각각 새로운 구간에 포함됩니다.

실습 6. 경계값 조정

크기 배열 30, 46, 64, 46, 60, 38은 유지합니다. A는 첫 경계만 63으로, B는 둘째 경계까지 50으로 조정한 전체 코드입니다. A·B를 각각 새 셀에서 실행합니다.

실습 6-A · 경계 63 / 40 · 전체 코드

새 구간은 20~39, 40~62, 63~80입니다. 크기 60과 64의 표현을 예상합니다.

실습 6-A · 경계 63 / 40 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 63:
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= 40:
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)

display(image)

결과 확인 60은 사각형에서 채운 원으로 바뀌고, 64는 사각형으로 남습니다.

A 확인 · 경계 바로 아래와 경계값 · 전체 코드

이미지에 나오지 않은 39·40·62·63도 검사합니다.

A 확인 · 경계 바로 아래와 경계값 · 전체 코드
for size in [39, 40, 62, 63]:
    if size >= 63:
        role = "사각형"
    elif size >= 40:
        role = "채운 원"
    else:
        role = "윤곽 원"
    print(size, role)

결과 확인 윤곽 원, 채운 원, 채운 원, 사각형 순서입니다.

실습 6-B · 경계 63 / 50 · 전체 코드

새 구간은 20~49, 50~62, 63~80입니다. 크기 46인 원의 내부가 채워질지 예상합니다.

실습 6-B · 경계 63 / 50 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= 63:
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= 50:
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)

display(image)

결과 확인 A에 있던 크기 46의 채운 원 두 개가 윤곽 원이 됩니다. 60은 채운 원, 64는 사각형입니다.

B 확인 · 경계 바로 아래와 경계값 · 전체 코드

49·50·62·63을 검사합니다.

B 확인 · 경계 바로 아래와 경계값 · 전체 코드
for size in [49, 50, 62, 63]:
    if size >= 63:
        role = "사각형"
    elif size >= 50:
        role = "채운 원"
    else:
        role = "윤곽 원"
    print(size, role)

결과 확인 49는 윤곽 원, 50·62는 채운 원, 63은 사각형입니다.

이미지 아래 숫자는 각 도형의 크기이며, 밑줄은 직전 단계에서 표현이 달라진 크기를 표시합니다. 각 표기의 앞 수는 if, 뒤 수는 elif의 경계값입니다. 첫 변경에서는 크기가 60인 도형이 사각형에서 채운 원으로 바뀝니다. 둘째 변경에서는 크기가 46인 원 두 개의 내부 채움이 없어지고 윤곽선만 남습니다. B의 경계값 확인 셀에서는 크기 49에 ‘윤곽 원’, 크기 50과 62에 ‘채운 원’, 크기 63에 ‘사각형’이 출력됩니다.

7. 의도에 맞게 규칙 정하기

핵심 질문: 강조색 사각형의 수를 줄이거나 윤곽 원의 수를 늘리려면 어떤 경계값을 바꿀까요?

지금까지는 경계값이 다른 코드의 실행 결과를 비교했습니다. 이번에는 강조색 사각형의 수나 윤곽 원의 비율 등 조정할 시각적 특성을 정하고, 그 의도에 맞는 경계값을 설정합니다. 사각형은 주변 원과 형태·색상 대비를 이루고, 윤곽 원은 내부를 채우지 않아 배경이 드러납니다. 전체 도형 수가 같아도 각 표현의 비율에 따라 강조색과 내부색이 차지하는 면적이 달라집니다.

다른 설정을 유지했을 때 경계값이 바꾸는 것
의도조절할 경계예상 변화
강조색 사각형을 줄이기첫 경계를 높임일부 사각형이 채운 원으로 바뀔 수 있음
윤곽 원을 늘리기둘째 경계를 높임일부 채운 원이 윤곽 원으로 바뀔 수 있음
채운 원의 구간을 넓히기첫 경계를 높이거나 둘째 경계를 낮춤채운 원으로 분류할 수 있는 크기가 늘어남

경계를 바꿔도 실제 이미지가 같을 수 있습니다. 예를 들어 첫 경계를 60에서 59로 내려도 현재 여섯 크기에는 59가 없어 바뀌는 도형이 없습니다. 선택 가능한 구간의 변화와 이번 이미지의 변화를 구분해서 설명합니다.

아래 전체 코드의 large_threshold = 60과 medium_threshold = 40이 조절할 설정입니다. 먼저 기본값으로 실행한 뒤, 의도에 맞는 경계 하나를 바꾸어 다시 실행합니다. 둘째 경계는 첫 경계보다 작게 유지하고, 실행 전에 달라질 크기를 적습니다.

실습 7. 경계값을 변수로 지정하기

3교시에서는 경계값을 large_threshold와 medium_threshold라는 변수에 저장합니다. threshold는 ‘임계값’을 뜻하며, 여기서는 크기 구간을 구분하는 경계값을 나타냅니다. 코드 상단의 두 변수 값을 수정하면 해당 변수를 사용하는 비교식의 경계값을 함께 변경할 수 있습니다. 비교 순서와 if·elif·else의 동작은 같습니다.

실습 7 · 경계값을 변수로 지정 · 전체 코드

실행하면 이미지와 함께 각 크기의 표현 이름이 출력됩니다. 이전 실습 코드를 가져올 필요 없이 이 코드만 사용합니다.

실습 7 · 경계값을 변수로 지정 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

palette = [
    (37, 62, 78),
    (111, 143, 126),
    (201, 111, 93),
]

large_threshold = 60
medium_threshold = 40

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)

random.seed(21)
for i in range(6):
    x = 50 + i * 100
    y = 80
    size = random.randint(20, 80)
    if size >= large_threshold:
        role = "사각형"
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= medium_threshold:
        role = "채운 원"
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        role = "윤곽 원"
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)
    print(size, role)

display(image)

결과 확인 60·40에서는 실습 4와 같은 이미지입니다. 경계 하나를 조절한 뒤 표현별 개수와 바뀐 크기를 비교하고, 이미지가 그대로라면 그 이유를 설명합니다.

경계값은 우리가 정하는 분류 기준입니다. 크기를 선택하는 난수 범위와 시드는 그대로이므로, 경계값을 바꿔도 크기 배열은 유지됩니다.

7 · 의도 예시: 강조색 사각형 줄이기경계 63 / 40
큰 경계를 63으로 높여 산호색 사각형을 한 개로 줄인 결과
위 코드에서 large_threshold만 63으로 정한 결과입니다. 크기 60이 채운 원으로 바뀌어 사각형이 두 개에서 한 개로 줄었습니다.
활동 7 · 의도와 결과 기록

내가 줄이거나 늘리고 싶은 표현, 바꾼 경계값, 실행 전 예상, 실제로 달라진 크기를 한 줄씩 적습니다. 경계를 바꿨는데 이미지가 같다면 변경 전후의 경계값 사이에 분류가 달라지는 입력값이 있는지 확인합니다.

8. 새로운 크기 배열에 적용하기

핵심 질문: 새로운 입력값에서도 표현과 개수를 예상할 수 있을까요?

이번에는 sizes = [25, 42, 55, 63, 74, 35]를 직접 지정합니다. 크기를 무작위로 선택하지 않으므로 난수와 시드는 사용하지 않습니다. size = sizes[i]로 목록의 값을 차례로 읽고, 큰 경계 65·중간 경계 45를 적용합니다.

실행 전에 여섯 값의 표현을 적고 사각형·채운 원·윤곽 원의 개수를 예상합니다. 출력 후에는 각 값의 분류와 전체 개수를 모두 확인합니다. 합계가 여섯 개라는 사실만으로 분류까지 올바르다고 판단할 수는 없습니다.

실습 8. 새 입력의 결과 검증

실습 8 · 새 배열과 경계 65 / 45 · 전체 코드

표현별 개수는 0에서 시작합니다. 실행되는 코드 블록에서 해당 도형의 개수에 1을 더해, 반복문이 끝나면 표현별로 그린 도형 수를 집계합니다.

실습 8 · 새 배열과 경계 65 / 45 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display

# 새 입력과 적용할 규칙
sizes = [25, 42, 55, 63, 74, 35]
large_threshold = 65
medium_threshold = 45
palette = [(37, 62, 78), (111, 143, 126), (201, 111, 93)]

image = Image.new("RGB", (660, 220), (245, 240, 228))
draw = ImageDraw.Draw(image)
square_count = 0
filled_count = 0
outline_count = 0

for i in range(6):
    x = 50 + i * 100
    y = 80
    size = sizes[i]
    if size >= large_threshold:
        role = "사각형"
        square_count = square_count + 1
        draw.rectangle((x, y, x + size, y + size), fill=palette[2])
    elif size >= medium_threshold:
        role = "채운 원"
        filled_count = filled_count + 1
        draw.ellipse((x, y, x + size, y + size), fill=palette[1])
    else:
        role = "윤곽 원"
        outline_count = outline_count + 1
        draw.ellipse((x, y, x + size, y + size), outline=palette[0], width=2)
    print(size, role)

display(image)
print("사각형:", square_count)
print("채운 원:", filled_count)
print("윤곽 원:", outline_count)
print("합계:", square_count + filled_count + outline_count)

결과 확인 사각형 1개, 채운 원 2개, 윤곽 원 3개이며 합계는 6개입니다. 각 크기의 출력도 아래 표와 대조합니다.

8 · 새 입력에 같은 검사 방식 적용Python 실행 결과
크기 74의 사각형 하나, 55와 63의 채운 원 두 개, 25와 42와 35의 윤곽 원 세 개
254255637435
목록의 순서와 위치는 유지하면서 각 크기에 맞는 표현 하나를 선택합니다.
예상과 실행 결과 대조
크기검사 경로표현
2565 이상 거짓 → 45 이상 거짓윤곽 원
4265 이상 거짓 → 45 이상 거짓윤곽 원
5565 이상 거짓 → 45 이상 참채운 원
6365 이상 거짓 → 45 이상 참채운 원
7465 이상 참 → 다음 조건 검사 생략사각형
3565 이상 거짓 → 45 이상 거짓윤곽 원
활동 8 · 확인 질문

큰 경계만 65에서 63으로 낮추면 어떤 도형이 바뀌고 표현별 개수는 어떻게 될까요? 먼저 적은 뒤 위 전체 코드의 large_threshold를 63으로 바꾸어 실행합니다.

예상과 해설 비교

크기 63만 채운 원에서 사각형으로 바뀝니다. 사각형 2개, 채운 원 1개, 윤곽 원 3개이며 합계는 여전히 6개입니다.

최종 기록 · 생성 규칙 설명

“입력 크기는 ___, 큰 경계는 ___, 중간 경계는 ___이다. 프로그램은 ___부터 검사하고, 처음 참인 조건에서 ___한다.”를 완성합니다. 이어서 큰 경계 변경 전후에 크기 63의 표현이 달라진 이유를 한 문장으로 적습니다.

결과물 점검

노트북에 각 단계의 코드·출력·예상과 비교한 기록을 남깁니다. 이미지가 나오는 단계는 해당 이미지도 보관합니다. 비교식의 참·거짓, 오류 원인, 경계 변경 이유와 새 입력의 분류를 설명할 수 있는지 확인합니다.

여덟 단계의 결과 점검
단계학습 결과물설명할 핵심 개념
1. 기준 이미지청회색 원 배열조건 적용 전의 크기와 위치
2. 비교식59·60·61의 아홉 비교 결과>와 >=, =와 ==의 차이
3. 두 색산호색 두 개·녹색 네 개60을 강조색에 포함하는 이유
4. 세 구간사각형·채운 원·윤곽 원큰 경계부터 검사하는 순서
5. 오류 분석잘못된·올바른 이미지와 원인검사하지 않은 조건과 거짓 조건의 차이
6. 경계값A·B 이미지와 경계 검사크기 60·46의 표현이 달라지는 이유
7. 의도와 규칙설정한 경계값과 예상·실행 결과 비교선택한 경계가 표현 비율에 미치는 영향
8. 새 입력크기별 결과와 1·2·3개 집계경계 63으로 바꾸면 2·1·3개가 되는 이유

규칙 설명

텍스트 셀 · 최종 규칙과 변경 이유

실습 6의 B 결과를 기준으로 “위치와 ________은 유지하고, 크기가 ________ 이상이면 ________, 그보다 작으면서 ________ 이상이면 ________, 나머지는 ________으로 그렸다.”를 완성합니다. 이어서 실습 4에서 A로 바꿨을 때와 A에서 B로 바꿨을 때를 나누어 설명합니다. 각 설명에는 바꾼 경계값, 달라진 도형의 크기, 도형 종류나 채움 방식이 달라진 이유를 적습니다.

오류 점검

현상별 점검 항목
현상점검 항목
문법 오류if·elif·else 줄 끝에 콜론이 있는지, 비교식에 올바른 기호를 썼는지 확인합니다.
들여쓰기 오류for 안의 문장은 네 칸, 조건별 코드 블록 안의 문장은 여덟 칸 들여썼는지 확인합니다.
실습 4에서 크기 64인 도형이 채운 원으로 출력됨60 이상을 첫 번째 조건에서 검사하고, 40 이상을 elif에서 검사하는지 확인합니다.
실습 4에서 크기 30인 도형이 사각형으로 출력됨조건 검사와 도형 좌표 계산에 같은 size를 사용하는지 확인합니다. 조건별 코드 블록 안에서 size에 새 난수를 저장했다면 해당 줄을 제거합니다.
실습 4에서 한 위치에 도형이 두 번 그려짐조건별 그리기 외에 draw.ellipse()를 한 번 더 실행하고 있지 않은지 확인합니다.
색상이나 그리기 명령만 바꿨는데 도형 크기도 달라짐시드가 21이고 크기 범위가 20~80인지 확인합니다. 난수 호출을 추가·삭제하거나 호출 순서를 바꾸지 않았는지도 확인합니다.
실습 4에서 사각형이 나오지 않음반복문 안의 크기 선택 직후에 print(size)를 넣어 60 이상의 값이 나오는지 확인합니다. ‘확인: 조건별 결과’ 코드에서는 size가 60일 때 ‘사각형’이 출력되는지 검사합니다.

개념 복습

1. 대입과 비교

=는 값을 저장하고, ==는 같은지 비교합니다. 이 실습의 비교식은 True 또는 False를 반환하며 저장된 값을 바꾸지 않습니다.

2. 조건 순서

if·elif·else는 위에서부터 조건을 검사해 처음 참이 된 조건의 코드 블록만 실행합니다. 모든 조건이 거짓이면 else의 코드 블록을 실행합니다. 이 예제처럼 이상 조건으로 구간을 나눌 때는 큰 경계부터 검사합니다.

3. else의 범위

else는 앞선 조건이 모두 거짓일 때 실행할 코드 블록을 지정하므로 별도의 비교식을 작성하지 않습니다.

4. 경계값 검사

이미지에 특정 크기가 없더라도 경계 바로 아래 값과 경계값을 직접 대입해 규칙을 검사할 수 있습니다.

3교시 예고

그래픽 포스터 세 후보

3교시에서는 겹친 색면·동심원 리듬·스트라이프 신호 중 표현을 고르고, 같은 규칙으로 시드 후보 세 장을 만듭니다. 그중 한 장을 선택하고 이유를 설명한 뒤 PNG와 노트북을 제출합니다. 전체 생성 코드가 제공되므로 설정을 설계하고 결과 비교에 집중합니다.

3교시에 이어지는 규칙
항목적용
캔버스와 범위600 × 600, 여백 40, 크기 20~80
무작위 선택크기·x·y·기본색을 매 반복에서 선택
조건두 경계가 큰·중간·작은 모티프를 구분
개수모티프 40~80개. 하나의 모티프에는 여러 그리기 명령이 들어갈 수 있음
재현과 선택서로 다른 시드 세 개 비교, 선택한 원본 저장
설명생성 규칙과 후보를 고른 이유를 각각 기록

기본색과 강조색의 사용

기본색은 random.choice(palette)로 선택하고 큰 모티프에는 강조색을 사용합니다. 선택한 그래픽 표현에 따라 큰 동심원의 중심에는 기본색을 함께 쓰기도 합니다. 난수로 선택한 값과 실제 그리기에 사용하는 위치를 구분해서 읽습니다.

예를 들어 크기 70, 경계 42·64라면 큰 분기에 들어갑니다. 색면은 겹친 사각형, 동심원은 강조 고리와 중심, 스트라이프는 가로 띠를 그립니다. 자세한 결과와 완성 코드는 3교시 교안에서 확인합니다.

보충: 포스터와 선택 비율

필수 실습을 마쳤다면 원 여섯 개의 규칙을 600 × 600 포스터로 확장합니다. 아래 코드는 도형 45개, 시드 29와 별도의 색상 설정을 사용합니다. 8단계의 새 입력 검증까지 마친 뒤 새 셀에서 실행합니다.

위치까지 무작위로 고를 때는 도형 크기를 먼저 선택하고, 도형이 여백의 안쪽 기준선을 넘지 않도록 왼쪽 위 좌표의 범위를 정합니다. margin은 캔버스 가장자리에 남길 여백입니다. x좌표는 margin부터 canvas_width - margin - size까지, y좌표는 margin부터 canvas_height - margin - size까지의 범위에서 선택합니다. 너비가 600, 여백이 40, 도형 크기가 70이면 x좌표의 범위는 40부터 600 - 40 - 70 = 490까지입니다.

이 예제의 작은 원은 내부색과 윤곽색을 함께 사용합니다. image.save()는 완성 이미지를 PNG로 저장합니다.

보충 실습 · 포스터 · 전체 코드

이 코드 하나로 준비·그리기·PNG 저장까지 실행합니다.

보충 실습 · 포스터 · 전체 코드
from PIL import Image, ImageDraw
from IPython.display import display
import random

# 1. 고정 규칙
canvas_width = 600
canvas_height = 600
background_color = (245, 240, 228)
outline_color = (37, 62, 78)
accent_color = (201, 111, 93)
medium_color = (211, 155, 42)
small_color = (111, 143, 126)
margin = 40
shape_count = 45
seed_number = 29

# 2. 이미지와 난수 시작점
image = Image.new(
    "RGB",
    (canvas_width, canvas_height),
    background_color,
)
draw = ImageDraw.Draw(image)
random.seed(seed_number)

# 3. 반복마다 후보 선택
for shape_number in range(shape_count):
    size = random.randint(20, 80)
    x = random.randint(
        margin,
        canvas_width - margin - size,
    )
    y = random.randint(
        margin,
        canvas_height - margin - size,
    )

    # 4. 같은 size를 조건과 도형에 함께 사용
    if size >= 60:
        draw.rectangle(
            (x, y, x + size, y + size),
            fill=accent_color,
        )
    elif size >= 40:
        draw.ellipse(
            (x, y, x + size, y + size),
            fill=medium_color,
        )
    else:
        draw.ellipse(
            (x, y, x + size, y + size),
            fill=small_color,
            outline=outline_color,
            width=3,
        )

# 5. 확인과 저장
display(image)
image.save("week05_controlled_chance_seed29.png")

결과 확인 600 × 600 이미지가 표시되고 week05_controlled_chance_seed29.png 파일이 저장됩니다.

보충: 선택 비율

random.random()은 0.0 이상 1.0 미만의 실수 하나를 생성합니다. 그 값이 0.2보다 작은지 검사하면 약 20%의 확률로 강조색을 선택할 수 있습니다. 아래 코드는 색을 정한 뒤 선택값과 RGB를 출력합니다.

보충 실습 · 포스터 · 전체 코드
import random

random.seed(21)
accent_color = (201, 111, 93)
base_color = (111, 143, 126)
chance = random.random()

if chance < 0.2:
    color = accent_color
else:
    color = base_color
print(chance, color)

조건을 0.5 미만으로 바꾸면 강조색을 선택할 확률이 약 50%로 증가합니다. 도형 10개 중 정확히 2개나 5개를 강조한다는 뜻은 아닙니다. 정확한 개수를 정하려면 강조할 도형의 위치나 번호를 직접 지정해야 합니다.

참고 자료

이 페이지의 목차