# GESP等级：三级 | GESP Python 三级考点

"""
第3节 模拟法
============
面向7-10岁少儿 —— 用turtle模拟蜗牛爬井

知识点：
  - 模拟四步法：状态→规则→循环→结果
  - 蜗牛爬井：白天爬3米，晚上滑2米
  - 小猫分鱼：逆向模拟
  - 猜数字游戏：交互式模拟
  - 模拟 vs 枚举的区别
"""

import turtle
import time
import random


# ============================================================
# 第一部分：基础模拟演示 —— 蜗牛爬井
# ============================================================

def demo_snail_well():
    """模拟蜗牛爬井 —— 经典模拟问题"""
    print("=" * 40)
    print("【模拟】蜗牛爬井")
    print("=" * 40)

    well_depth = 10
    height = 0
    day = 0

    print(f"井深{well_depth}米，每天白天爬3米，晚上滑2米")
    print("=" * 30)

    while height < well_depth:
        day += 1

        # 白天爬
        height += 3
        print(f"第{day}天白天：爬到{height}米")

        if height >= well_depth:
            print(f"\n✓ 成功！第{day}天爬出井口！")
            break

        # 晚上滑
        height -= 2
        print(f"第{day}天晚上：滑到{height}米")
        time.sleep(0.5)

    print(f"\n总结：{well_depth}米深的井，蜗牛用了{day}天爬出来！")


# ============================================================
# 第二部分：经典问题 —— 小猫分鱼（逆向模拟）
# ============================================================

def demo_cats_fish():
    """模拟小猫分鱼 —— 逆向模拟"""
    print("\n" + "=" * 40)
    print("【模拟】小猫分鱼")
    print("=" * 40)

    print("问题：5只小猫分鱼，每次分成5份多1条，扔掉多的拿走一份")
    print("      下只猫来了不知道已经分过...")
    print("      问原来至少有多少条鱼？")
    print()

    # 逆向模拟：从最后往前推
    fish = 1
    while True:
        total = fish
        ok = True
        for cat in range(5):
            if (total - 1) % 5 != 0:
                ok = False
                break
            total = (total - 1) // 5 * 4

        if ok:
            print(f"✓ 原来至少有 {fish} 条鱼！")
            # 正向验证
            print(f"\n正向验证过程：")
            total = fish
            for cat in range(1, 6):
                print(f"  第{cat}只猫：共有{total}条鱼", end="")
                total = total - 1  # 扔掉1条
                total = total // 5 * 4  # 拿走1/5，剩下4/5
                print(f"，扔掉1条，拿走1/5，剩余{total}条")
            break
        fish += 1


# ============================================================
# 第三部分：经典问题 —— 猜数字游戏（交互式模拟）
# ============================================================

def demo_guess_number():
    """猜数字游戏 —— 交互式模拟"""
    print("\n" + "=" * 40)
    print("【互动模拟】猜数字游戏")
    print("=" * 40)

    secret = random.randint(1, 100)
    attempts = 0
    guess = None

    print("电脑想了一个1~100之间的数字，你来猜！")
    print("（我用模拟法记录你的每一步猜测）")
    print()

    while guess != secret:
        try:
            guess = int(input("请输入你的猜测："))
        except ValueError:
            print("请输入数字！")
            continue

        attempts += 1

        if guess < secret:
            print("太小了！⬆️ 再大一点")
        elif guess > secret:
            print("太大了！⬇️ 再小一点")

        # 显示模拟状态
        if attempts % 3 == 0:
            print(f"[模拟状态] 你已经猜了{attempts}次，范围在缩小...")

    print(f"\n✓ 猜对了！就是{secret}！")
    print(f"你一共猜了{attempts}次")


# ============================================================
# 第四部分：更多模拟例子
# ============================================================

def demo_savings():
    """模拟存钱罐"""
    print("\n" + "=" * 40)
    print("【模拟】存钱罐 —— 每天存5元，每7天花10元")
    print("=" * 40)

    money = 0
    for day in range(1, 31):
        money += 5  # 每天存5元
        if day % 7 == 0:  # 每7天花10元
            money -= 10
            print(f"第{day}天：存5元，花10元，余额{money}元")
        else:
            print(f"第{day}天：存5元，余额{money}元")

    print(f"\n30天后一共有 {money} 元")


