# GESP等级：二级 | GESP Python 二级考点
"""
第7课·第4节 —— and/or/not：逻辑运算符 演示代码
GESP #22 | turtle 场景教学
==============================================

演示目录：
  演示1: 安全区检测 —— 4个 and 条件（全真才真）
  演示2: 越界检测 —— 4个 or 条件（有真就真）
  演示3: not 取反演示
  演示4: 弹球游戏 —— 四个独立 if
  演示5: 综合对比 —— and vs or vs 独立 if

运行方式：
  python 第4节_and_or_not.py
  或直接在本文件中取消对应演示的注释后运行
"""

import turtle
import random
import time

# ===========================================================
# 工具函数：画矩形边框
# ===========================================================
def draw_border(t, left, right, bottom, top, color="gray"):
    """画一个矩形边框作为围栏/安全区"""
    t.penup()
    t.goto(left, bottom)
    t.pendown()
    t.color(color)
    t.pensize(2)
    t.goto(right, bottom)
    t.goto(right, top)
    t.goto(left, top)
    t.goto(left, bottom)
    t.penup()


# ===========================================================
# 演示1：安全区检测 —— 4个 and 条件
# ===========================================================
def demo_safety_zone():
    """
    安全区：x 从 -100 到 100，y 从 -100 到 100
    在框里 → 绿色（安全！），在框外 → 红色（出界！）
    使用 and：四条边全部满足才算安全
    """
    print("=" * 50)
    print("演示1：安全区检测 —— 4个 and 条件")
    print("and = 严格老师：四条边全都满足才安全")
    print("=" * 50)

    t = turtle.Turtle()
    t.speed(3)
    t.penup()

    # 画安全区边框
    BOUNDARY = 100
    draw_border(t, -BOUNDARY, BOUNDARY, -BOUNDARY, BOUNDARY, "gray")

    # 标注"安全区"
    t.goto(0, BOUNDARY + 30)
    t.write("安全区 (and: 四条边都要满足)", align="center",
            font=("Arial", 12, "bold"))

    # 测试多个位置
    test_spots = [
        (0, 0),           # 框内 → 安全
        (50, 50),         # 框内 → 安全
        (-BOUNDARY - 50, 50),   # 左框外 → 出界
        (BOUNDARY + 50, -30),   # 右框外 → 出界
        (30, -BOUNDARY - 50),   # 下框外 → 出界
        (-30, BOUNDARY + 50),   # 上框外 → 出界
        (-BOUNDARY - 50, BOUNDARY + 50),  # 左上角框外 → 出界
        (BOUNDARY + 50, -BOUNDARY - 50),  # 右下角框外 → 出界
    ]

    for x, y in test_spots:
        t.goto(x, y)

        # ★ 核心：4个 and 条件 —— 全真才真 ★
        if x > -BOUNDARY and x < BOUNDARY and y > -BOUNDARY and y < BOUNDARY:
            t.color("green")
            t.write(" 安全!", font=("Arial", 10, "bold"))
        else:
            t.color("red")
            t.write(" 出界!", font=("Arial", 10, "bold"))

        t.dot(30)

    print("观察：只有四个条件全部为 True 的点才是绿色（安全区内）")
    print("任何一个 False → 红色（出界）")
    print()

    # 显示"四道墙"的说明
    t.penup()
    t.goto(0, -BOUNDARY - 40)
    t.color("blue")
    t.write("左墙: x>-100  右墙: x<100  下墙: y>-100  上墙: y<100",
            align="center", font=("Arial", 10, "normal"))

    turtle.done()


