# GESP等级：二级 | GESP Python 二级考点
"""
08第1节 · 列表基础——创建 + 索引 + 遍历
==================================================
课程对应：
  - 00:00-10:00 导入：一排编号盒子 = 列表  [0] [1] [2] 索引从0开始
  - 10:00-30:00 知识点：①创建列表 ②正索引0开始 ③负索引-1最后 ④for遍历
  - 30:00-40:00 演示：for c in ["red","blue","green"]: t.color(c); circle(30)
  - 40:00-55:00 实操：①填空索引 ②补全遍历 ③用颜色列表画彩虹圆
  - 55:00-60:00 小测："colors[0]和colors[-1]分别是什么?"
  - GESP 考点：#23 列表创建与索引、#24 列表遍历

运行方式：
  每个函数独立运行，按教学节奏调用。
"""

import turtle
import time


# ============================================================
# 阶段一：导入——一排编号盒子 = 列表（00:00-10:00）
# ============================================================
def demo_intro_list():
    """
    用"一排编号盒子"的比喻引入列表概念。
    老师演示：普通变量 vs 列表变量。
    """
    print("=" * 60)
    print(" 导入——一排编号盒子 = 列表")
    print("=" * 60)

    print("\n场景：假如你有3种颜色，想用变量存起来——")
    print()

    # ========== 第1步：不用列表，要写3个变量 ==========
    print("--- 第1步：普通变量——每样东西一个盒子 ---")
    color1 = "red"
    color2 = "blue"
    color3 = "green"
    print(f"  color1 = '{color1}'")
    print(f"  color2 = '{color2}'")
    print(f"  color3 = '{color3}'")
    print("  问题：如果有100种颜色，要写100个变量吗？")
    print()

    # ========== 第2步：用列表，一个盒子装全部 ==========
    print("--- 第2步：列表——一排编号盒子 ---")
    colors = ["red", "blue", "green"]
    print(f"  colors = {colors}")
    print()
    print("  想象有一个长条盒子架：")
    print()
    print("  ┌─────┬──────┬───────┐")
    print("  │ red │ blue │ green │")
    print("  ├─────┼──────┼───────┤")
    print("  │ [0] │ [1]  │  [2]  │  ← 编号（索引）从0开始！")
    print("  └─────┴──────┴───────┘")
    print()
    print("  📦 列表 = 一排贴了编号的小盒子")
    print("  📦 编号从0开始，不是1！")
    print("  📦 方盒子用方括号 []")
    print()
    print("🎯 总结：列表是一个容器，可以装多个数据，")
    print("   每个数据有一个编号（索引），从0开始。")
    print("   记忆钩子：'列表 = 一排贴编号盒子，编号从0开始'")


# ============================================================
# 阶段二：知识点讲解（10:00-30:00）
# ============================================================
def knowledge_create():
    """知识点①：创建列表"""
    print("=" * 60)
    print(" 知识点①：创建列表")
    print("=" * 60)
    print()

    print("--- 语法 ---")
    print("  列表名 = [元素1, 元素2, 元素3, ...]")
    print()

    print("--- 示例 ---")
    colors = ["red", "blue", "green"]
    numbers = [10, 20, 30, 40, 50]
    mix = ["hello", 100, True, 3.14]
    print(f"  颜色列表：colors = {colors}")
    print(f"  数字列表：numbers = {numbers}")
    print(f"  混合列表：mix    = {mix}")
    print()

    print("--- 特点 ---")
    print("  ① 用方括号 [] 创建列表")
    print("  ② 元素之间用逗号 , 分隔")
    print("  ③ 列表可以装不同类型的数据")
    print("  ④ 列表是有序的——元素的顺序就是存入的顺序")
    print()

    print("💡 记忆钩子：'方盒子用方括号 []'")


