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

"""
================================================================================
 挑战3 ★★★ — 多色画板（控制台版）
================================================================================

  场景：
    一个控制台中的多色画板程序。
    用户可以用不同的"画笔"在网格画布上绘制字符图案，
    每笔落下的颜色由当前选中的画笔决定。

  结构设计（set + dict 的综合应用）：
    ┌──────────────────────────────────────────────────────┐
    │  dict 「颜色映射表」     →  color_name → RGB         │
    │  dict 「画笔配置库」     →  pen_id → config_dict     │
    │  set  「活跃画笔集合」   →  当前选中的画笔           │
    │  dict 「画布数据」       →  (x,y) → color_char       │
    │  set  「已使用的颜色」   →  画布上出现过的颜色       │
    └──────────────────────────────────────────────────────┘

  运行方式：直接执行，交互式操作
================================================================================
"""
import os
import sys

# ========== 配置常量 ==========
CANVAS_WIDTH = 20
CANVAS_HEIGHT = 10
EMPTY_CHAR = "·"

# ========== 1. dict — 颜色映射表 ==========
COLOR_MAP = {
    "red":     "\033[31m█\033[0m",
    "green":   "\033[32m█\033[0m",
    "yellow":  "\033[33m█\033[0m",
    "blue":    "\033[34m█\033[0m",
    "purple":  "\033[35m█\033[0m",
    "cyan":    "\033[36m█\033[0m",
    "white":   "\033[37m█\033[0m",
}

# 无颜色模式的纯字符版本（兼容 Windows 旧终端）
COLOR_CHAR = {name: "●" for name in COLOR_MAP}
# 让 red 显示为 ■，green 显示为 ▲，增加辨识度
SHAPE_CHARS = {"red": "■", "green": "▲", "blue": "●",
               "yellow": "◆", "purple": "★", "cyan": "⬟", "white": "○"}


# ========== 2. dict — 画笔配置库 ==========
PENS = {
    "pen1": {"name": "红笔",   "color": "red",   "shape": "round", "size": 1},
    "pen2": {"name": "绿笔",   "color": "green", "shape": "round", "size": 1},
    "pen3": {"name": "蓝笔",   "color": "blue",  "shape": "round", "size": 1},
    "pen4": {"name": "黄笔",   "color": "yellow","shape": "square","size": 2},
    "pen5": {"name": "紫笔",   "color": "purple","shape": "diamond","size": 1},
    "pen6": {"name": "粗红笔", "color": "red",   "shape": "square","size": 3},
}

# ========== 3. set — 活跃画笔集合 ==========
active_pens: set = {"pen1"}  # 默认选中 pen1

# ========== 4. dict — 画布数据 ==========
canvas: dict = {}  # key=(x, y), value=color_name


# ========== 5. set — 已使用的颜色跟踪 ==========
used_colors: set = set()


# ========== 核心函数 ==========

def clear_screen():
    """清屏"""
    os.system("cls" if os.name == "nt" else "clear")


def draw_pixel(x: int, y: int, color: str = None) -> None:
    """在画布 (x,y) 位置画一笔"""
    if not (0 <= x < CANVAS_WIDTH and 0 <= y < CANVAS_HEIGHT):
        return  # 越界忽略
    if color is None:
        # 使用当前活跃的第一支画笔的颜色
        for pid in active_pens:
            color = PENS[pid]["color"]
            break
    if color is None:
        return

    canvas[(x, y)] = color
    used_colors.add(color)  # set 自动去重


def render():
    """渲染画布"""
    for y in range(CANVAS_HEIGHT):
        row = []
        for x in range(CANVAS_WIDTH):
            color = canvas.get((x, y))
            if color:
                # 尝试使用颜色字符，否则用形状字符，最后用普通符号
                char = COLOR_MAP.get(color, COLOR_CHAR.get(color, "█"))
            else:
                char = EMPTY_CHAR
            row.append(char)
        print(" ".join(row))


def draw_horizontal_line(y: int, color: str = None, length: int = None):
    """画水平线"""
    if length is None:
        length = CANVAS_WIDTH
    for x in range(length):
        draw_pixel(x, y, color)


def draw_vertical_line(x: int, color: str = None, length: int = None):
    """画垂直线"""
    if length is None:
        length = CANVAS_HEIGHT
    for y in range(length):
        draw_pixel(x, y, color)


