# GESP等级：二级 | GESP Python 二级考点
# -*- coding: utf-8 -*-
"""
11第2节4 — 参数化函数：传不同参数，画不同图形
GESP考点：#31（参数化函数）、#29（形参与实参）
=====================================================
"""
import turtle
import time

# =====================================================
# 【导入】00:00-10:00  draw_square只能画固定大小 → 加参数(size)画不同大小
# =====================================================
print("=" * 55)
print("【导入】画正方形——但能画任意大小的吗？")
print("=" * 55)
print()

# 先画一个固定大小的正方形——暴露问题
print("问题：下面的函数只能画边长100的正方形……")
print("如果我想画边长50、边长150的，怎么办？")
print()

t = turtle.Turtle()
t.speed(3)
t.pensize(3)
t.shape("turtle")

def draw_square_fixed():
    """只能画固定边长100的正方形"""
    for _ in range(4):
        t.forward(100)
        t.right(90)

# 画一个演示
t.penup()
t.goto(-150, 0)
t.pendown()
t.color("blue")
draw_square_fixed()
t.penup()
t.goto(-150, -50)
t.color("blue")
t.write("固定边长=100", font=("Arial", 10, "normal"))

print("  画好了——但永远是100，改不了大小！")
print()
print("怎么办？ → 给函数加一个【参数】，告诉它每次要画多大！")
print()