def knowledge_index():
    """知识点②：正索引（从0开始）"""
    print("=" * 60)
    print(" 知识点②：正索引——编号从0开始")
    print("=" * 60)
    print()

    colors = ["red", "blue", "green", "yellow", "purple"]
    print(f"  colors = {colors}")
    print()

    print("--- 索引规则 ---")
    print("  索引（index）= 元素在列表中的位置编号")
    print("  编号从 0 开始！不是 1！")
    print()

    # 画索引示意图
    print("  ┌─────────┬─────────┬─────────┬──────────┬──────────┐")
    print("  │  'red'  │ 'blue'  │ 'green' │ 'yellow' │ 'purple' │")
    print("  ├─────────┼─────────┼─────────┼──────────┼──────────┤")
    print("  │   [0]   │   [1]   │   [2]   │   [3]    │   [4]    │")
    print("  └─────────┴─────────┴─────────┴──────────┴──────────┘")
    print()

    print("--- 通过索引取值 ---")
    for i in range(len(colors)):
        print(f"  colors[{i}] → '{colors[i]}'")
    print()

    print("--- 修改列表元素 ---")
    print(f"  修改前：colors = {colors}")
    colors[2] = "orange"
    print(f"  执行：colors[2] = 'orange'")
    print(f"  修改后：colors = {colors}")
    print()

    print("💡 关键规则：")
    print("  ① 索引从0开始，最后一个元素的索引 = len(列表) - 1")
    print("  ② 通过 列表名[索引] 可以取值   → colors[0] 拿到 'red'")
    print("  ③ 通过 列表名[索引] = 新值 可以修改元素")
    print("  ④ 索引不能超出范围！len(colors)=5，最大索引是4")

    # 恢复原列表
    colors[2] = "green"


def knowledge_negative_index():
    """知识点③：负索引——从-1开始倒着数"""
    print("=" * 60)
    print(" 知识点③：负索引——从-1开始倒着数")
    print("=" * 60)
    print()

    colors = ["red", "blue", "green", "yellow", "purple"]
    print(f"  colors = {colors}")
    print()

    print("--- 负索引规则 ---")
    print("  -1  → 最后一个元素")
    print("  -2  → 倒数第二个元素")
    print("  -3  → 倒数第三个元素")
    print("  ...以此类推")
    print()

    # 画索引示意图（正+负对照）
    print("  ┌─────────┬─────────┬─────────┬──────────┬──────────┐")
    print("  │  'red'  │ 'blue'  │ 'green' │ 'yellow' │ 'purple' │")
    print("  ├─────────┼─────────┼─────────┼──────────┼──────────┤")
    print("  │  [0]    │  [1]    │  [2]    │  [3]     │  [4]     │  ← 正索引")
    print("  │  [-5]   │  [-4]   │  [-3]   │  [-2]    │  [-1]    │  ← 负索引")
    print("  └─────────┴─────────┴─────────┴──────────┴──────────┘")
    print()

    print("--- 负索引取值 ---")
    for i in range(-1, -6, -1):
        print(f"  colors[{i}] → '{colors[i]}'")
    print()

    print("--- 对比正负索引 ---")
    print(f"  colors[0]  = '{colors[0]}'    ← 第一个元素")
    print(f"  colors[-1] = '{colors[-1]}'   ← 最后一个元素")
    print(f"  colors[-2] = '{colors[-2]}'   ← 倒数第二个元素")
    print()

    print("💡 什么时候用负索引？")
    print("  ① 想取最后一个元素，但不知道列表长度 → colors[-1]")
    print("  ② 想取倒数第几个元素 → colors[-2], colors[-3]...")
    print("  ③ 代码更简洁，不用写 len(colors)-1")


def knowledge_traverse():
    """知识点④：for循环遍历列表"""
    print("=" * 60)
    print(" 知识点④：for循环遍历列表")
    print("=" * 60)
    print()

    colors = ["red", "blue", "green", "yellow"]
    print(f"  colors = {colors}")
    print()

    print("--- 方式一：直接遍历元素（推荐）---")
    print("  for c in colors:")
    print("      print(c)")
    print()
    print("  输出：")
    for c in colors:
        print(f"    {c}")
    print()

    print("--- 方式二：通过索引遍历 ---")
    print("  for i in range(len(colors)):")
    print("      print(f'colors[{i}] = {colors[i]}')")
    print()
    print("  输出：")
    for i in range(len(colors)):
        print(f"    colors[{i}] = {colors[i]}")
    print()

    print("--- 方式三：同时拿到索引和元素（enumerate）---")
    print("  for i, c in enumerate(colors):")
    print("      print(f'{i}: {c}')")
    print()
    print("  输出：")
    for i, c in enumerate(colors):
        print(f"    {i}: {c}")
    print()

    print("💡 遍历要点：")
    print("  ① for ... in 列表：直接拿到每个元素")
    print("  ② for i in range(len(列表))：同时拿到索引")
    print("  ③ 循环变量名要合理（c 代表 color，i 代表 index）")
    print("  ④ 遍历时不要修改列表的长度（别删元素！）")