def draw_rect(x1: int, y1: int, x2: int, y2: int, color: str = None):
    """画矩形"""
    for x in range(x1, x2 + 1):
        draw_pixel(x, y1, color)
        draw_pixel(x, y2, color)
    for y in range(y1, y2 + 1):
        draw_pixel(x1, y, color)
        draw_pixel(x2, y, color)


def get_stats() -> dict:
    """获取画布统计信息（dict 综合应用）"""
    # 各颜色使用次数
    color_count = {}
    for c in canvas.values():
        color_count[c] = color_count.get(c, 0) + 1

    # 按使用次数排序
    sorted_colors = sorted(color_count.items(), key=lambda x: -x[1])

    return {
        "total_pixels": len(canvas),
        "used_colors": used_colors,
        "color_count": color_count,
        "top_colors": sorted_colors[:3],
        "coverage": f"{len(canvas) / (CANVAS_WIDTH * CANVAS_HEIGHT) * 100:.1f}%",
    }


# ========== 主程序：绘制示例图案 ==========
if __name__ == "__main__":
    clear_screen()
    print("=" * 60)
    print(" 挑战3 ★★★ — 多色画板")
    print("=" * 60)

    # ---- 绘制样例 ----
    # 1. 用红笔在顶部画一条水平线
    active_pens = {"pen1"}
    draw_horizontal_line(0, "red")
    draw_horizontal_line(CANVAS_HEIGHT - 1, "red")

    # 2. 用蓝笔在左右画垂直线
    active_pens = {"pen3"}
    draw_vertical_line(0, "blue")
    draw_vertical_line(CANVAS_WIDTH - 1, "blue")

    # 3. 用绿笔画一个矩形框（中间区域）
    active_pens = {"pen2"}
    draw_rect(2, 2, CANVAS_WIDTH - 3, CANVAS_HEIGHT - 3, "green")

    # 4. 用黄笔在矩形内画小十字
    active_pens = {"pen4"}
    cx, cy = CANVAS_WIDTH // 2, CANVAS_HEIGHT // 2
    for dx in range(-3, 4):
        draw_pixel(cx + dx, cy, "yellow")
    for dy in range(-3, 4):
        draw_pixel(cx, cy + dy, "yellow")

    # 5. 紫色散点
    active_pens = {"pen5"}
    import random
    random.seed(42)
    for _ in range(15):
        rx = random.randint(4, CANVAS_WIDTH - 5)
        ry = random.randint(3, CANVAS_HEIGHT - 4)
        draw_pixel(rx, ry, "purple")

    # ---- 渲染 ----
    print("\n画布预览：\n")
    render()

    # ---- 统计 ----
    stats = get_stats()
    print(f"\n画布统计：")
    print(f"  总像素点：{stats['total_pixels']} / {CANVAS_WIDTH * CANVAS_HEIGHT}")
    print(f"  覆盖率   ：{stats['coverage']}")
    print(f"  使用颜色 ：{', '.join(sorted(stats['used_colors']))}")
    print(f"  颜色使用排行：")
    for color, count in stats["top_colors"]:
        char = COLOR_CHAR.get(color, "?")
        print(f"    {char} {color}: {count} 次")

    # ---- 展示画板底层的 dict 结构 ----
    print(f"\n--- 画板底层数据结构 ---")
    print(f"canvas 类型：{type(canvas).__name__}，条目数：{len(canvas)}")
    print(f"canvas 示例条目：{(list(canvas.items())[:3])}")

    print(f"\nused_colors 类型：{type(used_colors).__name__}，内容：{used_colors}")
    print(f"active_pens 类型：{type(active_pens).__name__}，当前选中：{active_pens}")

    print(f"\nPENS 配置库：")
    for pid, cfg in PENS.items():
        print(f"  {pid}: {cfg['name']} ({cfg['color']}, 形状={cfg['shape']}, 尺寸={cfg['size']})")

    print()
    print(">>> 挑战3 关键收获 <<<")
    print("1. dict 做画布 (x,y)→color 映射，空间换时间")
    print("2. set 自动跟踪已使用的颜色，无需判重")
    print("3. set 管理多画笔选中状态，支持批量绘制")
    print("4. dict.values() 配合 set 做颜色频次统计")
    print("5. 多种数据结构各司其职，组合解决复杂问题")