# ===========================================================
# 演示2：越界检测 —— 4个 or 条件
# ===========================================================
def demo_boundary_bounce():
    """
    围栏：x 从 -150 到 150，y 从 -150 到 150
    碰任意一道墙 → 弹回
    使用 or：有一个条件为 True 就触发
    """
    print("=" * 50)
    print("演示2：围栏反弹 —— 4个 or 条件")
    print("or = 好说话老师：碰任意一道墙就弹回")
    print("=" * 50)

    t = turtle.Turtle()
    t.shape("turtle")
    t.speed(6)
    t.pensize(2)
    t.penup()

    # 画围栏
    LEFT, RIGHT, BOTTOM, TOP = -150, 150, -150, 150
    draw_border(t, LEFT, RIGHT, BOTTOM, TOP, "lightgray")

    # 标注范围
    t.goto(0, TOP + 30)
    t.write("围栏 (or: 碰一道墙就弹回)", align="center",
            font=("Arial", 12, "bold"))

    # 随机漫步 + 围栏反弹
    t.goto(0, 0)
    t.color("purple")
    t.pendown()

    for step in range(100):
        # 随机方向
        t.setheading(random.choice([0, 90, 180, 270]))
        t.forward(15)

        # ★ 核心：4个 or 条件 —— 有真就真 ★
        if t.xcor() < LEFT or t.xcor() > RIGHT \
                or t.ycor() < BOTTOM or t.ycor() > TOP:
            # 碰墙了！弹回
            t.backward(15)
            t.right(180)

            # 标记碰墙位置
            t.penup()
            t.dot(8, "orange")
            t.pendown()

    print("观察：小乌龟每次碰到任意一道墙都会反弹")
    print("永远不会跑出围栏范围！")
    print()

    t.penup()
    t.goto(0, BOTTOM - 40)
    t.color("blue")
    t.write("碰左墙 or 碰右墙 or 碰下墙 or 碰上墙 → 弹回",
            align="center", font=("Arial", 10, "normal"))

    turtle.done()


# ===========================================================
# 演示3：not 取反演示
# ===========================================================
def demo_not():
    """
    not 取反演示：
    - not True = False
    - not False = True
    - not t.isdown() 等价于 t.isdown() == False
    """
    print("=" * 50)
    print("演示3：not 取反")
    print("not = 反义词怪兽：True ↔ False")
    print("=" * 50)

    t = turtle.Turtle()
    t.speed(2)
    t.pensize(3)

    # 演示1：not 的基本逻辑
    t.penup()
    t.goto(-200, 150)
    t.color("black")
    t.write("not 真值表：", font=("Arial", 14, "bold"))

    t.goto(-200, 110)
    t.write("not True  = False    ← 真变假", font=("Arial", 12, "normal"))

    t.goto(-200, 80)
    t.write("not False = True     ← 假变真", font=("Arial", 12, "normal"))

    t.goto(-200, 40)
    t.write("not 是反义词怪兽——吃掉True吐出False！", font=("Arial", 12, "normal"))

    # 演示2：not 在 turtle 中的实际应用
    time.sleep(1)

    t.goto(-200, -20)
    t.color("blue")
    t.write("实际应用：", font=("Arial", 14, "bold"))

    # 画一条线（笔是落下的）
    t.pendown()
    t.goto(100, 100)

    # 检测笔的状态
    t.penup()
    t.goto(-200, -60)
    t.color("darkgreen")

    if t.isdown():
        t.write("t.isdown() = True  ← 笔是落下的（正在画线）",
                font=("Arial", 12, "normal"))

    t.goto(-200, -90)
    if not t.isdown():
        t.write("not t.isdown() = True  ← 笔没有落下（抬起来了）",
                font=("Arial", 12, "normal"))
    else:
        t.write("not t.isdown() = False  ← 笔还是落下的",
                font=("Arial", 12, "normal"))

    # 演示3：not 和 != 的等价关系
    t.goto(-200, -140)
    t.color("purple")
    t.write("小贴士：not t.isdown() 等价于 t.isdown() == False",
            font=("Arial", 11, "normal"))

    t.goto(-200, -170)
    t.write("两种写法效果一样，但 not 更简洁！",
            font=("Arial", 11, "normal"))

    turtle.done()


