23번 벡터 문제 — Python Turtle 구현 완전정복

주어진 문제 → 수학적 해결 알고리즘 → 거북이 시각화 → 디딤돌 문제 10개 → 최종 통합 코드

1. 주어진 23번 문제

23번 원문 문제 이미지
두 벡터 \[ \vec a=(k,2),\qquad \vec b=(k,3) \] 에 대하여 \[ 2\vec a+\vec b \] 의 모든 성분의 합이 \(10\)일 때 \(k\)의 값을 구하는 문제이다.
핵심 벡터의 실수배와 덧셈은 같은 위치의 성분끼리 계산한다.

2. 먼저 수학으로 문제 해결하기

① a 읽기
② 2a
③ + b
④ 성분 합
⑤ 방정식
⑥ k
단계계산의미
\(\vec a=(k,2)\)첫째 성분 \(k\), 둘째 성분 \(2\)
\(2\vec a=(2k,4)\)두 성분 모두에 2를 곱함
\((2k,4)+(k,3)=(3k,7)\)같은 위치의 성분끼리 더함
\(3k+7\)‘모든 성분의 합’
\(3k+7=10\)문제 조건 적용
\(k=1\)최종 답
따라서 실제 Turtle 그림에 사용할 벡터는 \[ \vec a=(1,2),\qquad \vec b=(1,3),\qquad 2\vec a+\vec b=(3,7) \] 이다.
주의: “모든 성분의 합”은 벡터의 크기 \(\sqrt{x^2+y^2}\)를 뜻하지 않는다. 벡터가 \((3k,7)\)이면 성분의 합은 단순히 \(3k+7\)이다.

3. Turtle 구현 설계

① 좌표 변환
수학 좌표 1칸을 여러 픽셀로 확대한다.
② 좌표축
x축, y축과 눈금을 먼저 그린다.
③ 벡터 함수
원점에서 끝점까지 선과 라벨을 그린다.
④ 색 구분
a는 파랑, b는 초록, 2a+b는 빨강으로 표현한다.
⑤ 계산 표시
2a+b=(3,7), 3+7=10을 화면에 쓴다.
⑥ 검산
그림의 끝점과 계산 결과가 일치하는지 확인한다.

4. 디딤돌 문제 10개의 학습 순서

처음부터 완성 코드를 외우는 것이 아니라 점 → 선분 → 좌표 변환 → 좌표축 → 한 벡터 → 두 벡터 → 벡터 계산 → 함수화 → 색·라벨 → 문제 전체 표현의 순서로 올라간다.

1

디딤돌 1 — 좌표평면에 점 하나 찍기

학습 목표 — 거북이의 goto(x, y)는 화면의 좌표 (x, y)로 이동합니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

t.penup()
t.goto(100, 200)
t.dot(10)

turtle.done()

상세 설명

거북이의 goto(x, y)는 화면의 좌표 (x, y)로 이동합니다. 벡터를 그리기 전에 먼저 좌표를 화면의 위치로 바꾸어 이동하는 감각을 익히는 단계입니다. penup()을 사용하면 이동하는 동안 선이 그어지지 않고, dot(10)은 현재 위치에 점을 표시합니다.

실행 결과 — 점 (100, 200)에 해당하는 위치가 화면에 표시된다.
2

디딤돌 2 — 원점에서 한 점까지 선분 그리기

학습 목표 — 벡터는 시작점에서 끝점으로 향하는 방향과 크기를 갖습니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

t.penup()
t.goto(0, 0)
t.pendown()
t.goto(100, 200)

turtle.done()

상세 설명

벡터는 시작점에서 끝점으로 향하는 방향과 크기를 갖습니다. 가장 단순하게 원점 (0,0)에서 (100,200)까지 선을 그리면 벡터의 몸통과 같은 선분을 만들 수 있습니다. 이후에는 끝부분에 화살촉과 라벨을 붙여 벡터처럼 보이게 합니다.

실행 결과 — 원점에서 오른쪽 위의 점까지 한 개의 선분이 그려진다.
3

디딤돌 3 — 수학 좌표와 화면 좌표 연결하기