def demo_traffic_light():
    """模拟红绿灯"""
    print("\n" + "=" * 40)
    print("【模拟】红绿灯 —— 红灯30秒，绿灯25秒，黄灯5秒")
    print("=" * 40)

    print("模拟2分钟（120秒）的红绿灯变化：")
    print("-" * 30)

    for second in range(1, 121):
        cycle = second % 60
        if cycle <= 30 and cycle != 0:
            color = "🔴 红灯"
        elif cycle <= 55 and cycle != 0:
            color = "🟢 绿灯"
        else:
            color = "🟡 黄灯"

        if second % 10 == 0 or second == 1:
            print(f"第{second:3d}秒：{color}")

    print("...（每10秒显示一次）")
    print("\n模拟完成！")


def demo_rabbit_turtle():
    """模拟龟兔赛跑"""
    print("\n" + "=" * 40)
    print("【模拟】龟兔赛跑")
    print("=" * 40)

    distance = 100  # 总距离100米
    rabbit_pos = 0
    turtle_pos = 0
    rabbit_sleep = False
    sleep_counter = 0
    time_step = 0

    print(f"赛程{distance}米，乌龟匀速每秒5米")
    print("兔子每秒10米，但每跑30米休息3秒")
    print("=" * 30)

    while turtle_pos < distance and rabbit_pos < distance:
        time_step += 1

        if rabbit_sleep:
            sleep_counter -= 1
            if sleep_counter <= 0:
                rabbit_sleep = False
                print(f"第{time_step}秒：兔子醒了！继续跑")
        else:
            rabbit_pos += 10
            if rabbit_pos >= distance:
                print(f"第{time_step}秒：兔子跑到终点！")
                break
            if rabbit_pos % 30 < 10 and rabbit_pos > 0:
                rabbit_sleep = True
                sleep_counter = 3
                print(f"第{time_step}秒：兔子跑了{rabbit_pos}米，开始休息3秒")

        turtle_pos += 5
        if turtle_pos >= distance:
            print(f"第{time_step}秒：乌龟爬到终点！")
            break

        if time_step % 5 == 0:
            print(f"第{time_step}秒：兔子在{rabbit_pos}米，乌龟在{turtle_pos}米")

    print("\n" + "=" * 30)
    if rabbit_pos >= distance and turtle_pos >= distance:
        print("平局！")
    elif rabbit_pos >= distance:
        print("兔子赢了！但..."
              if turtle_pos < distance
              else "兔子先到！")
    else:
        print("乌龟赢了！坚持就是胜利！")


# ============================================================
# 第五部分：turtle可视化 —— 蜗牛爬井
# ============================================================

def setup_screen():
    """设置画布"""
    screen = turtle.Screen()
    screen.title("模拟法 —— 蜗牛爬井")
    screen.bgcolor("lightblue")
    screen.setup(800, 600)
    return screen


def draw_well(t, x, y, depth):
    """画井"""
    t.penup()
    t.goto(x, y)
    t.pendown()
    t.color("brown")
    t.pensize(3)

    # 井的左侧
    t.left(90)
    t.forward(depth * 20)
    # 井底
    t.right(90)
    t.forward(200)
    # 井的右侧
    t.right(90)
    t.forward(depth * 20)

    # 标注深度
    t.penup()
    t.goto(x + 220, y - depth * 10)
    t.color("black")
    t.write(f"井深{depth}米", font=("SimHei", 14, "bold"))

    # 井口标记
    t.penup()
    t.goto(x - 30, y + 10)
    t.color("green")
    t.write("井口", font=("SimHei", 12, "bold"))