# ===========================================================
# 演示4：弹球游戏 —— 四个独立 if
# ===========================================================
def demo_pong():
    """
    弹球游戏：
    - 四个方向独立检测
    - 碰不同墙 → 朝不同方向弹
    - 不能用 or，因为 or 不知道碰了哪道墙
    """
    print("=" * 50)
    print("演示4：弹球游戏 —— 四个独立 if")
    print("每道墙单独检测，碰哪道往反方向弹")
    print("=" * 50)

    t = turtle.Turtle()
    t.shape("circle")
    t.color("blue")
    t.speed(0)  # 最快
    t.penup()

    # 边界
    LEFT, RIGHT, BOTTOM, TOP = -200, 200, -200, 200

    # 画围栏
    border = turtle.Turtle()
    border.speed(0)
    border.penup()
    border.goto(LEFT, BOTTOM)
    border.pendown()
    border.color("gray")
    border.pensize(2)
    border.goto(RIGHT, BOTTOM)
    border.goto(RIGHT, TOP)
    border.goto(LEFT, TOP)
    border.goto(LEFT, BOTTOM)
    border.hideturtle()

    # 标注方向提示
    marker = turtle.Turtle()
    marker.speed(0)
    marker.penup()
    marker.color("gray")
    marker.goto(0, TOP + 20)
    marker.write("弹球游戏（四个方向独立判断）", align="center",
                 font=("Arial", 12, "bold"))
    marker.goto(LEFT - 60, 0)
    marker.write("←左", font=("Arial", 10, "normal"))
    marker.goto(RIGHT + 20, 0)
    marker.write("右→", font=("Arial", 10, "normal"))
    marker.goto(0, BOTTOM - 30)
    marker.write("↓下", font=("Arial", 10, "normal"))
    marker.goto(0, TOP + 50)
    marker.write("↑上", font=("Arial", 10, "normal"))
    marker.hideturtle()

    # 初始位置和方向
    t.goto(0, 0)

    # 速度控制
    speed = 8

    # 命中计数
    hits = 0

    # 主循环
    while hits < 30:  # 弹30次后自动停止
        t.forward(speed)

        x, y = t.xcor(), t.ycor()

        # ★ 四个独立 if —— 每道墙单独处理 ★
        if x < LEFT:
            t.setheading(0)  # 碰左墙 → 朝右
            hits += 1
            t.color("red")

        if x > RIGHT:
            t.setheading(180)  # 碰右墙 → 朝左
            hits += 1
            t.color("blue")

        if y < BOTTOM:
            t.setheading(90)  # 碰下墙 → 朝上
            hits += 1
            t.color("green")

        if y > TOP:
            t.setheading(270)  # 碰上墙 → 朝下
            hits += 1
            t.color("orange")

    print(f"弹球结束！共反弹 {hits} 次")
    print("注意：每次碰不同的墙，弹向不同的方向！")
    print("这就是为什么不能用 or —— or 只知道'碰了'，不知道'碰了哪道'")
    print()

    t.penup()
    t.goto(0, 0)
    t.color("black")
    t.write("完成！", align="center", font=("Arial", 16, "bold"))

    turtle.done()