학습 목표 — 문제의 벡터 (1,2)를 그대로 goto(1,2)에 넣으면 화면에서는 거의 원점 근처에만 보입니다.

코드

import turtle

SCALE = 60
OX, OY = -200, -200

def to_screen(x, y):
    return OX + x * SCALE, OY + y * SCALE

t = turtle.Turtle()
t.penup()
t.goto(to_screen(1, 2))
t.dot(10)

turtle.done()

상세 설명

문제의 벡터 (1,2)를 그대로 goto(1,2)에 넣으면 화면에서는 거의 원점 근처에만 보입니다. 그래서 좌표 1칸을 60픽셀로 확대합니다. OX, OY는 화면에서 수학적 원점을 어디에 둘지 정하는 값입니다. 따라서 (1,2)는 화면에서 (OX+60, OY+120)에 표시됩니다.

실행 결과 — 수학 좌표 (1,2)가 확대되어 보기 좋은 위치에 점으로 표시된다.
4

디딤돌 4 — x축과 y축 그리기

학습 목표 — 벡터 성분을 눈으로 읽으려면 좌표축이 필요합니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

t.penup()
t.goto(-300, 0)
t.pendown()
t.goto(300, 0)

t.penup()
t.goto(0, -250)
t.pendown()
t.goto(0, 250)

turtle.done()

상세 설명

벡터 성분을 눈으로 읽으려면 좌표축이 필요합니다. x축은 좌우 방향의 수평선, y축은 위아래 방향의 수직선입니다. 각 축을 그리기 전에 penup()으로 시작 위치까지 이동한 뒤 pendown()으로 선을 그립니다.

실행 결과 — x축과 y축이 서로 직각으로 만나는 좌표평면이 나타난다.
5

디딤돌 5 — 벡터 a=(1,2) 그리기

학습 목표 — 원점에서 (1,2)까지 그은 선은 벡터 a=(1,2)의 방향을 나타냅니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

SCALE = 60

t.pencolor("blue")
t.penup()
t.goto(0, 0)
t.pendown()
t.goto(1 * SCALE, 2 * SCALE)

turtle.done()

상세 설명

원점에서 (1,2)까지 그은 선은 벡터 a=(1,2)의 방향을 나타냅니다. 첫 번째 성분 1은 x방향으로 1칸, 두 번째 성분 2는 y방향으로 2칸 이동한다는 뜻입니다. SCALE=60이므로 실제 화면에서는 오른쪽 60픽셀, 위쪽 120픽셀 이동합니다.

실행 결과 — 원점에서 오른쪽 1칸, 위쪽 2칸 방향으로 파란 선이 그려진다.
6

디딤돌 6 — 두 벡터 a, b를 함께 그리기

학습 목표 — 원문에서 k=1이므로 a=(1,2), b=(1,3)입니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

SCALE = 60

for v, color in [((1, 2), "blue"), ((1, 3), "green")]:
    x, y = v
    t.pencolor(color)
    t.penup()
    t.goto(0, 0)
    t.pendown()
    t.goto(x * SCALE, y * SCALE)

turtle.done()

상세 설명

원문에서 k=1이므로 a=(1,2), b=(1,3)입니다. 두 벡터는 x성분은 같지만 y성분이 서로 다릅니다. 반복문으로 (벡터, 색상) 쌍을 하나씩 꺼내 같은 방식으로 그리면 중복 코드를 줄일 수 있습니다.

실행 결과 — 파란색 a와 초록색 b가 같은 원점에서 출발하여 서로 다른 높이로 그려진다.
7

디딤돌 7 — 파이썬으로 2a+b 계산하기

학습 목표 — 튜플 a[0], a[1]은 각각 벡터 a의 첫 번째 성분과 두 번째 성분입니다.

코드

k = 1

a = (k, 2)
b = (k, 3)

result = (
    2 * a[0] + b[0],
    2 * a[1] + b[1]
)

print(result)

상세 설명

