# GESP等级：四级 | GESP Python 四级考点
"""
第2节 综合模拟考
—— 模拟GESP考试编程题部分

本文件包含3道编程题的参考答案：
  第16题：用turtle绘制五角星（红色，边长150）
  第17题：找出100~200之间所有素数
  第18题：冒泡排序（实现+过程输出）

另外包含附加题：
  附加题1：打印数字三角形
  附加题2：二分查找算法

使用方法：
  运行程序后选择要查看/运行的题目。
"""

import turtle
import time


# ============================================================
# 第16题：绘制五角星（20分）
# 要求：红色五角星，边长150，完成后隐藏海龟
# ============================================================
def question16_star():
    """
    用turtle绘制一个红色的五角星。
    评分点：
      1. 正确导入turtle并创建海龟 (3分)
      2. 设置颜色为红色 (3分)
      3. 使用循环绘制五角星 (5分)
      4. 转角144度正确 (5分)
      5. 隐藏海龟并完成绘制 (4分)
    """
    # ---- 初始化 ----
    t = turtle.Turtle()
    t.speed(3)
    t.pensize(3)

    # ---- 设置颜色 ----
    t.color("red")
    t.pencolor("red")

    # ---- 用循环画五角星 ----
    # 五角星的每个外角是144度
    # 或者也可以用 left(72)
    for i in range(5):
        t.forward(150)   # 边长150
        t.right(144)     # 外角144度

    # ---- 隐藏海龟 ----
    t.hideturtle()

    # ---- 显示完成信息 ----
    t.penup()
    t.goto(0, -200)
    t.color("black")
    t.write("五角星绘制完成！边长=150，颜色=红色",
            align="center", font=("SimHei", 14, "normal"))

    print("第16题：五角星绘制完成！")
    turtle.done()