input("按 Enter 键进入知识点学习...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【知识点】10:00-30:00  形参 vs 实参 + def draw_square(size)
# =====================================================
print("=" * 55)
print("【知识点①】形参(formal parameter) vs 实参(actual argument)")
print("=" * 55)
print()
print("  ┌────────────────────────────────────────────────────┐")
print("  │  def draw_square(size):    ← 定义时的 size 就是【形参】  │")
print("  │      for _ in range(4):                           │")
print("  │          t.forward(size)   ← 函数体内用 size             │")
print("  │          t.right(90)                               │")
print("  │                                                    │")
print("  │  draw_square(50)           ← 调用时的 50 就是【实参】    │")
print("  │  draw_square(150)          ← 调用时的 150 就是【实参】   │")
print("  └────────────────────────────────────────────────────┘")
print()
print("  形参 = 定义时写在括号里的变量名（占位符）")
print("  实参 = 调用时传进去的具体值（真正的数据）")
print()
print("  类比理解：")
print("    形参 = 遥控器上的【频道按钮】（占位）")
print("    实参 = 你按下的具体【数字键】（真正的数字）")
print()

print("=" * 55)
print("【知识点②】def draw_square(size): 语法拆解")
print("=" * 55)
print()
print("  完整语法：")
print("    def 函数名(形参1, 形参2, ...):")
print("        '''文档字符串（可选）'''")
print("        代码块")
print()
print("  关键点：")
print("  ① 形参在函数定义时出现在括号内，不需要指定类型")
print("  ② 形参的值由调用者通过实参传入")
print("  ③ 函数体内把形参当变量用即可")
print("  ④ 每次调用可以传不同的实参，得到不同的结果")
print()

print("=" * 55)
print("【知识点③】调用 draw_square(100) — 参数传递过程")
print("=" * 55)
print()
print("  调用 draw_square(100) 时，Python 内部做：")
print("    ① size = 100     ← 把实参 100 赋值给形参 size")
print("    ② 进入函数体，size 就是 100")
print("    ③ t.forward(size)  → t.forward(100)")
print()
print("  调用 draw_square(200) 时：")
print("    ① size = 200")
print("    ② t.forward(size)  → t.forward(200)")
print()

print("=" * 55)
print("【知识点④】多个参数 def draw_polygon(sides, size)")
print("=" * 55)
print()
print("  一个函数可以有多个形参，用逗号分隔：")
print()
print("    def draw_polygon(sides, size):")
print("        \"\"\"画任意边数的正多边形\"\"\"")
print("        angle = 360 / sides")
print("        for _ in range(sides):")
print("            t.forward(size)")
print("            t.right(angle)")
print()
print("    draw_polygon(3, 100)   ← 画三角形（边长100）")
print("    draw_polygon(5, 80)    ← 画五边形（边长80）")
print("    draw_polygon(8, 60)    ← 画八边形（边长60）")
print()
print("  形参顺序很重要：第一个实参→第一个形参，第二个→第二个")
print()

print("形参 vs 实参对比表：")
print("  ┌──────────┬──────────────────┬──────────────────┐")
print("  │          │ 形参（parameter） │ 实参（argument）  │")
print("  ├──────────┼──────────────────┼──────────────────┤")
print("  │ 何时出现 │ 函数定义时        │ 函数调用时        │")
print("  │ 是什么   │ 变量名（占位符）  │ 具体值（数据）    │")
print("  │ 例子     │ size, sides       │ 100, 3, 80       │")
print("  │ 类比     │ 遥控器按钮        │ 按下的数字        │")
print("  └──────────┴──────────────────┴──────────────────┘")
print()

input("按 Enter 键进入演示环节...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【演示】30:00-40:00  draw_square(50)→小 / draw_square(150)→大
# =====================================================
print("=" * 55)
print("【演示】同一个函数，传不同参数画不同大小！")
print("=" * 55)
print()

t.speed(4)
t.pensize(3)

# 定义参数化函数
def draw_square(size):
    """画一个边长为 size 的正方形"""
    for _ in range(4):
        t.forward(size)
        t.right(90)

# 演示①：小正方形
t.penup()
t.goto(-200, 50)
t.pendown()
t.color("green")
print("  draw_square(50) → 边长50的小正方形")
draw_square(50)
t.penup()
t.goto(-200, 30)
t.color("green")
t.write("size=50", font=("Arial", 10, "normal"))

# 演示②：中等正方形
t.penup()
t.goto(-50, 50)
t.pendown()
t.color("blue")
print("  draw_square(100) → 边长100的中正方形")
draw_square(100)
t.penup()
t.goto(-50, 30)
t.color("blue")
t.write("size=100", font=("Arial", 10, "normal"))

# 演示③：大正方形
t.penup()
t.goto(160, 50)
t.pendown()
t.color("red")
print("  draw_square(150) → 边长150的大正方形")
draw_square(150)
t.penup()
t.goto(160, 30)
t.color("red")
t.write("size=150", font=("Arial", 10, "normal"))

t.penup()
t.goto(0, -100)
t.color("purple")
t.write("同一个函数 draw_square(size)，传不同参数得不同大小！",
        align="center", font=("Arial", 12, "bold"))

print()
print("  ★ 结论：参数化让一个函数变出无数种可能！")
print("  ★ draw_square(50)   → 小")
print("  ★ draw_square(100)  → 中")
print("  ★ draw_square(150)  → 大")
print()

input("按 Enter 键进入实操环节...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【实操①】40:00-45:00  补全参数 — 让 draw_square 接受 size
# =====================================================
print("=" * 55)
print("【实操①】补全参数 — 修改 draw_square 接受 size")
print("=" * 55)
print()

t.speed(2)
t.pensize(3)
t.shape("turtle")

print("下面的函数定义缺少参数，请补全：")
print()
print("  def draw_square(____):   ← 补全形参")
print("      for _ in range(4):")
print("          t.forward(____)  ← 补全为形参")
print("          t.right(90)")
print()
print("补全后的效果演示：")
print()

# 补全后的版本（教学中展示补全结果）
def draw_square(size):          # ← 补全①：形参 size
    for _ in range(4):
        t.forward(size)         # ← 补全②：用 size 替代固定值
        t.right(90)

# 测试补全后的函数
test_sizes = [30, 60, 90]
colors = ["green", "blue", "red"]
start_x = -220

for i, s in enumerate(test_sizes):
    t.penup()
    t.goto(start_x + i * 160, 0)
    t.pendown()
    t.color(colors[i])
    draw_square(s)
    t.penup()
    t.goto(start_x + i * 160, -40)
    t.color(colors[i])
    t.write(f"size={s}", font=("Arial", 10, "normal"))
    print(f"  draw_square({s}) ✅  边长 {s} 的正方形画好了！")

t.penup()
t.goto(0, -100)
t.color("purple")
t.write("实操①完成：补全参数后，一个函数画任意大小！",
        align="center", font=("Arial", 12, "bold"))

print()
print("✅ 实操①完成！")
print()

input("按 Enter 键继续实操②...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【实操②】45:00-50:00  def draw_polygon(sides, size) — 画任意多边形
# =====================================================
print("=" * 55)
print("【实操②】def draw_polygon(sides, size) 画任意多边形")
print("=" * 55)
print()

t.speed(3)
t.pensize(3)

print("请补全下面的函数，实现画任意边数的正多边形：")
print()
print("  def draw_polygon(sides, size):")
print("      angle = 360 / ____     ← 补全：外角度数")
print("      for _ in range(____):   ← 补全：循环次数")
print("          t.forward(____)     ← 补全：边长")
print("          t.right(____)       ← 补全：右转角度")
print()

# 补全后的版本
def draw_polygon(sides, size):
    """画一个边数为 sides、边长为 size 的正多边形"""
    angle = 360 / sides             # 外角 = 360 / 边数
    for _ in range(sides):          # 循环次数 = 边数
        t.forward(size)             # 前进 size 步
        t.right(angle)              # 右转外角度数

# 测试：画不同多边形
test_polygons = [
    (3, 100, "红色三角形", "red"),
    (4, 80,  "蓝色正方形", "blue"),
    (5, 70,  "绿色五边形", "green"),
    (6, 60,  "紫色六边形", "purple"),
]

start_x = -250
start_y = 60

for i, (sides, size, label, color) in enumerate(test_polygons):
    # 计算位置（两行排列）
    row = i // 2
    col = i % 2
    x = start_x + col * 250
    y = start_y - row * 180

    t.penup()
    t.goto(x, y)
    t.pendown()
    t.color(color)
    draw_polygon(sides, size)
    t.penup()
    t.goto(x, y - 30)
    t.color(color)
    t.write(f"{label} (sides={sides}, size={size})",
            font=("Arial", 9, "normal"))
    print(f"  draw_polygon({sides}, {size}) → {label} ✅")

t.penup()
t.goto(0, -200)
t.color("purple")
t.write("实操②：draw_polygon(sides, size) 画任意多边形！",
        align="center", font=("Arial", 12, "bold"))

print()
print("✅ 实操②完成！一个函数画 N 种多边形！")
print()

input("按 Enter 键继续实操③...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【实操③】50:00-55:00  调用不同参数画不同多边形 + 创意
# =====================================================
print("=" * 55)
print("【实操③】创意组合——不同参数画出千变万化的图形")
print("=" * 55)
print()

t.speed(4)
t.pensize(2)

# 重新定义 draw_polygon（供演示用）
def draw_polygon(sides, size):
    angle = 360 / sides
    for _ in range(sides):
        t.forward(size)
        t.right(angle)

print("用同一个函数，传不同的参数组合：")
print()

# 3~10 边形，边长递减
configs = [
    (3, 120, "red"),     # 三角形
    (4, 100, "orange"),  # 正方形
    (5, 90,  "gold"),    # 五边形
    (6, 80,  "green"),   # 六边形
    (7, 70,  "blue"),    # 七边形
    (8, 60,  "purple"),  # 八边形
    (9, 55,  "pink"),    # 九边形
    (10, 50, "brown"),   # 十边形
]

# 呈弧形排列
start_angle = -160
for i, (sides, size, color) in enumerate(configs):
    t.penup()
    # 从左边开始，沿弧线排列
    angle = start_angle + i * 22
    t.goto(0, 0)
    t.setheading(angle)
    t.forward(150)
    t.setheading(0)   # 朝右开始画
    t.pendown()
    t.color(color)
    draw_polygon(sides, size)
    print(f"  draw_polygon(sides={sides}, size={size:>3d})  →  边数={sides} 边形")

t.penup()
t.goto(0, -200)
t.color("purple")
t.write("同一个函数 draw_polygon(sides, size)，不同参数画出不同多边形！",
        align="center", font=("Arial", 12, "bold"))

print()
print("✅ 实操③完成！参数化让一个函数拥有无限可能！")
print()

input("按 Enter 键进行小测...")
t.clear()
t.penup()
t.home()

# =====================================================
# 【小测】55:00-60:00  形参和实参分别是什么？
# =====================================================
print("=" * 55)
print("【小测】形参和实参分别是什么？")
print("=" * 55)
print()
print("题目：下面的代码中，指出哪个是形参，哪个是实参。")
print()
print("  def draw_square(size):     ← 这里的 size 是____？")
print("      for _ in range(4):")
print("          t.forward(size)")
print("          t.right(90)")
print()
print("  draw_square(50)            ← 这里的 50 是____？")
print("  draw_square(150)           ← 这里的 150 是____？")
print()

print("-" * 55)
print("答案与分析：")
print("-" * 55)
print()
print("  ① def draw_square(size):")
print("     → size 是【形参】（formal parameter）")
print("     因为它在函数定义时出现，是一个变量名（占位符）")
print()
print("  ② draw_square(50)")
print("     → 50 是【实参】（actual argument）")
print("     因为它在函数调用时传入，是一个具体的数值")
print()
print("  ③ draw_square(150)")
print("     → 150 也是【实参】")
print("     调用时传入的具体数值，传给形参 size")
print()

print("-" * 55)
print("判断口诀：")
print("-" * 55)
print()
print("  定义时括号里的是【形参】—— 形参=形式上的参数（占位符）")
print("  调用时括号里的是【实参】—— 实参=实际的参数（具体值）")
print()
print("  记忆钩子：")
print("  形参 = 遥控器上的【频道按钮】（等着你按）")
print("  实参 = 你按下的【具体数字键】（真正的数值）")
print()

# 图形化辅助说明
t.speed(1)
t.pensize(2)

# 画示意图：形参 vs 实参
t.penup()
t.goto(-200, 80)
t.pendown()
t.color("blue")
t.write("def draw_square(size):  ← size 是形参",
        font=("Arial", 12, "normal"))
t.penup()
t.goto(-200, 50)
t.color("green")
t.write("draw_square(50)         ← 50 是实参",
        font=("Arial", 12, "normal"))
t.penup()
t.goto(-200, 20)
t.color("green")
t.write("draw_square(150)        ← 150 是实参",
        font=("Arial", 12, "normal"))

t.penup()
t.goto(-200, -30)
t.color("purple")
t.write("形参=占位符  实参=具体值",
        font=("Arial", 14, "bold"))

# 画箭头关系
t.penup()
t.goto(-40, 70)
t.pendown()
t.color("gray")
t.setheading(0)
t.forward(80)
t.penup()
t.goto(-40, 65)
t.color("gray")
t.write("定义时", font=("Arial", 8, "normal"))

t.penup()
t.goto(-40, 40)
t.pendown()
t.color("gray")
t.forward(60)
t.penup()
t.goto(-40, 35)
t.color("gray")
t.write("调用时", font=("Arial", 8, "normal"))

t.penup()
t.goto(-40, 10)
t.pendown()
t.color("gray")
t.forward(60)
t.penup()
t.goto(-40, 5)
t.color("gray")
t.write("调用时", font=("Arial", 8, "normal"))

print()
print("=" * 55)
print("【课堂总结】")
print("=" * 55)
print()
print("  ◇ 形参（parameter）= 定义时括号里的变量名（占位符）")
print("  ◇ 实参（argument）= 调用时括号里的具体值（数据）")
print("  ◇ 参数化让同一个函数传不同值得到不同结果")
print("  ◇ def draw_square(size):  ← 形参")
print("  ◇ draw_square(50)         ← 实参")
print("  ◇ 多个参数用逗号分隔：def draw_polygon(sides, size):")
print()
print("记忆钩子：")
print("  参数 = 遥控器，传不同数字得不同结果！")
print("  形参 = 遥控器按钮（占位），实参 = 按下的数字（具体值）")
print("=" * 55)
print()

t.penup()
t.goto(0, -150)
t.color("purple")
t.write("今日总结：参数化函数 = 传不同参数，得不同结果！",
        align="center", font=("Arial", 16, "bold"))

turtle.done()