# ============================================================
# 阶段三：演示——用颜色列表画彩虹圆（30:00-40:00）
# ============================================================
def demo_rainbow_circles():
    """
    演示用列表 + for循环 + turtle 画彩虹圆。
    遍历颜色列表，每次换一种颜色画一个圆。
    """
    print("=" * 60)
    print(" 演示：用颜色列表画彩虹圆")
    print("=" * 60)
    print()
    print("代码逻辑：")
    print("  colors = ['red', 'blue', 'green']")
    print("  for c in colors:")
    print("      t.color(c)")
    print("      t.circle(30)")
    print("      t.penup()")
    print("      t.forward(70)")
    print("      t.pendown()")
    print()

    t = turtle.Turtle()
    t.speed(3)
    t.pensize(3)

    # ========== 第1步：3种颜色 ==========
    print("--- 第1步：3种颜色 ---")
    colors = ["red", "blue", "green"]
    print(f"  colors = {colors}")
    print()

    t.penup()
    t.goto(-120, 0)
    t.pendown()

    for c in colors:
        t.color(c)
        t.circle(30)
        print(f"  t.color('{c}')  →  画了一个{c}色的圆")
        t.penup()
        t.forward(80)
        t.pendown()

    print()
    time.sleep(1)

    # ========== 第2步：彩虹7色（更丰富的列表）==========
    print("--- 第2步：彩虹7色 ---")
    t.clear()
    t.penup()
    t.goto(-200, 0)
    t.pendown()

    rainbow = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
    print(f"  rainbow = {rainbow}")
    print(f"  len(rainbow) = {len(rainbow)}   ← 7种颜色")
    print()

    radius = 40
    for color in rainbow:
        t.color(color)
        t.circle(radius)
        print(f"  画了一个{color}色的圆 (半径={radius})")
        radius += 10  # 半径递增，画出彩虹效果
        t.penup()
        t.forward(5)
        t.pendown()

    print()
    print("🎯 关键代码回顾：")
    print("  ① colors = ['red', 'blue', 'green']  ← 创建列表")
    print("  ② for c in colors:                   ← 遍历列表")
    print("  ③ t.color(c)                         ← 用列表元素")
    print("  ④ t.circle(30)                       ← 画圆")

    turtle.done()


# ============================================================
# 阶段四：实操练习（40:00-55:00）
# ============================================================
def practice_answers():
    """实操练习参考答案"""
    print("=" * 60)
    print(" 实操练习参考答案")
    print("=" * 60)
    print()

    # === 练习1：填空索引 ===
    print("--- 练习1：填空索引 ---")
    print()
    print("题目：")
    print("  fruits = ['apple', 'banana', 'cherry', 'durian']")
    print("  ① 取出 'apple'   →  fruits[____]")
    print("  ② 取出 'cherry'  →  fruits[____]")
    print("  ③ 取出 'durian'  →  fruits[____] 或 fruits[____]")
    print()

    fruits = ["apple", "banana", "cherry", "durian"]
    print("答案：")
    print(f"  ① fruits[0] → '{fruits[0]}'")
    print(f"  ② fruits[2] → '{fruits[2]}'")
    print(f"  ③ fruits[3] → '{fruits[3]}' 或 fruits[-1] → '{fruits[-1]}'")
    print()

    # === 练习2：补全遍历 ===
    print("--- 练习2：补全遍历 ---")
    print()
    print("题目：补全代码，遍历 pets 列表并输出每个元素")
    print("  pets = ['cat', 'dog', 'fish']")
    print("  ____ p ____ pets:")
    print("      ____(p)")
    print()

    pets = ["cat", "dog", "fish"]
    print("答案：")
    print("  for p in pets:")
    print("      print(p)")
    print()
    print("  输出结果：")
    for p in pets:
        print(f"    {p}")
    print()

    # === 练习3：用颜色列表画彩虹圆 ===
    print("--- 练习3：用颜色列表画彩虹圆 ---")
    print()
    print("题目：使用 colors = ['red', 'orange', 'yellow', 'green', 'blue']")
    print("      遍历列表，用 turtle 画出5个不同颜色的圆")
    print()
    print("参考代码：")
    print("""    import turtle
    t = turtle.Turtle()
    t.speed(3)
    colors = ['red', 'orange', 'yellow', 'green', 'blue']
    t.penup()
    t.goto(-150, 0)
    t.pendown()
    for c in colors:
        t.color(c)
        t.circle(25)
        t.penup()
        t.forward(60)
        t.pendown()""")
    print()

    # 运行演示
    print("运行结果：")
    t = turtle.Turtle()
    t.speed(3)
    t.pensize(3)
    colors = ["red", "orange", "yellow", "green", "blue"]
    t.penup()
    t.goto(-150, 0)
    t.pendown()
    for c in colors:
        t.color(c)
        t.circle(25)
        print(f"  画了一个{c}色的圆")
        t.penup()
        t.forward(60)
        t.pendown()

    print()
    print("💡 关键点：")
    print("  ① 列表存颜色名，for循环逐个取出")
    print("  ② t.color(c) 把颜色名应用到画笔")
    print("  ③ 每个圆之间用 penup + forward 分隔位置")

    turtle.done()