# ===========================================================
# 演示5：综合对比 —— and vs or vs 独立 if
# ===========================================================
def demo_compare():
    """
    三个场景对比，直观展示 and/or/独立if 的区别。
    用一个表格+演示说明三者各自适合的场景。
    """
    print("=" * 60)
    print("演示5：综合对比 —— and vs or vs 独立 if")
    print("=" * 60)

    t = turtle.Turtle()
    t.speed(3)
    t.pensize(2)

    # === 场景A：安全区（and）===
    t.penup()
    t.goto(-250, 180)
    t.color("black")
    t.write("场景A：安全区（and）", font=("Arial", 12, "bold"))

    t.goto(-250, 150)
    t.color("darkgreen")
    t.write(" 条件：x>-50 and x<50 and y>-50 and y<50", font=("Arial", 10, "normal"))
    t.goto(-250, 130)
    t.write(" 规则：全真才真 —— 四道墙都满足", font=("Arial", 10, "normal"))

    # 画安全区
    draw_border(t, -50, 50, -50, 50, "green")

    # 测试点
    for x, y in [(-20, 0), (60, 0), (0, -60)]:
        t.goto(x, y)
        if x > -50 and x < 50 and y > -50 and y < 50:
            t.color("green")
            t.dot(15)
        else:
            t.color("red")
            t.dot(15)

    # === 场景B：围栏（or）===
    t.penup()
    t.goto(50, 180)
    t.color("black")
    t.write("场景B：围栏（or）", font=("Arial", 12, "bold"))

    t.goto(50, 150)
    t.color("darkorange")
    t.write(" 条件：x<-80 or x>80 or y<-80 or y>80", font=("Arial", 10, "normal"))
    t.goto(50, 130)
    t.write(" 规则：有真就真 —— 碰一道就弹", font=("Arial", 10, "normal"))

    draw_border(t, -80, 80, -80, 80, "orange")

    for x, y in [(0, 0), (100, 0), (0, -100)]:
        t.goto(x, y)
        if x < -80 or x > 80 or y < -80 or y > 80:
            t.color("red")
            t.dot(15)
        else:
            t.color("green")
            t.dot(15)

    # === 场景C：弹球（独立if）===
    t.penup()
    t.goto(-250, -50)
    t.color("black")
    t.write("场景C：弹球（4个独立if）", font=("Arial", 12, "bold"))

    t.goto(-250, -80)
    t.color("purple")
    t.write(" 碰左墙→朝右  碰右墙→朝左", font=("Arial", 10, "normal"))
    t.goto(-250, -100)
    t.write(" 碰下墙→朝上  碰上墙→朝下", font=("Arial", 10, "normal"))

    draw_border(t, -120, -20, -100, 0, "purple")
    t.goto(-70, -50)
    t.write("模拟", align="center", font=("Arial", 10, "normal"))

    # 总结
    t.penup()
    t.goto(-250, -150)
    t.color("black")
    t.write("总结对比：", font=("Arial", 12, "bold"))

    t.goto(-250, -180)
    t.color("black")
    t.write(" and → 所有条件必须同时满足（安全区）", font=("Arial", 10, "normal"))
    t.goto(-250, -200)
    t.write(" or  → 任意一个条件满足即可（围栏反弹）", font=("Arial", 10, "normal"))
    t.goto(-250, -220)
    t.write(" 独立if → 每个条件有不同处理（弹球）", font=("Arial", 10, "normal"))

    turtle.done()