def turtle_snail_well():
    """用turtle模拟蜗牛爬井过程"""
    screen = setup_screen()
    t = turtle.Turtle()
    t.speed(3)
    t.hideturtle()

    well_depth = 10
    well_x = -100
    well_y = -100

    # 画井
    draw_well(t, well_x, well_y, well_depth)

    # 创建蜗牛乌龟
    snail = turtle.Turtle()
    snail.shape("turtle")
    snail.color("green")
    snail.penup()
    snail.speed(1)

    # 初始在井底
    snail.goto(well_x + 100, well_y)

    # 信息显示
    info = turtle.Turtle()
    info.hideturtle()
    info.penup()

    height = 0
    day = 0
    pixel_per_meter = 20

    info.goto(200, 200)
    info.color("darkblue")
    info.write("蜗牛爬井模拟", font=("SimHei", 20, "bold"))

    while height < well_depth:
        day += 1
        height += 3

        # 蜗牛往上爬
        snail_y = well_y + height * pixel_per_meter
        snail.goto(well_x + 100, snail_y)

        # 显示信息
        info.clear()
        info.goto(200, 150)
        info.color("black")
        info.write(f"第{day}天：爬到{height}米", font=("SimHei", 16, "normal"))

        time.sleep(1)

        if height >= well_depth:
            info.goto(200, 100)
            info.color("green")
            info.write(f"✓ 第{day}天成功出井！", font=("SimHei", 18, "bold"))
            snail.goto(well_x + 100, well_y + well_depth * pixel_per_meter + 30)
            break

        # 晚上滑下来
        height -= 2
        snail_y = well_y + height * pixel_per_meter
        snail.goto(well_x + 100, snail_y)

        info.goto(200, 100)
        info.color("orange")
        info.write(f"晚上滑到{height}米", font=("SimHei", 16, "normal"))

        time.sleep(1)

    # 总结
    info.goto(200, 50)
    info.color("purple")
    info.write(f"口诀：状态→规则→循环→结果", font=("SimHei", 14, "bold"))

    screen.mainloop()


# ============================================================
# 第六部分：互动 —— 模拟 vs 枚举 对比
# ============================================================

def compare_simulation_enum():
    """对比模拟和枚举"""
    print("\n" + "=" * 40)
    print("【对比】模拟法 vs 枚举法")
    print("=" * 40)

    print("""
    ┌──────────────┬──────────────────┬──────────────────┐
    │  对比项      │  模拟法          │  枚举法          │
    ├──────────────┼──────────────────┼──────────────────┤
    │  核心        │  按时间一步步演  │  一次试所有可能  │
    │  循环类型    │  while（条件）   │  for（范围）     │
    │  适合问题    │  过程变化类      │  选择筛选类      │
    │  比喻        │  过家家/导演     │  试钥匙/考官     │
    │  例子        │  蜗牛爬井        │  水仙花数        │
    └──────────────┴──────────────────┴──────────────────┘
    """)

    print("同一问题的两种解法对比：")

    # 问题：1~100之间能被3整除的数
    print("\n【问题】找出1~100之间能被3整除的数")
    print()

    print("方法一：枚举法（一次性检查所有）")
    result = []
    for i in range(1, 101):
        if i % 3 == 0:
            result.append(i)
    print(f"  结果：{result}")
    print()

    print("方法二：模拟法（一步步生成）")
    result = []
    num = 3
    while num <= 100:
        result.append(num)
        num += 3
    print(f"  结果：{result}")
    print()
    print("两种方法结果一样，但思维方式不同！")


# ============================================================
# 第七部分：主程序
# ============================================================

def main():
    print("""
    ╔══════════════════════════════════╗
    ║    模拟法学习程序                  ║
    ╚══════════════════════════════════╝
    """)

    while True:
        print("\n请选择要运行的功能：")
        print("1. 蜗牛爬井模拟")
        print("2. 小猫分鱼（逆向模拟）")
        print("3. 猜数字游戏（交互式模拟）")
        print("4. 存钱罐模拟")
        print("5. 红绿灯模拟")
        print("6. 龟兔赛跑模拟")
        print("7. turtle蜗牛爬井可视化（图形界面）")
        print("8. 模拟 vs 枚举 对比")
        print("9. 全部运行")
        print("0. 退出")

        choice = input("\n请输入数字（0-9）：").strip()

        if choice == "1":
            demo_snail_well()
        elif choice == "2":
            demo_cats_fish()
        elif choice == "3":
            demo_guess_number()
        elif choice == "4":
            demo_savings()
        elif choice == "5":
            demo_traffic_light()
        elif choice == "6":
            demo_rabbit_turtle()
        elif choice == "7":
            print("\n正在打开turtle图形窗口...")
            turtle_snail_well()
        elif choice == "8":
            compare_simulation_enum()
        elif choice == "9":
            demo_snail_well()
            demo_savings()
            demo_traffic_light()
            compare_simulation_enum()
        elif choice == "0":
            print("再见！记住模拟四步法：")
            print("状态→规则→循环→结果！")
            break
        else:
            print("输入有误，请重新选择。")


if __name__ == "__main__":
    main()
