S SmartDocs
系列: Python python 1850 行 · 更新於 2026-03-20

practice_exercises.py

Python/01_beginner_level/practice_exercises.py

"""
Python 初學者練習題 - Core Syntax & Control Flow
Practice Exercises for Core Syntax and Control Flow

涵蓋主題 (Topics Covered):
  - 變數與賦值 (Variables & Assignment)
  - 資料型態 (Data Types)
  - 運算子 (Operators)
  - 字串操作 (String Operations)
  - 輸入與輸出 (Input & Output)
  - 條件判斷 (Conditional Statements)
  - 迴圈 (Loops)
  - 綜合練習 (Combined Exercises)

使用方法 (How to Use):
  1. 閱讀每道題目的說明
  2. 在 "YOUR CODE HERE" 區塊中撰寫程式碼
  3. 執行程式碼確認結果是否正確
  4. 參考最下方的解答 (Solutions) 進行對照
"""


# ============================================================
# PART 1: 變數與資料型態 (Variables & Data Types)
# ============================================================

print("=" * 60)
print("PART 1: 變數與資料型態 (Variables & Data Types)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 1.1: 變數宣告與賦值
# 宣告以下變數並印出它們的值與型態
#   - student_name: 你的名字 (字串)
#   - student_age: 你的年齡 (整數)
#   - student_height: 你的身高,單位公分 (浮點數)
#   - is_enrolled: 是否已經註冊 (布林值)
#
# 預期輸出範例:
#   Name: Alice, Type: <class 'str'>
#   Age: 20, Type: <class 'int'>
#   Height: 165.5, Type: <class 'float'>
#   Enrolled: True, Type: <class 'bool'>
# ----------------------------------------------------------
print("\n--- Exercise 1.1: 變數宣告與賦值 ---")

student_name = "Alice"
student_age = 20
student_height = 165.5
is_enrolled = True

print(f"Name: {student_name}, Type: {type(student_name)}")
print(f"Age: {student_age}, Type: {type(student_age)}")
print(f"Height: {student_height}, Type: {type(student_height)}")
print(f"Enrolled: {is_enrolled}, Type: {type(is_enrolled)}")


# ----------------------------------------------------------
# Exercise 1.2: 多重賦值 (Multiple Assignment)
# 使用一行程式碼同時宣告三個變數:
#   x = 10, y = 20, z = 30
# 然後交換 x 和 z 的值 (使用 Pythonic 方式)
# 印出交換前後的結果
#
# 預期輸出:
#   Before swap: x=10, y=20, z=30
#   After swap: x=30, y=20, z=10
# ----------------------------------------------------------
print("\n--- Exercise 1.2: 多重賦值 ---")

x, y, z = 10, 20, 30
print(f"Before swap: x={x}, y={y}, z={z}")
x, z = z, x
print(f"After swap: x={x}, y={y}, z={z}")


# ----------------------------------------------------------
# Exercise 1.3: 型態轉換 (Type Conversion)
# 給定以下字串,將它們轉換成適當的型態並進行計算
#   price_str = "49.99"
#   quantity_str = "3"
#   discount_str = "True"
#
# 計算: total = price * quantity
# 如果 discount 為 True,打 9 折 (total * 0.9)
# 印出最終價格 (保留 2 位小數)
#
# 預期輸出:
#   Price: 49.99, Quantity: 3
#   Subtotal: 149.97
#   Discount applied: True
#   Final total: $134.97
# ----------------------------------------------------------
print("\n--- Exercise 1.3: 型態轉換 ---")

price_str = "49.99"
quantity_str = "3"
discount_str = "True"

price = float(price_str)
quantity = int(quantity_str)
discount = discount_str == "True"

subtotal = price * quantity
print(f"Price: {price}, Quantity: {quantity}")
print(f"Subtotal: {subtotal}")
print(f"Discount applied: {discount}")

if discount:
    total = subtotal * 0.9
else:
    total = subtotal
print(f"Final total: ${total:.2f}")


# ----------------------------------------------------------
# Exercise 1.4: 數字系統 (Number Systems)
# 將十進位數字 255 分別轉換為:
#   - 二進位 (binary)
#   - 八進位 (octal)
#   - 十六進位 (hexadecimal)
# 並印出結果
#
# 提示: 使用 bin(), oct(), hex() 函數
#
# 預期輸出:
#   Decimal: 255
#   Binary: 0b11111111
#   Octal: 0o377
#   Hex: 0xff
# ----------------------------------------------------------
print("\n--- Exercise 1.4: 數字系統 ---")

decimal_num = 255

print(f"Decimal: {decimal_num}")
print(f"Binary: {bin(decimal_num)}")
print(f"Octal: {oct(decimal_num)}")
print(f"Hex: {hex(decimal_num)}")


# ----------------------------------------------------------
# Exercise 1.5: 布林運算 (Boolean Operations)
# 判斷以下運算式的結果 (先不要執行,先自己想)
# 然後印出結果驗證
#
#   a) True and False
#   b) True or False
#   c) not True
#   d) (5 > 3) and (10 < 20)
#   e) (5 > 3) or (10 > 20)
#   f) not (5 == 5)
#   g) bool(0)
#   h) bool("")
#   i) bool("Hello")
#   j) bool(42)
# ----------------------------------------------------------
print("\n--- Exercise 1.5: 布林運算 ---")

print(f"a) True and False = {True and False}")
print(f"b) True or False = {True or False}")
print(f"c) not True = {not True}")
print(f"d) (5 > 3) and (10 < 20) = {(5 > 3) and (10 < 20)}")
print(f"e) (5 > 3) or (10 > 20) = {(5 > 3) or (10 > 20)}")
print(f"f) not (5 == 5) = {not (5 == 5)}")
print(f"g) bool(0) = {bool(0)}")
print(f"h) bool('') = {bool('')}")
print(f"i) bool('Hello') = {bool('Hello')}")
print(f"j) bool(42) = {bool(42)}")


# ============================================================
# PART 2: 運算子 (Operators)
# ============================================================

print("\n" + "=" * 60)
print("PART 2: 運算子 (Operators)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 2.1: 算術運算子 (Arithmetic Operators)
# 給定兩個數字 a = 17, b = 5
# 計算並印出所有算術運算的結果:
#   加法、減法、乘法、除法、整數除法、取餘數、次方
#
# 預期輸出:
#   a + b = 22
#   a - b = 12
#   a * b = 85
#   a / b = 3.4
#   a // b = 3
#   a % b = 2
#   a ** b = 1419857
# ----------------------------------------------------------
print("\n--- Exercise 2.1: 算術運算子 ---")

a = 17
b = 5

print(f"a + b = {a + b}")
print(f"a - b = {a - b}")
print(f"a * b = {a * b}")
print(f"a / b = {a / b}")
print(f"a // b = {a // b}")
print(f"a % b = {a % b}")
print(f"a ** b = {a ** b}")


# ----------------------------------------------------------
# Exercise 2.2: 複合賦值運算子 (Compound Assignment Operators)
# 從 x = 100 開始,依序執行以下操作,並在每步印出結果:
#   1. x += 50    (加 50)
#   2. x -= 30    (減 30)
#   3. x *= 2     (乘以 2)
#   4. x //= 3    (整除 3)
#   5. x %= 7     (取餘數 7)
#   6. x **= 3    (三次方)
#
# 每步印出:  Step N: x = ???
# ----------------------------------------------------------
print("\n--- Exercise 2.2: 複合賦值運算子 ---")

x = 100

x += 50
print(f"Step 1: x = {x}")   # 150
x -= 30
print(f"Step 2: x = {x}")   # 120
x *= 2
print(f"Step 3: x = {x}")   # 240
x //= 3
print(f"Step 4: x = {x}")   # 80
x %= 7
print(f"Step 5: x = {x}")   # 3
x **= 3
print(f"Step 6: x = {x}")   # 27


# ----------------------------------------------------------
# Exercise 2.3: 比較運算子 (Comparison Operators)
# 給定 score = 78,判斷以下各條件是否為 True:
#   a) score >= 90  (A 等級)
#   b) score >= 80  (B 等級)
#   c) score >= 70  (C 等級)
#   d) score == 78  (剛好 78 分)
#   e) score != 100 (不是滿分)
#   f) 60 <= score < 80  (D 或 C 等級)
#
# 預期輸出:
#   score >= 90: False
#   score >= 80: False
#   score >= 70: True
#   score == 78: True
#   score != 100: True
#   60 <= score < 80: True
# ----------------------------------------------------------
print("\n--- Exercise 2.3: 比較運算子 ---")

score = 78

print(f"score >= 90: {score >= 90}")
print(f"score >= 80: {score >= 80}")
print(f"score >= 70: {score >= 70}")
print(f"score == 78: {score == 78}")
print(f"score != 100: {score != 100}")
print(f"60 <= score < 80: {60 <= score < 80}")


# ----------------------------------------------------------
# Exercise 2.4: 運算優先順序 (Operator Precedence)
# 計算以下運算式的結果 (先自己算,再用 Python 驗證)
#   a) 2 + 3 * 4
#   b) (2 + 3) * 4
#   c) 10 - 2 ** 3
#   d) 15 // 4 + 15 % 4
#   e) 2 ** 3 ** 2    (提示: ** 是右結合)
#   f) not True or False and True
# ----------------------------------------------------------
print("\n--- Exercise 2.4: 運算優先順序 ---")

print(f"a) 2 + 3 * 4 = {2 + 3 * 4}")                        # 14
print(f"b) (2 + 3) * 4 = {(2 + 3) * 4}")                      # 20
print(f"c) 10 - 2 ** 3 = {10 - 2 ** 3}")                      # 2
print(f"d) 15 // 4 + 15 % 4 = {15 // 4 + 15 % 4}")            # 6
print(f"e) 2 ** 3 ** 2 = {2 ** 3 ** 2}")                       # 512
print(f"f) not True or False and True = {not True or False and True}")  # False


# ============================================================
# PART 3: 字串操作 (String Operations)
# ============================================================

print("\n" + "=" * 60)
print("PART 3: 字串操作 (String Operations)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 3.1: 字串基本操作
# 給定字串 sentence = "  Hello, Python World!  "
# 完成以下操作:
#   a) 去除前後空白
#   b) 轉為大寫
#   c) 轉為小寫
#   d) 將 "Python" 替換為 "Java"
#   e) 用空格分割成 list
#   f) 計算字串長度 (去除空白後)
#
# 印出每步結果
# ----------------------------------------------------------
print("\n--- Exercise 3.1: 字串基本操作 ---")

sentence = "  Hello, Python World!  "

cleaned = sentence.strip()
print(f"a) Stripped: '{cleaned}'")
print(f"b) Upper: '{cleaned.upper()}'")
print(f"c) Lower: '{cleaned.lower()}'")
print(f"d) Replaced: '{cleaned.replace('Python', 'Java')}'")
print(f"e) Split: {cleaned.split()}")
print(f"f) Length: {len(cleaned)}")


# ----------------------------------------------------------
# Exercise 3.2: 字串索引與切片 (String Indexing & Slicing)
# 給定字串 text = "Programming"
# 取出以下子字串:
#   a) 第一個字元          -> "P"
#   b) 最後一個字元        -> "g"
#   c) 前 4 個字元         -> "Prog"
#   d) 後 4 個字元         -> "ming"
#   e) 從第 3 到第 7 個字元 -> "gram"
#   f) 反轉字串            -> "gnimmargorP"
#   g) 每隔一個字元取      -> "Pormig"
# ----------------------------------------------------------
print("\n--- Exercise 3.2: 字串索引與切片 ---")

text = "Programming"

print(f"a) First char: {text[0]}")
print(f"b) Last char: {text[-1]}")
print(f"c) First 4: {text[:4]}")
print(f"d) Last 4: {text[-4:]}")
print(f"e) 3rd to 7th: {text[2:6]}")
print(f"f) Reversed: {text[::-1]}")
print(f"g) Every other: {text[::2]}")


# ----------------------------------------------------------
# Exercise 3.3: f-string 格式化
# 使用 f-string 格式化以下資料:
#   name = "Alice"
#   score = 87.5
#   rank = 3
#
# 印出:
#   Student: Alice
#   Score: 87.50 (保留 2 位小數)
#   Rank: 003 (補零到 3 位)
#   Result: Alice got 87.5 points and ranked #3
# ----------------------------------------------------------
print("\n--- Exercise 3.3: f-string 格式化 ---")

name = "Alice"
score = 87.5
rank = 3

print(f"Student: {name}")
print(f"Score: {score:.2f}")
print(f"Rank: {rank:03d}")
print(f"Result: {name} got {score} points and ranked #{rank}")


# ----------------------------------------------------------
# Exercise 3.4: 字串方法練習
# 給定以下電子郵件地址:
#   email = "  User.Name@Example.COM  "
#
# 完成以下操作:
#   a) 清除前後空白並轉為小寫
#   b) 檢查是否包含 "@" 符號
#   c) 取出 "@" 前面的使用者名稱
#   d) 取出 "@" 後面的網域名稱
#   e) 檢查網域是否以 ".com" 結尾
#   f) 將使用者名稱中的 "." 替換為 "_"
#
# 預期輸出:
#   Cleaned email: user.name@example.com
#   Contains @: True
#   Username: user.name
#   Domain: example.com
#   Is .com: True
#   Modified username: user_name
# ----------------------------------------------------------
print("\n--- Exercise 3.4: 字串方法練習 ---")

email = "  User.Name@Example.COM  "

cleaned_email = email.strip().lower()
print(f"Cleaned email: {cleaned_email}")
print(f"Contains @: {'@' in cleaned_email}")

at_index = cleaned_email.index("@")
username = cleaned_email[:at_index]
domain = cleaned_email[at_index + 1:]

print(f"Username: {username}")
print(f"Domain: {domain}")
print(f"Is .com: {domain.endswith('.com')}")
print(f"Modified username: {username.replace('.', '_')}")


# ----------------------------------------------------------
# Exercise 3.5: 字串檢查方法 (String Checking Methods)
# 判斷以下字串各屬於什麼類型:
#   a) "Hello123"    -> isalnum()? isalpha()? isdigit()?
#   b) "12345"       -> isalnum()? isalpha()? isdigit()?
#   c) "Hello"       -> isalnum()? isalpha()? isdigit()?
#   d) "hello world" -> isalnum()? isalpha()? islower()?
#   e) "HELLO"       -> isupper()? isalpha()?
#   f) "   "         -> isspace()?
# ----------------------------------------------------------
print("\n--- Exercise 3.5: 字串檢查方法 ---")

test_strings = ["Hello123", "12345", "Hello", "hello world", "HELLO", "   "]

for s in test_strings:
    print(f"'{s}': isalnum={s.isalnum()}, isalpha={s.isalpha()}, "
          f"isdigit={s.isdigit()}, islower={s.islower()}, "
          f"isupper={s.isupper()}, isspace={s.isspace()}")


# ============================================================
# PART 4: 條件判斷 (Conditional Statements)
# ============================================================

print("\n" + "=" * 60)
print("PART 4: 條件判斷 (Conditional Statements)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 4.1: 基本 if/else
# 給定一個年份 year,判斷它是否為閏年
# 閏年規則:
#   - 能被 4 整除 且 不能被 100 整除 → 閏年
#   - 能被 400 整除 → 閏年
#   - 其他 → 平年
#
# 測試: year = 2024, 1900, 2000, 2023
# ----------------------------------------------------------
print("\n--- Exercise 4.1: 閏年判斷 ---")

test_years = [2024, 1900, 2000, 2023]

for year in test_years:
    if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
        print(f"{year} is a leap year")
    else:
        print(f"{year} is not a leap year")


# ----------------------------------------------------------
# Exercise 4.2: 成績等級判斷
# 給定一個分數 score (0-100),判斷等級:
#   90-100: A+ (Outstanding)
#   85-89:  A  (Excellent)
#   80-84:  B+ (Very Good)
#   75-79:  B  (Good)
#   70-74:  C+ (Above Average)
#   60-69:  C  (Average)
#   50-59:  D  (Below Average)
#   0-49:   F  (Fail)
#   其他:   Invalid score
#
# 測試: scores = [95, 87, 82, 76, 71, 65, 55, 42, -5, 105]
# ----------------------------------------------------------
print("\n--- Exercise 4.2: 成績等級判斷 ---")

scores = [95, 87, 82, 76, 71, 65, 55, 42, -5, 105]

for score in scores:
    if score < 0 or score > 100:
        grade = "Invalid score"
    elif score >= 90:
        grade = "A+ (Outstanding)"
    elif score >= 85:
        grade = "A (Excellent)"
    elif score >= 80:
        grade = "B+ (Very Good)"
    elif score >= 75:
        grade = "B (Good)"
    elif score >= 70:
        grade = "C+ (Above Average)"
    elif score >= 60:
        grade = "C (Average)"
    elif score >= 50:
        grade = "D (Below Average)"
    else:
        grade = "F (Fail)"
    print(f"Score {score}: {grade}")


# ----------------------------------------------------------
# Exercise 4.3: BMI 計算器
# 給定體重 weight (kg) 和身高 height (m)
# 計算 BMI = weight / (height ** 2)
# 判斷 BMI 類別:
#   BMI < 18.5:        Underweight
#   18.5 <= BMI < 24:  Normal
#   24 <= BMI < 27:    Overweight
#   27 <= BMI < 30:    Mild Obesity
#   30 <= BMI < 35:    Moderate Obesity
#   BMI >= 35:         Severe Obesity
#
# 測試資料:
#   weight = 70, height = 1.75
#   weight = 50, height = 1.70
#   weight = 95, height = 1.65
# ----------------------------------------------------------
print("\n--- Exercise 4.3: BMI 計算器 ---")

test_data = [
    (70, 1.75),
    (50, 1.70),
    (95, 1.65),
]

for weight, height in test_data:
    bmi = weight / (height ** 2)
    if bmi < 18.5:
        category = "Underweight"
    elif bmi < 24:
        category = "Normal"
    elif bmi < 27:
        category = "Overweight"
    elif bmi < 30:
        category = "Mild Obesity"
    elif bmi < 35:
        category = "Moderate Obesity"
    else:
        category = "Severe Obesity"
    print(f"Weight: {weight}kg, Height: {height}m, BMI: {bmi:.1f}, Category: {category}")


# ----------------------------------------------------------
# Exercise 4.4: 簡易計算機 (Nested Conditions)
# 寫一個簡易計算機:
#   1. 給定兩個數字和一個運算符號
#   2. 支援 +, -, *, /, //, %, **
#   3. 除法需要檢查除數是否為零
#   4. 印出計算結果
#
# 測試資料:
#   (10, "+", 3) -> 10 + 3 = 13
#   (10, "/", 0) -> Error: Division by zero!
#   (2, "**", 8) -> 2 ** 8 = 256
#   (17, "%", 5) -> 17 % 5 = 2
# ----------------------------------------------------------
print("\n--- Exercise 4.4: 簡易計算機 ---")

test_calculations = [
    (10, "+", 3),
    (10, "-", 3),
    (10, "*", 3),
    (10, "/", 3),
    (10, "/", 0),
    (2, "**", 8),
    (17, "%", 5),
    (17, "//", 5),
]

for num1, op, num2 in test_calculations:
    if op == "+":
        result = num1 + num2
    elif op == "-":
        result = num1 - num2
    elif op == "*":
        result = num1 * num2
    elif op == "/":
        if num2 == 0:
            print(f"{num1} {op} {num2} = Error: Division by zero!")
            continue
        result = num1 / num2
    elif op == "//":
        if num2 == 0:
            print(f"{num1} {op} {num2} = Error: Division by zero!")
            continue
        result = num1 // num2
    elif op == "%":
        result = num1 % num2
    elif op == "**":
        result = num1 ** num2
    else:
        print(f"Unknown operator: {op}")
        continue
    print(f"{num1} {op} {num2} = {result}")


# ----------------------------------------------------------
# Exercise 4.5: 三角形判斷
# 給定三個邊長 a, b, c,判斷:
#   1. 是否能構成三角形 (任兩邊之和大於第三邊)
#   2. 如果能構成三角形,判斷是什麼類型:
#      - 等邊三角形 (Equilateral): 三邊相等
#      - 等腰三角形 (Isosceles): 恰好兩邊相等
#      - 不等邊三角形 (Scalene): 三邊都不相等
#   3. 額外判斷是否為直角三角形 (Pythagorean theorem)
#
# 測試資料:
#   (3, 4, 5)  -> Scalene, Right triangle
#   (5, 5, 5)  -> Equilateral
#   (3, 3, 5)  -> Isosceles
#   (1, 2, 10) -> Not a valid triangle
# ----------------------------------------------------------
print("\n--- Exercise 4.5: 三角形判斷 ---")

test_triangles = [
    (3, 4, 5),
    (5, 5, 5),
    (3, 3, 5),
    (1, 2, 10),
    (5, 12, 13),
    (7, 7, 7),
]

for a, b, c in test_triangles:
    if a + b > c and b + c > a and a + c > b:
        if a == b == c:
            triangle_type = "Equilateral"
        elif a == b or b == c or a == c:
            triangle_type = "Isosceles"
        else:
            triangle_type = "Scalene"

        sides = sorted([a, b, c])
        if sides[0] ** 2 + sides[1] ** 2 == sides[2] ** 2:
            triangle_type += ", Right triangle"

        print(f"({a}, {b}, {c}): Valid - {triangle_type}")
    else:
        print(f"({a}, {b}, {c}): Not a valid triangle")


# ============================================================
# PART 5: for 迴圈 (For Loops)
# ============================================================

print("\n" + "=" * 60)
print("PART 5: for 迴圈 (For Loops)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 5.1: 基本 range 練習
# 使用 range() 和 for 迴圈:
#   a) 印出 1 到 20 的所有偶數
#   b) 印出 100 到 50 的倒數 (每次減 10)
#   c) 印出 1 到 100 的總和
#   d) 印出 1 到 10 的階乘 (10!)
# ----------------------------------------------------------
print("\n--- Exercise 5.1: 基本 range 練習 ---")

# a) 偶數
print("Even numbers 1-20:", end=" ")
for i in range(2, 21, 2):
    print(i, end=" ")
print()

# b) 倒數
print("100 to 50 countdown:", end=" ")
for i in range(100, 49, -10):
    print(i, end=" ")
print()

# c) 總和
total = 0
for i in range(1, 101):
    total += i
print(f"Sum 1 to 100: {total}")

# d) 階乘
factorial = 1
for i in range(1, 11):
    factorial *= i
print(f"10! = {factorial}")


# ----------------------------------------------------------
# Exercise 5.2: 九九乘法表
# 印出完整的九九乘法表 (1x1 到 9x9)
# 格式要求:
#   1x1= 1  1x2= 2  1x3= 3 ...
#   2x1= 2  2x2= 4  2x3= 6 ...
#   ...
#   9x1= 9  9x2=18  9x3=27 ...
# ----------------------------------------------------------
print("\n--- Exercise 5.2: 九九乘法表 ---")

for i in range(1, 10):
    for j in range(1, 10):
        print(f"{i}x{j}={i*j:2}", end="  ")
    print()


# ----------------------------------------------------------
# Exercise 5.3: 星號圖案 (Star Patterns)
# 使用 for 迴圈印出以下圖案 (n = 5):
#
# Pattern A: 直角三角形
# *
# **
# ***
# ****
# *****
#
# Pattern B: 倒直角三角形
# *****
# ****
# ***
# **
# *
#
# Pattern C: 等腰三角形
#     *
#    ***
#   *****
#  *******
# *********
#
# Pattern D: 菱形
#     *
#    ***
#   *****
#  *******
# *********
#  *******
#   *****
#    ***
#     *
# ----------------------------------------------------------
print("\n--- Exercise 5.3: 星號圖案 ---")

n = 5

# Pattern A
print("Pattern A:")
for i in range(1, n + 1):
    print("*" * i)

# Pattern B
print("\nPattern B:")
for i in range(n, 0, -1):
    print("*" * i)

# Pattern C
print("\nPattern C:")
for i in range(1, n + 1):
    spaces = " " * (n - i)
    stars = "*" * (2 * i - 1)
    print(spaces + stars)

# Pattern D
print("\nPattern D:")
for i in range(1, n + 1):
    spaces = " " * (n - i)
    stars = "*" * (2 * i - 1)
    print(spaces + stars)
for i in range(n - 1, 0, -1):
    spaces = " " * (n - i)
    stars = "*" * (2 * i - 1)
    print(spaces + stars)


# ----------------------------------------------------------
# Exercise 5.4: List 迭代練習
# 給定一個學生成績列表:
#   grades = [88, 72, 95, 60, 45, 83, 91, 77, 68, 54]
#
# 使用 for 迴圈計算:
#   a) 最高分和最低分
#   b) 平均分數
#   c) 及格 (>= 60) 和不及格的人數
#   d) 高於平均的學生編號 (從 1 開始)
#
# 注意: 不要使用 max(), min(), sum() 等內建函數
# ----------------------------------------------------------
print("\n--- Exercise 5.4: List 迭代練習 ---")

grades = [88, 72, 95, 60, 45, 83, 91, 77, 68, 54]

max_grade = grades[0]
min_grade = grades[0]
total = 0
pass_count = 0
fail_count = 0

for i, g in enumerate(grades):
    total += g
    if g > max_grade:
        max_grade = g
    if g < min_grade:
        min_grade = g
    if g >= 60:
        pass_count += 1
    else:
        fail_count += 1

average = total / len(grades)
print(f"Max: {max_grade}, Min: {min_grade}")
print(f"Average: {average:.2f}")
print(f"Pass: {pass_count}, Fail: {fail_count}")

print("Above average students:", end=" ")
for i, g in enumerate(grades):
    if g > average:
        print(f"#{i+1}({g})", end=" ")
print()


# ----------------------------------------------------------
# Exercise 5.5: enumerate 和 zip 練習
# 給定:
#   names = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
#   scores = [88, 72, 95, 60, 83]
#
# a) 使用 enumerate 印出每個學生的排名和名字
#    (排名從 1 開始)
# b) 使用 zip 將名字和分數配對印出
# c) 找出最高分的學生名字
# ----------------------------------------------------------
print("\n--- Exercise 5.5: enumerate 和 zip 練習 ---")

names = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
scores = [88, 72, 95, 60, 83]

# a) enumerate
print("a) Student list:")
for i, name in enumerate(names, 1):
    print(f"  #{i}: {name}")

# b) zip
print("b) Name-score pairs:")
for name, score in zip(names, scores):
    print(f"  {name}: {score}")

# c) 最高分
best_name = names[0]
best_score = scores[0]
for name, score in zip(names, scores):
    if score > best_score:
        best_score = score
        best_name = name
print(f"c) Top student: {best_name} ({best_score})")


# ----------------------------------------------------------
# Exercise 5.6: 字典迭代 (Dictionary Iteration)
# 給定一個學生資料字典:
#   students = {
#       "Alice": {"age": 20, "grade": 88, "major": "CS"},
#       "Bob": {"age": 21, "grade": 72, "major": "Math"},
#       "Charlie": {"age": 19, "grade": 95, "major": "CS"},
#       "Diana": {"age": 22, "grade": 60, "major": "Physics"},
#       "Eve": {"age": 20, "grade": 83, "major": "CS"},
#   }
#
# 使用 for 迴圈:
#   a) 印出所有學生的名字和成績
#   b) 計算 CS 主修學生的平均成績
#   c) 找出成績最高的學生
#   d) 列出所有不同的主修 (不重複)
# ----------------------------------------------------------
print("\n--- Exercise 5.6: 字典迭代 ---")

students = {
    "Alice": {"age": 20, "grade": 88, "major": "CS"},
    "Bob": {"age": 21, "grade": 72, "major": "Math"},
    "Charlie": {"age": 19, "grade": 95, "major": "CS"},
    "Diana": {"age": 22, "grade": 60, "major": "Physics"},
    "Eve": {"age": 20, "grade": 83, "major": "CS"},
}

# a) 印出所有學生的名字和成績
print("a) All students:")
for name, info in students.items():
    print(f"  {name}: grade={info['grade']}")

# b) 計算 CS 主修學生的平均成績
cs_total = 0
cs_count = 0
for name, info in students.items():
    if info["major"] == "CS":
        cs_total += info["grade"]
        cs_count += 1
print(f"b) CS average: {cs_total / cs_count:.2f}")

# c) 找出成績最高的學生
top_name = ""
top_grade = 0
for name, info in students.items():
    if info["grade"] > top_grade:
        top_grade = info["grade"]
        top_name = name
print(f"c) Top student: {top_name} ({top_grade})")

# d) 列出所有不同的主修
majors = []
for name, info in students.items():
    if info["major"] not in majors:
        majors.append(info["major"])
print(f"d) Majors: {majors}")


# ============================================================
# PART 6: while 迴圈 (While Loops)
# ============================================================

print("\n" + "=" * 60)
print("PART 6: while 迴圈 (While Loops)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 6.1: 數字猜測
# 不使用 input(),模擬猜數字遊戲:
#   - 目標數字 target = 42
#   - 猜測列表 guesses = [10, 30, 50, 40, 45, 42]
#   - 從列表中依序取出猜測值
#   - 印出 "Too low!", "Too high!", 或 "Correct!"
#   - 記錄猜了幾次
# ----------------------------------------------------------
print("\n--- Exercise 6.1: 數字猜測 ---")

target = 42
guesses = [10, 30, 50, 40, 45, 42]

index = 0
while index < len(guesses):
    guess = guesses[index]
    if guess == target:
        print(f"Guess {guess}... Correct! Found in {index + 1} attempts!")
        break
    elif guess < target:
        print(f"Guess {guess}... Too low!")
    else:
        print(f"Guess {guess}... Too high!")
    index += 1


# ----------------------------------------------------------
# Exercise 6.2: Collatz 猜想 (3n+1 問題)
# 給定一個正整數 n:
#   - 如果 n 是偶數,n = n / 2
#   - 如果 n 是奇數,n = 3n + 1
#   - 重複直到 n = 1
#
# 印出整個過程和步數
#
# 測試: n = 27
# 預期: 27 → 82 → 41 → 124 → 62 → 31 → ... → 1
# ----------------------------------------------------------
print("\n--- Exercise 6.2: Collatz 猜想 ---")

n = 27

steps = 0
print(n, end="")
while n != 1:
    if n % 2 == 0:
        n = n // 2
    else:
        n = 3 * n + 1
    steps += 1
    print(f" → {n}", end="")
print(f"\nTotal steps: {steps}")


# ----------------------------------------------------------
# Exercise 6.3: 反轉數字
# 使用 while 迴圈將一個整數反轉
#   例如: 12345 → 54321
#         -6789 → -9876
#
# 提示: 使用 % 10 取得個位數,// 10 去掉個位數
# 注意: 不要使用字串轉換的方式
# ----------------------------------------------------------
print("\n--- Exercise 6.3: 反轉數字 ---")

test_numbers = [12345, -6789, 100, 7, 9900]

for num in test_numbers:
    original = num
    negative = num < 0
    num = abs(num)
    reversed_num = 0
    while num > 0:
        reversed_num = reversed_num * 10 + num % 10
        num //= 10
    if negative:
        reversed_num = -reversed_num
    print(f"{original} → {reversed_num}")


# ----------------------------------------------------------
# Exercise 6.4: 數字拆解與統計
# 使用 while 迴圈,對於一個正整數:
#   a) 計算位數 (幾位數)
#   b) 計算各位數字之和
#   c) 判斷是否為回文數 (正反讀都一樣)
#   d) 找出最大和最小的位數
#
# 測試: numbers = [12321, 9876, 1001, 54321, 11111]
#
# 注意: 只能使用 while 迴圈和數學運算,不能轉字串
# ----------------------------------------------------------
print("\n--- Exercise 6.4: 數字拆解與統計 ---")

numbers = [12321, 9876, 1001, 54321, 11111]

for num in numbers:
    original = num
    digit_count = 0
    digit_sum = 0
    max_digit = 0
    min_digit = 9
    reversed_num = 0
    temp = num

    while temp > 0:
        d = temp % 10
        digit_count += 1
        digit_sum += d
        if d > max_digit:
            max_digit = d
        if d < min_digit:
            min_digit = d
        reversed_num = reversed_num * 10 + d
        temp //= 10

    is_palindrome = original == reversed_num
    print(f"{original}: digits={digit_count}, sum={digit_sum}, "
          f"max={max_digit}, min={min_digit}, palindrome={is_palindrome}")


# ============================================================
# PART 7: 迴圈控制 (Loop Control: break, continue, pass)
# ============================================================

print("\n" + "=" * 60)
print("PART 7: 迴圈控制 (Loop Control)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 7.1: break 練習
# 在列表中搜尋目標值,找到時立即停止
#   data = [4, 7, 2, 9, 1, 5, 8, 3, 6, 10]
#   target = 5
#
# 印出搜尋過程和結果:
#   Checking 4... not found
#   Checking 7... not found
#   Checking 2... not found
#   Checking 9... not found
#   Checking 1... not found
#   Checking 5... FOUND at index 5!
# ----------------------------------------------------------
print("\n--- Exercise 7.1: break 練習 ---")

data = [4, 7, 2, 9, 1, 5, 8, 3, 6, 10]
target = 5

for i, val in enumerate(data):
    if val == target:
        print(f"Checking {val}... FOUND at index {i}!")
        break
    else:
        print(f"Checking {val}... not found")


# ----------------------------------------------------------
# Exercise 7.2: continue 練習
# 給定一個混合列表:
#   items = [1, "hello", 3.14, None, 5, "world", 7, None, 9.5, 2]
#
# 只印出數字 (int 和 float),跳過其他型態
# 並計算所有數字的總和
# ----------------------------------------------------------
print("\n--- Exercise 7.2: continue 練習 ---")

items = [1, "hello", 3.14, None, 5, "world", 7, None, 9.5, 2]

total = 0
for item in items:
    if not isinstance(item, (int, float)):
        continue
    print(f"Number found: {item}")
    total += item
print(f"Sum of numbers: {total}")


# ----------------------------------------------------------
# Exercise 7.3: 質數判斷 (Prime Number)
# 寫程式判斷一個數字是否為質數
# 然後找出 2 到 100 之間的所有質數
#
# 提示:
#   - 質數: 只能被 1 和自己整除的大於 1 的正整數
#   - 檢查 2 到 sqrt(n) 的因數即可
#   - 使用 break 提早結束檢查
#
# 預期輸出: 2, 3, 5, 7, 11, 13, ...
# ----------------------------------------------------------
print("\n--- Exercise 7.3: 質數判斷 ---")

primes = []
for num in range(2, 101):
    is_prime = True
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            is_prime = False
            break
    if is_prime:
        primes.append(num)
print(f"Primes (2-100): {primes}")


# ----------------------------------------------------------
# Exercise 7.4: FizzBuzz
# 經典面試題: 印出 1 到 50 的數字,但:
#   - 如果是 3 的倍數,印 "Fizz"
#   - 如果是 5 的倍數,印 "Buzz"
#   - 如果同時是 3 和 5 的倍數,印 "FizzBuzz"
#   - 其他情況印數字
#
# 輸出格式: 每行 10 個,用 tab 分隔
# ----------------------------------------------------------
print("\n--- Exercise 7.4: FizzBuzz ---")

for i in range(1, 51):
    if i % 15 == 0:
        val = "FizzBuzz"
    elif i % 3 == 0:
        val = "Fizz"
    elif i % 5 == 0:
        val = "Buzz"
    else:
        val = str(i)
    print(f"{val}\t", end="")
    if i % 10 == 0:
        print()


# ============================================================
# PART 8: 巢狀迴圈 (Nested Loops)
# ============================================================

print("\n" + "=" * 60)
print("PART 8: 巢狀迴圈 (Nested Loops)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 8.1: 座位表
# 一個教室有 4 排 (rows),每排 6 個座位 (seats)
# 印出所有座位號碼:
#   Row 1: [1-1] [1-2] [1-3] [1-4] [1-5] [1-6]
#   Row 2: [2-1] [2-2] [2-3] [2-4] [2-5] [2-6]
#   Row 3: [3-1] [3-2] [3-3] [3-4] [3-5] [3-6]
#   Row 4: [4-1] [4-2] [4-3] [4-4] [4-5] [4-6]
# ----------------------------------------------------------
print("\n--- Exercise 8.1: 座位表 ---")

rows = 4
seats = 6

for r in range(1, rows + 1):
    print(f"Row {r}: ", end="")
    for s in range(1, seats + 1):
        print(f"[{r}-{s}]", end=" ")
    print()


# ----------------------------------------------------------
# Exercise 8.2: 二維列表處理
# 給定一個 4x4 的矩陣 (二維列表):
#   matrix = [
#       [1, 2, 3, 4],
#       [5, 6, 7, 8],
#       [9, 10, 11, 12],
#       [13, 14, 15, 16],
#   ]
#
# 計算:
#   a) 所有元素的總和
#   b) 每一列 (row) 的總和
#   c) 每一行 (column) 的總和
#   d) 對角線的總和 (主對角線 + 副對角線)
#   e) 印出矩陣的轉置 (行列互換)
# ----------------------------------------------------------
print("\n--- Exercise 8.2: 二維列表處理 ---")

matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16],
]

# a) 所有元素的總和
total = 0
for row in matrix:
    for val in row:
        total += val
print(f"a) Total sum: {total}")

# b) 每一列的總和
print("b) Row sums:")
for i, row in enumerate(matrix):
    row_sum = 0
    for val in row:
        row_sum += val
    print(f"   Row {i+1} sum: {row_sum}")

# c) 每一行的總和
print("c) Column sums:")
for j in range(len(matrix[0])):
    col_sum = 0
    for i in range(len(matrix)):
        col_sum += matrix[i][j]
    print(f"   Column {j+1} sum: {col_sum}")

# d) 對角線的總和
main_diag = 0
anti_diag = 0
size = len(matrix)
for i in range(size):
    main_diag += matrix[i][i]
    anti_diag += matrix[i][size - 1 - i]
print(f"d) Main diagonal sum: {main_diag}")
print(f"   Anti diagonal sum: {anti_diag}")

# e) 轉置矩陣
print("e) Transposed matrix:")
for j in range(len(matrix[0])):
    for i in range(len(matrix)):
        print(f"{matrix[i][j]:4}", end="")
    print()


# ----------------------------------------------------------
# Exercise 8.3: 密碼驗證器
# 給定一組密碼列表,檢查每個密碼是否符合以下規則:
#   - 長度至少 8 個字元
#   - 至少包含 1 個大寫字母
#   - 至少包含 1 個小寫字母
#   - 至少包含 1 個數字
#   - 至少包含 1 個特殊字元 (!@#$%^&*)
#
# 對每個密碼印出驗證結果和不符合的條件
#
# 測試:
#   passwords = ["Abc12345!", "password", "SHORT1!", "NoSpecial1",
#                "alllowercase1!", "ALLUPPERCASE1!", "NoDigits!abc"]
# ----------------------------------------------------------
print("\n--- Exercise 8.3: 密碼驗證器 ---")

passwords = [
    "Abc12345!",
    "password",
    "SHORT1!",
    "NoSpecial1",
    "alllowercase1!",
    "ALLUPPERCASE1!",
    "NoDigits!abc",
]

special_chars = "!@#$%^&*"
for pwd in passwords:
    errors = []
    if len(pwd) < 8:
        errors.append("too short")
    has_upper = False
    has_lower = False
    has_digit = False
    has_special = False
    for ch in pwd:
        if ch.isupper():
            has_upper = True
        elif ch.islower():
            has_lower = True
        elif ch.isdigit():
            has_digit = True
        elif ch in special_chars:
            has_special = True
    if not has_upper:
        errors.append("no uppercase")
    if not has_lower:
        errors.append("no lowercase")
    if not has_digit:
        errors.append("no digit")
    if not has_special:
        errors.append("no special char")

    if errors:
        print(f"'{pwd}': WEAK - {', '.join(errors)}")
    else:
        print(f"'{pwd}': STRONG")


# ============================================================
# PART 9: 綜合練習 (Combined Exercises)
# ============================================================

print("\n" + "=" * 60)
print("PART 9: 綜合練習 (Combined Exercises)")
print("=" * 60)

# ----------------------------------------------------------
# Exercise 9.1: 購物車計算器
# 給定一個購物車資料:
#   cart = [
#       {"item": "Apple", "price": 1.50, "quantity": 4},
#       {"item": "Bread", "price": 2.99, "quantity": 2},
#       {"item": "Milk", "price": 3.49, "quantity": 1},
#       {"item": "Eggs", "price": 4.99, "quantity": 2},
#       {"item": "Rice", "price": 8.99, "quantity": 1},
#   ]
#
# 計算:
#   a) 每個商品的小計 (price * quantity)
#   b) 購物車總金額
#   c) 如果總金額超過 $30,打 9 折
#   d) 稅金 (5%)
#   e) 最終付款金額
#   f) 印出漂亮的收據 (receipt)
# ----------------------------------------------------------
print("\n--- Exercise 9.1: 購物車計算器 ---")

cart = [
    {"item": "Apple", "price": 1.50, "quantity": 4},
    {"item": "Bread", "price": 2.99, "quantity": 2},
    {"item": "Milk", "price": 3.49, "quantity": 1},
    {"item": "Eggs", "price": 4.99, "quantity": 2},
    {"item": "Rice", "price": 8.99, "quantity": 1},
]

print("=" * 40)
print("         RECEIPT")
print("=" * 40)
subtotal = 0
for item in cart:
    item_total = item["price"] * item["quantity"]
    subtotal += item_total
    print(f"{item['item']:<10} x{item['quantity']}  ${item['price']:>6.2f}  ${item_total:>7.2f}")

print("-" * 40)
print(f"{'Subtotal':<25} ${subtotal:>7.2f}")

if subtotal > 30:
    discount = subtotal * 0.1
    print(f"{'Discount (10%)':<25} -${discount:>6.2f}")
    after_discount = subtotal - discount
else:
    discount = 0
    after_discount = subtotal

tax = after_discount * 0.05
final = after_discount + tax
print(f"{'Tax (5%)':<25} ${tax:>7.2f}")
print("=" * 40)
print(f"{'TOTAL':<25} ${final:>7.2f}")
print("=" * 40)


# ----------------------------------------------------------
# Exercise 9.2: 學生成績報告
# 給定多個學生的多科成績:
#   report = {
#       "Alice":   {"Math": 92, "English": 88, "Science": 95, "History": 78},
#       "Bob":     {"Math": 76, "English": 82, "Science": 71, "History": 90},
#       "Charlie": {"Math": 88, "English": 91, "Science": 84, "History": 87},
#       "Diana":   {"Math": 65, "English": 70, "Science": 62, "History": 68},
#       "Eve":     {"Math": 95, "English": 93, "Science": 98, "History": 92},
#   }
#
# 計算並印出:
#   a) 每個學生的平均成績和等級 (A/B/C/D/F)
#   b) 每個科目的班級平均分
#   c) 全班最高分的學生和科目
#   d) 全班最低分的學生和科目
#   e) 印出漂亮的成績報告表格
# ----------------------------------------------------------
print("\n--- Exercise 9.2: 學生成績報告 ---")

report = {
    "Alice":   {"Math": 92, "English": 88, "Science": 95, "History": 78},
    "Bob":     {"Math": 76, "English": 82, "Science": 71, "History": 90},
    "Charlie": {"Math": 88, "English": 91, "Science": 84, "History": 87},
    "Diana":   {"Math": 65, "English": 70, "Science": 62, "History": 68},
    "Eve":     {"Math": 95, "English": 93, "Science": 98, "History": 92},
}

print(f"{'Student':<10} {'Math':>6} {'Eng':>6} {'Sci':>6} {'Hist':>6} {'Avg':>6} {'Grade'}")
print("-" * 52)

all_highest = ("", "", 0)
all_lowest = ("", "", 101)

for student, subjects in report.items():
    total = 0
    for subj, score in subjects.items():
        total += score
        if score > all_highest[2]:
            all_highest = (student, subj, score)
        if score < all_lowest[2]:
            all_lowest = (student, subj, score)
    avg = total / len(subjects)
    if avg >= 90:
        grade = "A"
    elif avg >= 80:
        grade = "B"
    elif avg >= 70:
        grade = "C"
    elif avg >= 60:
        grade = "D"
    else:
        grade = "F"
    print(f"{student:<10} {subjects['Math']:>6} {subjects['English']:>6} "
          f"{subjects['Science']:>6} {subjects['History']:>6} {avg:>6.1f} {grade:>5}")

print(f"\nHighest: {all_highest[0]} - {all_highest[1]}: {all_highest[2]}")
print(f"Lowest: {all_lowest[0]} - {all_lowest[1]}: {all_lowest[2]}")


# ----------------------------------------------------------
# Exercise 9.3: 數字猜謎遊戲 (進階版)
# 模擬一個二分搜尋猜數字的策略:
#   - 目標數字 target = 73
#   - 範圍: 1 到 100
#   - 每次猜中間值 (low + high) // 2
#   - 根據結果調整範圍
#   - 記錄每次猜測和結果
#
# 預期輸出:
#   Round 1: Guess = 50, Too low!  (Range: 1-100)
#   Round 2: Guess = 75, Too high! (Range: 51-100)
#   Round 3: Guess = 62, Too low!  (Range: 51-74)
#   ...
#   Correct! Found 73 in N rounds!
# ----------------------------------------------------------
print("\n--- Exercise 9.3: 二分搜尋猜數字 ---")

target = 73

low = 1
high = 100
rounds = 0
while low <= high:
    rounds += 1
    guess = (low + high) // 2
    if guess == target:
        print(f"Round {rounds}: Guess = {guess}, Correct! (Range: {low}-{high})")
        break
    elif guess < target:
        print(f"Round {rounds}: Guess = {guess}, Too low!  (Range: {low}-{high})")
        low = guess + 1
    else:
        print(f"Round {rounds}: Guess = {guess}, Too high! (Range: {low}-{high})")
        high = guess - 1
print(f"Found {target} in {rounds} rounds!")


# ----------------------------------------------------------
# Exercise 9.4: 文字直方圖 (Text Histogram)
# 給定一段文字,統計每個字母出現的次數
# 並用 * 印出水平直方圖 (忽略空格和標點符號)
#
# 文字: "Hello World Python Programming"
#
# 預期輸出 (部分):
#   d: *
#   e: *
#   g: **
#   h: **
#   i: *
#   l: ***
#   ...
# ----------------------------------------------------------
print("\n--- Exercise 9.4: 文字直方圖 ---")

histogram_text = "Hello World Python Programming"

char_count = {}
for ch in histogram_text.lower():
    if ch.isalpha():
        if ch in char_count:
            char_count[ch] += 1
        else:
            char_count[ch] = 1

sorted_keys = sorted(char_count.keys())
for key in sorted_keys:
    print(f"{key}: {'*' * char_count[key]}")


# ----------------------------------------------------------
# Exercise 9.5: 凱撒密碼 (Caesar Cipher)
# 實作凱撒密碼的加密和解密:
#   - 加密: 每個字母向後移動 shift 個位置
#   - 解密: 每個字母向前移動 shift 個位置
#   - 只處理英文字母,其他字元保持不變
#   - 處理大小寫
#
# 測試:
#   message = "Hello, World! Python 3.14"
#   shift = 3
#   加密後: "Khoor, Zruog! Sbwkrq 3.14"
#   解密後: "Hello, World! Python 3.14"
# ----------------------------------------------------------
print("\n--- Exercise 9.5: 凱撒密碼 ---")

message = "Hello, World! Python 3.14"
shift = 3

# Encrypt
encrypted = ""
for ch in message:
    if ch.isalpha():
        base = ord('A') if ch.isupper() else ord('a')
        encrypted += chr((ord(ch) - base + shift) % 26 + base)
    else:
        encrypted += ch
print(f"Original:  {message}")
print(f"Encrypted: {encrypted}")

# Decrypt
decrypted = ""
for ch in encrypted:
    if ch.isalpha():
        base = ord('A') if ch.isupper() else ord('a')
        decrypted += chr((ord(ch) - base - shift) % 26 + base)
    else:
        decrypted += ch
print(f"Decrypted: {decrypted}")


# ----------------------------------------------------------
# Exercise 9.6: 數列生成器
# 生成以下數列的前 N 項 (N = 10):
#
# a) 費波那契數列 (Fibonacci):
#    0, 1, 1, 2, 3, 5, 8, 13, 21, 34
#
# b) 三角數 (Triangular Numbers):
#    1, 3, 6, 10, 15, 21, 28, 36, 45, 55
#    (第 n 個 = n * (n+1) / 2)
#
# c) 完全平方數 (Perfect Squares):
#    1, 4, 9, 16, 25, 36, 49, 64, 81, 100
#
# d) 質數列 (Prime Numbers):
#    2, 3, 5, 7, 11, 13, 17, 19, 23, 29
# ----------------------------------------------------------
print("\n--- Exercise 9.6: 數列生成器 ---")

N = 10

# a) Fibonacci
fib = [0, 1]
for i in range(2, N):
    fib.append(fib[-1] + fib[-2])
print(f"a) Fibonacci:  {fib}")

# b) Triangular Numbers
tri = []
for i in range(1, N + 1):
    tri.append(i * (i + 1) // 2)
print(f"b) Triangular: {tri}")

# c) Perfect Squares
squares = []
for i in range(1, N + 1):
    squares.append(i ** 2)
print(f"c) Squares:    {squares}")

# d) Prime Numbers
primes = []
num = 2
while len(primes) < N:
    is_prime = True
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            is_prime = False
            break
    if is_prime:
        primes.append(num)
    num += 1
print(f"d) Primes:     {primes}")


# ----------------------------------------------------------
# Exercise 9.7: 簡易排序 (Sorting)
# 不使用 sort() 或 sorted(),實作以下排序演算法:
#
# a) 氣泡排序 (Bubble Sort)
# b) 選擇排序 (Selection Sort)
#
# 測試資料: data = [64, 34, 25, 12, 22, 11, 90]
# 每一輪排序後印出陣列狀態
# ----------------------------------------------------------
print("\n--- Exercise 9.7: 簡易排序 ---")

data = [64, 34, 25, 12, 22, 11, 90]

# a) Bubble Sort
print("=== Bubble Sort ===")
arr = data.copy()
print(f"Original: {arr}")
for i in range(len(arr)):
    for j in range(len(arr) - 1 - i):
        if arr[j] > arr[j + 1]:
            arr[j], arr[j + 1] = arr[j + 1], arr[j]
    print(f"Round {i+1}: {arr}")
print(f"Bubble Sort result: {arr}")

# b) Selection Sort
print("\n=== Selection Sort ===")
arr = data.copy()
print(f"Original: {arr}")
for i in range(len(arr)):
    min_idx = i
    for j in range(i + 1, len(arr)):
        if arr[j] < arr[min_idx]:
            min_idx = j
    arr[i], arr[min_idx] = arr[min_idx], arr[i]
    print(f"Round {i+1}: {arr}")
print(f"Selection Sort result: {arr}")


# ============================================================
# PART 10: 挑戰題 (Challenge Exercises)
# ============================================================

print("\n" + "=" * 60)
print("PART 10: 挑戰題 (Challenge Exercises)")
print("=" * 60)

# ----------------------------------------------------------
# Challenge 10.1: 猜拳遊戲模擬
# 模擬兩個玩家的猜拳遊戲 (不使用 random):
#   player1_moves = ["rock", "paper", "scissors", "rock", "paper"]
#   player2_moves = ["scissors", "rock", "scissors", "paper", "paper"]
#
# 判斷每局的勝負,最終統計:
#   - Player 1 勝場數
#   - Player 2 勝場數
#   - 平局次數
#   - 最終勝者
# ----------------------------------------------------------
print("\n--- Challenge 10.1: 猜拳遊戲模擬 ---")

player1_moves = ["rock", "paper", "scissors", "rock", "paper"]
player2_moves = ["scissors", "rock", "scissors", "paper", "paper"]

p1_wins = 0
p2_wins = 0
draws = 0
for i in range(len(player1_moves)):
    p1 = player1_moves[i]
    p2 = player2_moves[i]
    if p1 == p2:
        result = "Draw"
        draws += 1
    elif (p1 == "rock" and p2 == "scissors") or \
         (p1 == "paper" and p2 == "rock") or \
         (p1 == "scissors" and p2 == "paper"):
        result = "Player 1 wins"
        p1_wins += 1
    else:
        result = "Player 2 wins"
        p2_wins += 1
    print(f"Round {i+1}: {p1} vs {p2} -> {result}")

print(f"\nP1: {p1_wins}, P2: {p2_wins}, Draws: {draws}")
if p1_wins > p2_wins:
    print("Player 1 wins overall!")
elif p2_wins > p1_wins:
    print("Player 2 wins overall!")
else:
    print("It's a tie!")


# ----------------------------------------------------------
# Challenge 10.2: 停車場收費系統
# 停車場收費規則:
#   - 前 1 小時: 免費
#   - 1-3 小時: 每小時 $30
#   - 3-6 小時: 每小時 $50
#   - 6-12 小時: 每小時 $40
#   - 超過 12 小時: 一律 $500 (全日最高)
#   - 不足 1 小時以 1 小時計算
#
# 計算以下停車時間的費用:
#   times = [0.5, 1, 2.5, 3, 4.5, 6, 8, 12, 15, 24]
# ----------------------------------------------------------
print("\n--- Challenge 10.2: 停車場收費系統 ---")

import math

times = [0.5, 1, 2.5, 3, 4.5, 6, 8, 12, 15, 24]

for hours in times:
    if hours <= 1:
        fee = 0
    elif hours <= 3:
        billable = math.ceil(hours) - 1
        fee = billable * 30
    elif hours <= 6:
        fee = 2 * 30
        billable = math.ceil(hours) - 3
        fee += billable * 50
    elif hours <= 12:
        fee = 2 * 30 + 3 * 50
        billable = math.ceil(hours) - 6
        fee += billable * 40
    else:
        fee = 500
    print(f"{hours:5.1f} hours: ${fee}")


# ----------------------------------------------------------
# Challenge 10.3: 數獨驗證器 (Sudoku Validator)
# 驗證一個已填完的 9x9 數獨是否合法:
#   - 每一列 (row) 包含 1-9 不重複
#   - 每一行 (column) 包含 1-9 不重複
#   - 每個 3x3 小方格包含 1-9 不重複
#
# 注意: 只需要驗證,不需要解題
# ----------------------------------------------------------
print("\n--- Challenge 10.3: 數獨驗證器 ---")

valid_sudoku = [
    [5, 3, 4, 6, 7, 8, 9, 1, 2],
    [6, 7, 2, 1, 9, 5, 3, 4, 8],
    [1, 9, 8, 3, 4, 2, 5, 6, 7],
    [8, 5, 9, 7, 6, 1, 4, 2, 3],
    [4, 2, 6, 8, 5, 3, 7, 9, 1],
    [7, 1, 3, 9, 2, 4, 8, 5, 6],
    [9, 6, 1, 5, 3, 7, 2, 8, 4],
    [2, 8, 7, 4, 1, 9, 6, 3, 5],
    [3, 4, 5, 2, 8, 6, 1, 7, 9],
]

invalid_sudoku = [
    [5, 3, 4, 6, 7, 8, 9, 1, 2],
    [6, 7, 2, 1, 9, 5, 3, 4, 8],
    [1, 9, 8, 3, 4, 2, 5, 6, 7],
    [8, 5, 9, 7, 6, 1, 4, 2, 3],
    [4, 2, 6, 8, 5, 3, 7, 9, 1],
    [7, 1, 3, 9, 2, 4, 8, 5, 6],
    [9, 6, 1, 5, 3, 7, 2, 8, 4],
    [2, 8, 7, 4, 1, 9, 6, 3, 5],
    [3, 4, 5, 2, 8, 6, 1, 7, 8],  # 最後一個 9 改成 8 (重複)
]

def validate_sudoku(grid):
    for row in grid:
        if sorted(row) != list(range(1, 10)):
            return False
    for j in range(9):
        col = []
        for i in range(9):
            col.append(grid[i][j])
        if sorted(col) != list(range(1, 10)):
            return False
    for box_r in range(3):
        for box_c in range(3):
            box = []
            for i in range(3):
                for j in range(3):
                    box.append(grid[box_r * 3 + i][box_c * 3 + j])
            if sorted(box) != list(range(1, 10)):
                return False
    return True

print(f"Valid sudoku:   {validate_sudoku(valid_sudoku)}")
print(f"Invalid sudoku: {validate_sudoku(invalid_sudoku)}")


# ----------------------------------------------------------
# Challenge 10.4: 生命遊戲 (Conway's Game of Life) - 簡化版
# 在一個 10x10 的網格上模擬生命遊戲:
#   - 活細胞 (1) 周圍有 2 或 3 個活鄰居 → 存活
#   - 活細胞 周圍少於 2 或多於 3 個活鄰居 → 死亡
#   - 死細胞 (0) 周圍恰好 3 個活鄰居 → 復活
#
# 初始狀態 (Glider):
#   在 (1,2), (2,3), (3,1), (3,2), (3,3) 放置活細胞
#
# 模擬 5 代,每代印出網格狀態
# ----------------------------------------------------------
print("\n--- Challenge 10.4: 生命遊戲 ---")

GRID_SIZE = 10
GENERATIONS = 5

grid = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
# Glider pattern
grid[1][2] = 1
grid[2][3] = 1
grid[3][1] = 1
grid[3][2] = 1
grid[3][3] = 1


def print_grid(g, gen):
    print(f"\nGeneration {gen}:")
    for row in g:
        line = ""
        for cell in row:
            line += "█ " if cell else ". "
        print(line)


def count_neighbors(g, r, c):
    count = 0
    for dr in [-1, 0, 1]:
        for dc in [-1, 0, 1]:
            if dr == 0 and dc == 0:
                continue
            nr, nc = r + dr, c + dc
            if 0 <= nr < GRID_SIZE and 0 <= nc < GRID_SIZE:
                count += g[nr][nc]
    return count


print_grid(grid, 0)

for gen in range(1, GENERATIONS + 1):
    new_grid = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
    for r in range(GRID_SIZE):
        for c in range(GRID_SIZE):
            neighbors = count_neighbors(grid, r, c)
            if grid[r][c] == 1:
                if neighbors in (2, 3):
                    new_grid[r][c] = 1
            else:
                if neighbors == 3:
                    new_grid[r][c] = 1
    grid = new_grid
    print_grid(grid, gen)


print("\n=== All exercises completed! ===")

相關文章