# ===========================================================
# 演示6：短路求值 —— and/or 的偷懒原理
# ===========================================================
def demo_short_circuit():
    """
    短路求值演示：
    - and：遇到 False 就停（后面的不执行）
    - or：遇到 True 就停（后面的不执行）
    GESP考点补充：逻辑运算符的短路特性
    """
    print("=" * 60)
    print("演示6：短路求值 —— and/or 的偷懒原理（知识点⑤）")
    print("=" * 60)

    t = turtle.Turtle()
    t.speed(3)
    t.pensize(2)
    t.penup()

    # === 演示1：and 短路 ===
    t.goto(-250, 180)
    t.color("black")
    t.write("演示1：and 短路 —— 遇到False就停！", font=("Arial", 14, "bold"))

    def check_left():
        """模拟检测左墙"""
        t.penup()
        t.goto(-250, 140)
        t.color("blue")
        t.write("  check_left() 执行了！", font=("Arial", 11, "normal"))
        return False  # 左墙已经出界了

    def check_right():
        """这个函数不会被调用（短路了）"""
        t.penup()
        t.goto(-250, 110)
        t.color("red")
        t.write("  check_right() 被调用了！", font=("Arial", 11, "normal"))
        return True

    t.goto(-250, 80)
    t.color("black")
    t.write("运行：False and check_right()", font=("Arial", 11, "bold"))

    # 这里演示 and 短路
    result = check_left()  # 返回 False

    # ★ 关键：由于 check_left() 是 False，check_right() 不会被执行！
    t.goto(-250, 50)
    t.color("green")
    t.write("  → check_left() = False, 所以 and 后面的不执行了！", font=("Arial", 11, "normal"))
    t.goto(-250, 20)
    t.write("  → and 短路：第一个假 → 后面的不用看！", font=("Arial", 11, "bold"))

    # === 演示2：or 短路 ===
    t.goto(50, 180)
    t.color("black")
    t.write("演示2：or 短路 —— 遇到True就停！", font=("Arial", 14, "bold"))

    def check_top():
        """模拟检测上墙"""
        t.penup()
        t.goto(50, 140)
        t.color("blue")
        t.write("  check_top() 执行了！", font=("Arial", 11, "normal"))
        return True  # 上墙碰壁了

    def check_bottom():
        """这个函数不会被调用（短路了）"""
        t.penup()
        t.goto(50, 110)
        t.color("red")
        t.write("  check_bottom() 被调用了！", font=("Arial", 11, "normal"))
        return True

    t.goto(50, 80)
    t.color("black")
    t.write("运行：True or check_bottom()", font=("Arial", 11, "bold"))

    # ★ 关键：由于 check_top() 是 True，check_bottom() 不会被执行！
    result = check_top()  # 返回 True

    t.goto(50, 50)
    t.color("green")
    t.write("  → check_top() = True, 所以 or 后面的不执行了！", font=("Arial", 11, "normal"))
    t.goto(50, 20)
    t.write("  → or 短路：第一个真 → 后面的不用看！", font=("Arial", 11, "bold"))

    # === 总结 ===
    t.penup()
    t.goto(-250, -40)
    t.color("black")
    t.write("总结：短路求值", font=("Arial", 14, "bold"))

    t.goto(-250, -75)
    t.color("darkred")
    t.write(" and 短路：False and 任何值 → 后面不执行（反正肯定是False）",
            font=("Arial", 11, "normal"))
    t.goto(-250, -100)
    t.color("darkgreen")
    t.write(" or  短路：True  or  任何值 → 后面不执行（反正肯定是True）",
            font=("Arial", 11, "normal"))

    t.goto(-250, -140)
    t.color("black")
    t.write("生活类比：", font=("Arial", 12, "bold"))
    t.goto(-250, -165)
    t.write("  and短路 → 第一个同学没举手 → 不用问第二个了（严格老师）",
            font=("Arial", 10, "normal"))
    t.goto(-250, -185)
    t.write("  or短路  → 第一个同学已举手 → 不用问第二个了（好说话老师）",
            font=("Arial", 10, "normal"))

    t.goto(-250, -220)
    t.color("purple")
    t.write("口诀：and遇假停，or遇真停 —— Python也偷懒！",
            font=("Arial", 12, "bold"))

    turtle.done()


# ===========================================================
# 主程序入口
# ===========================================================
if __name__ == "__main__":
    print("第7课·第4节 —— and/or/not 演示代码")
    print()
    print("请选择要运行的演示：")
    print("  1—安全区检测（and）")
    print("  2—围栏反弹（or）")
    print("  3—not 取反演示")
    print("  4—弹球游戏（四个独立 if）")
    print("  5—综合对比")
    print("  6—短路求值演示（知识点⑤）")

    try:
        choice = int(input("请输入数字 (1-6): "))
        if choice == 1:
            demo_safety_zone()
        elif choice == 2:
            demo_boundary_bounce()
        elif choice == 3:
            demo_not()
        elif choice == 4:
            demo_pong()
        elif choice == 5:
            demo_compare()
        elif choice == 6:
            demo_short_circuit()
        else:
            print("请输入 1-6 之间的数字")
    except ValueError:
        print("请输入有效的数字")
    except turtle.Terminator:
        pass