# ============================================================
# 第17题：找出100~200之间所有素数（20分）
# 要求：枚举法，输出每个素数，统计总数
# ============================================================
def question17_primes():
    """
    找出100~200之间所有素数。
    评分点：
      1. 正确使用两层循环 (5分)
      2. 判断素数的逻辑正确 (5分)
      3. 输出结果格式正确 (5分)
      4. 统计总数正确 (5分)
    """
    # ---- 素数判断函数 ----
    def is_prime(n):
        """判断一个数是不是素数"""
        if n < 2:
            return False
        # 只需要检查到平方根
        # 因为如果n有因数a，则必有因数b=n/a
        # a和b中一定有一个 <= sqrt(n)
        for i in range(2, int(n ** 0.5) + 1):
            if n % i == 0:
                return False
        return True

    # ---- 主程序 ----
    print("\n" + "=" * 50)
    print("第17题：找出100~200之间的所有素数")
    print("=" * 50)

    count = 0
    primes_list = []

    for n in range(100, 201):
        if is_prime(n):
            primes_list.append(n)
            count += 1
            print(n, end=" ")
            # 每行显示10个数
            if count % 10 == 0:
                print()

    print("\n" + "-" * 50)
    print(f"100~200之间共有 {count} 个素数")
    print("素数列表：", primes_list)

    # ---- 用turtle显示结果 ----
    t = turtle.Turtle()
    t.speed(5)
    t.penup()

    t.goto(-300, 200)
    t.write("100~200之间的素数：", font=("SimHei", 16, "bold"))

    x, y = -300, 160
    for i, prime in enumerate(primes_list):
        t.goto(x + (i % 10) * 65, y - (i // 10) * 30)
        t.write(prime, font=("Arial", 12, "normal"))

    t.goto(-300, y - (count // 10 + 1) * 30 - 20)
    t.color("red")
    t.write(f"共找到 {count} 个素数",
            font=("SimHei", 14, "bold"))

    t.hideturtle()
    turtle.done()


# ============================================================
# 第18题：冒泡排序（20分）
# 要求：排序列表 [64, 34, 25, 12, 22, 11, 90]
#       输出每一轮结果，最终输出排序后列表
# ============================================================
def question18_bubble_sort():
    """
    冒泡排序实现。
    评分点：
      1. 使用双重循环 (5分)
      2. 相邻元素比较并交换 (5分)
      3. 输出每一轮结果 (5分)
      4. 最终结果正确 (5分)
    """
    # ---- 原始数据 ----
    arr = [64, 34, 25, 12, 22, 11, 90]
    n = len(arr)

    print("\n" + "=" * 50)
    print("第18题：冒泡排序")
    print("=" * 50)
    print(f"原始数组：{arr}")
    print(f"数组长度：{n}")
    print("-" * 50)

    # ---- 冒泡排序 ----
    # 外层循环：控制排序轮数
    for i in range(n - 1):
        # 内层循环：比较相邻元素
        # 每轮过后，最大的数就"冒"到了最后
        # 所以下一轮可以少比较一次
        swapped = False  # 优化：如果一轮没有交换，说明已经排好

        for j in range(n - 1 - i):
            if arr[j] > arr[j + 1]:
                # 交换两个元素
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True

        # 输出本轮结果
        print(f"第{i+1}轮排序后：{arr}")

        # 优化：如果没有交换，提前结束
        if not swapped:
            print(f"第{i+1}轮没有交换，排序提前完成！")
            break

    print("-" * 50)
    print(f"最终排序结果：{arr}")
    print(f"排序完成！共进行了 {i+1} 轮排序")

    # ---- 用turtle可视化排序过程 ----
    visualize_bubble_sort()


def visualize_bubble_sort():
    """用turtle可视化冒泡排序过程（简单版）"""
    import random

    t = turtle.Turtle()
    t.speed(2)
    t.penup()

    # 生成随机数据
    data = [random.randint(10, 100) for _ in range(8)]
    n = len(data)

    t.goto(-300, 200)
    t.write("冒泡排序可视化演示", font=("SimHei", 16, "bold"))

    def draw_bars(t, data, highlight=(-1, -1), title=""):
        """画柱状图"""
        t.clear()
        t.penup()
        t.goto(-300, 150)
        if title:
            t.write(title, font=("SimHei", 12, "normal"))

        bar_width = 40
        for i, val in enumerate(data):
            x = -280 + i * (bar_width + 10)
            y = -100
            t.penup()
            t.goto(x, y)
            t.pendown()

            # 高亮正在比较的两个元素
            if i in highlight:
                t.color("red")
            else:
                t.color("blue")

            # 画矩形
            t.begin_fill()
            t.goto(x, y + val * 2)
            t.goto(x + bar_width, y + val * 2)
            t.goto(x + bar_width, y)
            t.goto(x, y)
            t.end_fill()

            # 标数字
            t.penup()
            t.goto(x + 5, y + val * 2 + 5)
            t.color("black")
            t.write(val, font=("Arial", 8, "normal"))

    # 画原始数据
    draw_bars(t, data, title="原始数据")
    print(f"原始数据：{data}")

    # 排序过程
    for i in range(n - 1):
        for j in range(n - 1 - i):
            draw_bars(t, data, highlight=(j, j + 1),
                      title=f"第{i+1}轮，比较位置{j}和{j+1}")
            time.sleep(0.5)

            if data[j] > data[j + 1]:
                data[j], data[j + 1] = data[j + 1], data[j]
                draw_bars(t, data, highlight=(j, j + 1),
                          title=f"交换 {data[j+1]} 和 {data[j]}")
                time.sleep(0.3)

    # 最终结果
    draw_bars(t, data, title="排序完成！")
    t.penup()
    t.goto(-300, -150)
    t.color("green")
    t.write(f"排序结果：{data}", font=("SimHei", 14, "bold"))

    print(f"排序结果：{data}")
    t.hideturtle()
    turtle.done()


# ============================================================
# 附加题1：打印数字三角形
# ============================================================
def bonus1_number_triangle():
    """
    打印一个数字三角形。
    例如 n=5 时：
        1
       121
      12321
     1234321
    123454321
    """
    n = int(input("请输入三角形行数："))

    print("\n数字三角形：\n")

    for i in range(1, n + 1):
        # 打印前面的空格
        print(" " * (n - i), end="")

        # 打印递增的数字
        for j in range(1, i + 1):
            print(j, end="")

        # 打印递减的数字
        for j in range(i - 1, 0, -1):
            print(j, end="")

        # 换行
        print()


# ============================================================
# 附加题2：二分查找算法
# ============================================================
def bonus2_binary_search():
    """
    二分查找：在一个有序列表中查找目标值。
    每次把查找范围缩小一半，效率非常高！
    """
    # 先创建一个有序列表
    arr = list(range(1, 101))  # 1~100
    print(f"有序列表：1 ~ 100")

    target = int(input("请输入要查找的数（1~100）："))

    # 二分查找
    left = 0
    right = len(arr) - 1
    steps = 0
    found = False

    while left <= right:
        steps += 1
        mid = (left + right) // 2

        print(f"第{steps}步：查找范围 [{arr[left]} ~ {arr[right]}]，中间值 = {arr[mid]}")

        if arr[mid] == target:
            print(f"\n找到了！{target} 在位置 {mid}")
            print(f"一共查找了 {steps} 次")
            found = True
            break
        elif arr[mid] < target:
            print(f"  {arr[mid]} < {target}，向右半区查找")
            left = mid + 1
        else:
            print(f"  {arr[mid]} > {target}，向左半区查找")
            right = mid - 1

    if not found:
        print(f"\n{target} 不在列表中")


# ============================================================
# 附加题3：猜数字游戏（综合应用）
# ============================================================
def bonus3_guess_number():
    """
    猜数字游戏：电脑随机生成一个1~100之间的数，
    玩家猜，电脑提示"大了"或"小了"。
    综合运用了：随机数、循环、分支、输入输出
    """
    import random

    print("\n" + "=" * 50)
    print("🎮 猜数字游戏")
    print("=" * 50)
    print("电脑想了一个1~100之间的数，你能猜出来吗？")

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

    while True:
        try:
            guess = int(input("\n请输入你的猜测（1~100）："))
            attempts += 1

            if guess < 1 or guess > 100:
                print("请输入1~100之间的数！")
                continue

            if guess < secret:
                print(f"小了！再大一点（已猜{attempts}次）")
            elif guess > secret:
                print(f"大了！再小一点（已猜{attempts}次）")
            else:
                print(f"\n🎉 恭喜你猜对了！就是 {secret}！")
                print(f"你一共猜了 {attempts} 次")

                if attempts <= 5:
                    print("太厉害了！你是猜数字大师！")
                elif attempts <= 10:
                    print("不错哦！继续加油！")
                else:
                    print("虽然猜了很多次，但坚持就是胜利！")

                break

        except ValueError:
            print("请输入有效的数字！")


# ============================================================
# 程序入口
# ============================================================
if __name__ == "__main__":
    print("=" * 60)
    print("     综合模拟考 —— 编程题参考答案")
    print("=" * 60)
    print()
    print("请选择题号：")
    print("  16 - 绘制五角星（红色，边长150）")
    print("  17 - 找出100~200之间的所有素数")
    print("  18 - 冒泡排序（含可视化演示）")
    print("  ---- 附加题 ----")
    print("  b1 - 打印数字三角形")
    print("  b2 - 二分查找演示")
    print("  b3 - 猜数字游戏")
    print("  q  - 退出")
    print("=" * 60)

    while True:
        choice = input("\n请输入选择：").strip().lower()

        if choice == "16":
            question16_star()
        elif choice == "17":
            question17_primes()
        elif choice == "18":
            question18_bubble_sort()
        elif choice == "b1":
            bonus1_number_triangle()
        elif choice == "b2":
            bonus2_binary_search()
        elif choice == "b3":
            bonus3_guess_number()
        elif choice == "q":
            print("再见！祝你编程学习愉快！")
            break
        else:
            print("无效选择，请重新输入！")