튜플 a[0], a[1]은 각각 벡터 a의 첫 번째 성분과 두 번째 성분입니다. 벡터의 실수배와 덧셈은 같은 위치의 성분끼리 계산하므로 첫 성분은 2*a[0]+b[0], 둘째 성분은 2*a[1]+b[1]입니다. 계산 결과는 (3,7)입니다.

실행 결과 — 콘솔에 (3, 7)이 출력된다.
8

디딤돌 8 — 벡터 그리기 함수 만들기

학습 목표 — 같은 형식의 벡터를 여러 번 그릴 때는 함수가 매우 유용합니다.

코드

import turtle

t = turtle.Turtle()
SCALE = 60

def draw_vector(v):
    x, y = v
    t.penup()
    t.goto(0, 0)
    t.pendown()
    t.goto(x * SCALE, y * SCALE)

draw_vector((1, 2))
draw_vector((1, 3))
draw_vector((3, 7))

turtle.done()

상세 설명

같은 형식의 벡터를 여러 번 그릴 때는 함수가 매우 유용합니다. draw_vector(v)는 벡터 하나를 받아 원점에서 그 벡터의 끝점까지 이동합니다. 이제 a, b, 2a+b를 한 줄씩 함수에 전달하기만 하면 됩니다.

실행 결과 — 세 벡터가 동일한 규칙으로 원점에서 그려진다.
9

디딤돌 9 — 벡터마다 색과 이름 붙이기

학습 목표 — 세 벡터가 겹쳐 보일 수 있으므로 색상과 라벨을 다르게 지정합니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

SCALE = 60

def draw_vector(v, color, label):
    x, y = v

    t.pencolor(color)
    t.penup()
    t.goto(0, 0)
    t.pendown()
    t.goto(x * SCALE, y * SCALE)

    t.penup()
    t.goto(x * SCALE + 10, y * SCALE)
    t.write(label, font=("Arial", 12, "normal"))

draw_vector((1, 2), "blue", "a")
draw_vector((1, 3), "green", "b")
draw_vector((3, 7), "red", "2a+b")

turtle.done()

상세 설명

세 벡터가 겹쳐 보일 수 있으므로 색상과 라벨을 다르게 지정합니다. 함수에 color, label 매개변수를 추가하면 한 함수로 다양한 벡터를 표현할 수 있습니다. 이것은 최종 프로그램의 핵심 함수 구조입니다.

실행 결과 — a, b, 2a+b가 서로 다른 색과 이름으로 표시된다.
10

디딤돌 10 — 문제 조건까지 화면에 설명하기

학습 목표 — 거북이 그래픽은 그림만 그리는 도구가 아니라 설명문도 함께 쓸 수 있습니다.

코드

import turtle

t = turtle.Turtle()
t.speed(0)

t.penup()
t.goto(-300, 250)
t.write("2a+b = (3,7)",
        font=("Arial", 16, "bold"))

t.goto(-300, 210)
t.write("3+7=10, so k=1",
        font=("Arial", 16, "bold"))

turtle.done()

상세 설명

거북이 그래픽은 그림만 그리는 도구가 아니라 설명문도 함께 쓸 수 있습니다. write()를 사용하면 계산식과 결론을 화면에 표시할 수 있습니다. 최종 프로그램에서는 벡터 그림과 함께 2a+b=(3,7), 성분의 합 3+7=10, 그리고 k=1이라는 결론을 동시에 보여 줍니다.

실행 결과 — 그림 위쪽에 계산 결과와 최종 답이 함께 표시된다.

5. 최종 완성 — 23번 문제 Turtle 구현 코드

import turtle

# -----------------------------------------
# 1. 문제에서 구한 값
# -----------------------------------------
k = 1

a = (k, 2)       # a = (1, 2)
b = (k, 3)       # b = (1, 3)

# 2a + b 계산
result = (
    2 * a[0] + b[0],
    2 * a[1] + b[1]
)

# -----------------------------------------
# 2. 화면 설정
# -----------------------------------------
screen = turtle.Screen()
screen.setup(900, 700)
screen.title("23번 벡터 문제 - Turtle 시각화")
screen.bgcolor("white")