# ============================================================
# 阶段五：小测（55:00-60:00）
# ============================================================
def demo_quiz():
    """小测题目及正确答案"""
    print("=" * 60)
    print(" 小测：colors[0] 和 colors[-1] 分别是什么？")
    print("=" * 60)
    print()

    colors = ["red", "blue", "green", "yellow", "purple"]
    print(f"  colors = {colors}")
    print()

    print("--- 问题1：colors[0] 是什么？ ---")
    print()
    print("  A. 'purple'")
    print("  B. 'red'     ← 正确答案")
    print("  C. 'blue'")
    print("  D. 报错")
    print()
    print(f"  解析：索引从0开始，colors[0] 是第一个元素 → '{colors[0]}'")
    print()

    print("--- 问题2：colors[-1] 是什么？ ---")
    print()
    print("  A. 'purple'  ← 正确答案")
    print("  B. 'red'")
    print("  C. 'yellow'")
    print("  D. 报错")
    print()
    print(f"  解析：负索引-1是最后一个元素 → '{colors[-1]}'")
    print()

    print("--- 额外题1：colors[len(colors)-1] 是什么？ ---")
    print(f"  len(colors) = {len(colors)}")
    print(f"  colors[{len(colors)-1}] = '{colors[len(colors)-1]}'")
    print("  和 colors[-1] 是一样的！")
    print()

    print("--- 额外题2：下面代码会输出什么？ ---")
    nums = [10, 20, 30, 40, 50]
    print(f"  nums = {nums}")
    print("  for n in nums:")
    print("      print(n * 2)")
    print()
    print("  输出：")
    for n in nums:
        print(f"    {n * 2}")
    print()

    print("--- 记忆钩子复习 ---")
    print("  '列表 = 一排贴编号盒子，编号从0开始'")
    print("  '方盒子用方括号 []'")
    print("  '正索引: 0 1 2 3 ...'")
    print("  '负索引: -1最后一个, -2倒数第二个...'")


# ============================================================
# 入口
# ============================================================
if __name__ == "__main__":
    print(" 08第1节 · 列表基础——创建 + 索引 + 遍历")
    print(" GESP #23 #24")
    print("=" * 60)
    print()
    print("请选择要运行的功能：")
    print("  1  - 导入：一排编号盒子 = 列表（00:00-10:00）")
    print("  2  - 知识点①：创建列表")
    print("  3  - 知识点②：正索引（从0开始）")
    print("  4  - 知识点③：负索引（从-1开始）")
    print("  5  - 知识点④：for循环遍历列表")
    print("  6  - 演示：用颜色列表画彩虹圆（30:00-40:00）")
    print("  7  - 实操练习参考答案（40:00-55:00）")
    print("  8  - 小测答案（55:00-60:00）")
    print()

    try:
        choice = int(input("请输入数字 (1-8)，直接回车默认 6: ") or "6")
    except (ValueError, EOFError):
        choice = 6

    print()

    functions = {
        1: demo_intro_list,
        2: knowledge_create,
        3: knowledge_index,
        4: knowledge_negative_index,
        5: knowledge_traverse,
        6: demo_rainbow_circles,
        7: practice_answers,
        8: demo_quiz,
    }

    func = functions.get(choice)
    if func:
        func()
    else:
        print("无效选择，运行彩虹圆演示")
        demo_rainbow_circles()