t = turtle.Turtle()
t.speed(0)
t.hideturtle()
t.pensize(2)

SCALE = 60
OX, OY = -230, -220

# -----------------------------------------
# 3. 수학 좌표 -> 거북이 화면 좌표
# -----------------------------------------
def to_screen(x, y):
    return OX + x * SCALE, OY + y * SCALE

# -----------------------------------------
# 4. 좌표축 그리기
# -----------------------------------------
def draw_axes():
    t.pencolor("gray")

    t.penup()
    t.goto(-330, OY)
    t.pendown()
    t.goto(330, OY)

    t.penup()
    t.goto(OX, -280)
    t.pendown()
    t.goto(OX, 280)

    for x in range(-1, 10):
        sx, sy = to_screen(x, 0)
        t.penup()
        t.goto(sx, sy - 5)
        t.pendown()
        t.goto(sx, sy + 5)

        if x != 0:
            t.penup()
            t.goto(sx - 5, sy - 25)
            t.write(str(x), font=("Arial", 9, "normal"))

    for y in range(-1, 9):
        sx, sy = to_screen(0, y)
        t.penup()
        t.goto(sx - 5, sy)
        t.pendown()
        t.goto(sx + 5, sy)

        if y != 0:
            t.penup()
            t.goto(sx - 28, sy - 7)
            t.write(str(y), font=("Arial", 9, "normal"))

    t.penup()
    t.goto(OX - 18, OY - 24)
    t.write("O", font=("Arial", 11, "bold"))

# -----------------------------------------
# 5. 벡터 그리기
# -----------------------------------------
def draw_vector(v, color, label, width=3):
    x, y = v
    end_x, end_y = to_screen(x, y)

    t.pencolor(color)
    t.pensize(width)

    t.penup()
    t.goto(OX, OY)
    t.setheading(t.towards(end_x, end_y))
    t.pendown()
    t.goto(end_x, end_y)

    # 화살촉을 삼각형으로 직접 그린다.
    t.right(150)
    t.forward(14)
    t.backward(14)
    t.left(300)
    t.forward(14)
    t.backward(14)
    t.right(150)

    t.penup()
    t.goto(end_x + 10, end_y + 8)
    t.write(label, font=("Malgun Gothic", 12, "bold"))

# -----------------------------------------
# 6. 계산 정보 표시
# -----------------------------------------
def write_info():
    t.pencolor("black")
    t.penup()
    t.goto(-410, 290)
    t.write("a = (1, 2),   b = (1, 3)",
            font=("Malgun Gothic", 15, "bold"))

    t.goto(-410, 255)
    t.write("2a + b = (3, 7)",
            font=("Malgun Gothic", 15, "bold"))

    t.goto(-410, 220)
    t.write("성분의 합: 3 + 7 = 10  →  k = 1",
            font=("Malgun Gothic", 15, "bold"))

# -----------------------------------------
# 7. 실행
# -----------------------------------------
draw_axes()
draw_vector(a, "blue", "a = (1, 2)")
draw_vector(b, "green", "b = (1, 3)")
draw_vector(result, "red", "2a + b = (3, 7)", 4)
write_info()

turtle.done()

최종 코드에서 꼭 이해할 부분

문제의 수학적 결론
\(\boxed{k=1}\)
\(2\vec a+\vec b=(3,7)\), 성분의 합 \(3+7=10\)

6. 학생이 최종적으로 설명할 수 있어야 하는 내용

  1. 왜 \(2(k,2)=(2k,4)\)인지 설명할 수 있다.
  2. 왜 \((2k,4)+(k,3)=(3k,7)\)인지 설명할 수 있다.
  3. “모든 성분의 합”과 “벡터의 크기”의 차이를 설명할 수 있다.
  4. \(3k+7=10\)에서 \(k=1\)을 구할 수 있다.
  5. 수학 좌표와 Turtle 화면 좌표의 차이를 설명할 수 있다.
  6. 반복되는 벡터 그리기 코드를 함수로 만드는 이유를 설명할 수 있다.
  7. 최종 그림의 세 벡터가 각각 무엇을 의미하는지 설명할 수 있다.