---
# System prepended metadata

title: F04099526_鄭譯賢_能源112_筆記整理
tags: [python上課筆記]

---

# Python 10/17-11/14筆記整理
___
## 10/17運用Python進行科學計算
### 1.本利和
本利是指在投資或貸款中所產生的利息，它是基於原始本金和利率的產物。計算本利的公式如下：

$$
I = P \times r \times t 
$$

其中：
- \( I \) 代表本利（總利息），
- \( P \) 代表原始本金，
- \( r \) 代表利率（以小數形式表示，例如5%轉換為0.05），
- \( t \) 代表時間（以年為單位）。

如果你想要計算總金額（本金加上本利），則公式如下：

$$ A = P + I $$

其中：
- \( A \) 代表總金額。

### 2.四捨五入VS沒有四捨五入的本利和

```python=
# 輸入資訊
P = 1000  # 假設本金為1000元
r = 0.03  # 年利率為3%
n = 365   # 每天複利一次
t = 1     # 1年

# 計算每日利息
daily_interest = P * (r/n)

# 計算本利和
A = P
for _ in range(n*t):
    A += daily_interest
    A = round(A)  # 每天結束後四捨五入到整數位

# 輸出結果
print("一年後的本利和為:", A)

```
:::success
一年後的本利和為: 1000
:::
```python=
import matplotlib.pyplot as plt

# 設定參數
n = 365       # 複利次數（每年365次）
t = 10        # 年數

# 計算每個本金 P 對應的差異
P_values = list(range(1000, 100001, 1000))
differences = []

for P in P_values:
    # 初始化有和無四捨五入的本利計算結果
    A_with_rounding = P
    A_without_rounding = P
    
    # 進行複利計算
    for _ in range(n * t):
        # 有四捨五入的計算
        daily_interest = A_with_rounding * (r/n)
        A_with_rounding += daily_interest
        A_with_rounding = round(A_with_rounding)

        # 無四捨五入的計算
        daily_interest_without_rounding = A_without_rounding * (r/n)
        A_without_rounding += daily_interest_without_rounding

    # 計算有和無四捨五入的差異
    difference = A_with_rounding - A_without_rounding
    differences.append(difference)

# 繪製圖表
plt.figure(figsize=(10, 6))
plt.plot(P_values, differences)
plt.xlabel("Principal")
plt.ylabel("Difference between Rounded and Unrounded Compound Interests")
plt.title("Impact of Principal (P) on Differences")
plt.grid(True)
plt.show()


```
![download](https://hackmd.io/_uploads/SJIJJQ9Ep.png)
:::success
有四捨五入的本利和為: 1000
無四捨五入的本利和為: 1030.45326360051
有四捨五入與無四捨五入的差異為: -30.4532636005099
:::

### 3.人口成長模型
```python=
import numpy as np
import matplotlib.pyplot as plt

# 定義參數
r = 0.1       # 增長率
M = 500       # 環境容量
u0 = 10       # 初始人口大小
num_steps = 100  # 模擬的時間步數

# 初始化數據
u_values = [u0]
time_values = [0]

# 進行數值模擬
for t in range(1, num_steps + 1):
    u_t = u_values[-1]
    
    # 使用 Logistic 模型的差分方程進行數值模擬
    u_next = u_t + r * u_t * (1 - u_t/M)
    
    # 更新數據
    u_values.append(u_next)
    time_values.append(t)

# 繪製人口變化圖
plt.plot(time_values, u_values)
plt.xlabel('時間')
plt.ylabel('人口數')
plt.title('Logistic 模型')
plt.grid(True)
plt.show()

```
![download](https://hackmd.io/_uploads/SyPKLjdVa.png)


```python=

```
## 10/24運用Python進行網路爬蟲
爬蟲的基本步驟：

發送請求： 使用程式代碼發送 HTTP 請求到目標網站的伺服器，獲取網頁內容。

解析 HTML： 使用解析庫（例如 BeautifulSoup 或 lxml）解析獲得的 HTML 內容，找到目標數據的標籤和屬性。

提取數據： 根據解析結果，提取出需要的數據，可以是文字、圖片、連結等。

存儲數據： 將提取的數據存儲在本地文件或數據庫中，以便後續分析或使用。
### 1.抓成大故事觀點下面的內容
```python=
import requests
from bs4 import BeautifulSoup

# 指定目標網頁的URL
url = 'https://www.ncku.edu.tw/'

# 發送HTTP請求，獲取網頁內容
response = requests.get(url)

# 檢查是否成功獲取網頁內容
if response.status_code == 200:
    # 使用Beautiful Soup解析網頁內容
    soup = BeautifulSoup(response.text, 'html.parser')

    # 查找包含 "故事 觀點" 文字的元素。這是第一層，要注意從網頁檢查時，藍色的
    elements_1 = soup.find_all('div', class_='mouter')

    # 打印找到的元素內容
    k = 1
    for element in elements_1:
        print(f"=== 第 {k} 個元素 ===")
        k = k + 1
        
        # 在第一層元素中，查找包含 "d-item v-it col-sm-3" 類別的子元素
        elements_2 = element.find_all('div', class_='d-item v-it col-sm-3')
        
        # 打印第二層元素的文本內容
        for e in elements_2:
            print(e.text.strip())

else:
    print('無法獲取網頁內容')
```
:::success
【92 校慶】2023「永續之島策略設計策略系列論壇」　以永續前瞻為起點　回饋母校共好台灣
【92 校慶】2023 成材產業論壇　關心人類生存大環境　聚焦綠能科技與新經濟
【92 校慶】第三屆成電論壇　重量級校友、系友探討生成式 AI 發展趨勢
建築學系 45 級 黃南淵 : 如果不能看清楚眼前美麗的玫瑰，又如何期待明年春天的來臨｜成大 112 傑出校友
:::
### 2.抓獎學金資料
```python=
import requests
from bs4 import BeautifulSoup

def download_file(url, destination_filename):
    # 發送 HTTP 請求獲取文件
    response = requests.get(url)
    response.raise_for_status()  # 如果是 HTTP 錯誤，則拋出異常
    with open(destination_filename, 'wb') as f:
        f.write(response.content)
    print(f"File saved to {destination_filename}")

# 輸入網址
response = requests.get('https://assistance-osa.ncku.edu.tw/p/403-1051-699.php?Lang=zh-tw')

# 解析成 HTML 語言
soup = BeautifulSoup(response.content, "html.parser")

# 找到對應的 tag，find_all 之後要用一個 for-loop 把找到的一個一個列出來
mtitle = soup.find_all("section", class_="mb")

for m in mtitle:
    # 再往下找對應的 title
    scholarship = m.find_all("div", class_="mtitle")
    for s in scholarship:
        # 找到 a 標籤，取得文字和連結
        u = s.find('a')
        print(f"Title: {u.text.strip()}")
        
        # 找到 i 標籤，取得文字（日期等相關資訊）
        d = s.find('i')
        print(f"Date: {d.text.strip()}")
        
        # 打印連結
        print(f"URL: {u['href']}")
        
        # 透過連結發送 HTTP 請求獲取子網頁內容
        response2 = requests.get(u["href"])
        soup2 = BeautifulSoup(response2.content, "html.parser")
        
        # 找到包含附件的區塊
        attach = soup2.find('ul', class_='mptattach')
        
        # 找到附件的 a 標籤，取得文字和連結
        file = attach.find('a')
        print(f"Attachment: {file.text.strip()}")
        print(f"Attachment URL: {file['href']}")
        
        # 下載文件
        download_file("https://assistance-osa.ncku.edu.tw/"+file["href"], u.text.strip() + ".pdf")

```
:::success
112上漢翔航空工業股份有限公司-獎助碩博士獎學金
2023-11-20
https://assistance-osa.ncku.edu.tw/p/406-1051-260862,r699.php?Lang=zh-tw
a15103-130.doc-.pdf
/app/index.php?Action=downloadfile&file=WVhSMFlXTm9Mekk1TDNCMFlWOHhORGMxTmpOZk5UUTBNRFV6TUY4ME16QXpOeTV3WkdZPQ==&fname=B154RPOKIC44TXMPA404USWT34B4OOHC14B040YSA105DCTSKPZWLOUW14OK50XXYWPOHD0520A0TX24YWSWJGICQOICNORLUTJDA52114NO1111
File saved to 112上漢翔航空工業股份有限公司-獎助碩博士獎學金.pdf
112上財團法人嘉義西區扶輪社文教基金會-獎學金
2023-11-13
https://assistance-osa.ncku.edu.tw/p/406-1051-260547,r699.php?Lang=zh-tw
a3491-407申請表格.odt
/app/index.php?Action=downloadfile&file=WVhSMFlXTm9MelV2Y0hSaFh6RTBOelF4TjE4NU56RTNOVFV3WHpVNU1URTBMbTlrZEE9PQ==&fname=B154RPOKICWWVXMPA4TWJGWTVWB4GGIC14FGHGYSVXQLPO40NKB424B4WS10B4SSYW5400HHDG04EGHC34XSTSA1KL3410GCTXVXA4CC34A401OOOOA4XXWXROPOSSOO
File saved to 112上財團法人嘉義西區扶輪社文教基金會-獎學金.pdf
國立成功大學永豐商業銀行傑出人才獎助學金
2023-11-13
https://assistance-osa.ncku.edu.tw/p/406-1051-260546,r699.php?Lang=zh-tw
:::
這個程式主要爬取了指定網頁中的相關資訊，包括獎學金標題、日期、連結和附件，然後進行文件下載。
## 10/31運用Python進行圖像處理
:::info
用於下載兩張圖片，然後將它們水平合併成一張新的圖片。

1.download_image(url): 這個函數使用 requests 庫向指定的 URL 發送 HTTP 請求，然後使用 PIL 库的 Image.open 方法打開圖片。該函數返回打開的圖片對象。

2.concatenate_images(image1, image2): 這個函數接受兩個圖片對象，計算它們的合併寬度和高度，然後創建一個新的圖片對象（new_image）。接著，它使用 paste 方法將第一張圖片粘貼到新圖片的左側，將第二張圖片粘貼到右側。最終，它返回合併後的圖片對象。

3.指定兩個圖片的 URL，然後使用上述函數將它們合併成一張新的圖片。合併的過程是將第一張圖片的左側和右側分別粘貼上第二張圖片，形成一張寬度是兩張圖片寬度總和，高度是兩張圖片高度的最大值的新圖片。

4.顯示合併後的圖片：使用 matplotlib 的 imshow 方法顯示合併後的圖片，並且設置 plt.axis('off') 以隱藏座標軸。

5.儲存合併後的圖片：使用 save 方法將合併後的圖片保存到本地文件系統中。
:::
### 1.拼接三張圖
```python=
import requests
from PIL import Image
from io import BytesIO
import matplotlib.pyplot as plt

def download_image(url):
    # 發送 HTTP 請求獲取圖片
    response = requests.get(url)
    
    # 使用 PIL 库打開圖片
    image = Image.open(BytesIO(response.content))
    
    return image

def concatenate_images(image1, image2):
    # 計算合併後的圖片寬度和高度
    total_width = image1.width + image2.width
    max_height = max(image1.height, image2.height)

    # 創建一個新的圖片，大小為合併後的寬度和高度
    new_image = Image.new('RGB', (total_width, max_height))
    
    # 將第一張圖片粘貼到新圖片的左側
    new_image.paste(image1, (0, 0))
    
    # 將第二張圖片粘貼到新圖片的右側
    new_image.paste(image2, (image1.width, 0))

    return new_image

# 替換成你的圖片網址
image_url1 = download_image("https://web.ncku.edu.tw/var/file/0/1000/img/DSC01181ok.jpg")
image_url2 = download_image("https://web.ncku.edu.tw/var/file/0/1000/img/418380686.jpg")

# 連接三張圖片
result_image = concatenate_images(image_url1, image_url2)
result_image = concatenate_images(result_image, image_url1)

# 顯示合併後的圖片
plt.imshow(result_image)
plt.axis('off')  # 不顯示座標軸
plt.show()

# 儲存合併後的圖片
result_image.save("concatenated_image.jpg")
```
![download](https://hackmd.io/_uploads/HyQi83OV6.png)
### 2.拼接圖片及文字
```python=
import requests
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import matplotlib.pyplot as plt

def download_image(url):
    # 發送 HTTP 請求獲取圖片
    response = requests.get(url)
    
    # 使用 PIL 库打開圖片
    image = Image.open(BytesIO(response.content))
    
    return image

def draw_multiline_text(draw, text, position, font, max_width):
    lines = text.split('\n')
    y = position[1]
    for line in lines:
        # 使用 textbbox 獲取文字的尺寸
        text_bbox = draw.textbbox((0, 0), line, font=font)
        text_width = text_bbox[2] - text_bbox[0]
        text_height = text_bbox[3] - text_bbox[1]

        # 計算文字位置
        x = (max_width - text_width) / 2 + position[0]
        draw.text((x, y), line, font=font, fill="white")
        y += text_height

def create_image_with_text(image_url, text):
    # 下載並獲取左邊的圖片
    left_image = download_image(image_url)

    # 創建一個相同大小的黑色背景圖片
    right_image = Image.new('RGB', left_image.size, color='black')

    # 在黑色背景圖片上添加文字
    draw = ImageDraw.Draw(right_image)
    font_size = int(min(right_image.size) / 10)  # 根據圖片大小調整字體大小
    font = ImageFont.truetype("ThePeakFontBeta_V0_101.ttf", font_size)  # 使用下載的字體

    # 計算文字位置
    max_width = right_image.width * 0.8
    x = (right_image.width - max_width) / 2
    y = (right_image.height - draw.textbbox((0, 0), text, font=font)[3]) / 2
    draw_multiline_text(draw, text, (x, y), font, max_width)

    # 將左邊和右邊的圖片拼接
    total_width = left_image.width + right_image.width
    new_image = Image.new('RGB', (total_width, left_image.height))
    new_image.paste(left_image, (0, 0))
    new_image.paste(right_image, (left_image.width, 0))

    return new_image

# 替換成你的圖片網址
image_url = "https://web.ncku.edu.tw/var/file/0/1000/img/DSC01181ok.jpg"
# 輸入你想在右邊圖片中顯示的多行文字
text = "成大職治系實在好棒棒！\n成大職治系實在好棒棒！\n成大職治系實在好棒棒！"

result_image = create_image_with_text(image_url, text)

# 顯示合併後的圖片
plt.imshow(result_image)
plt.axis('off')  # 不顯示座標軸
plt.show()

# 儲存合併後的圖片
result_image.save("image_with_multiline_text.jpg")

```
![download](https://hackmd.io/_uploads/SkFbwnuNT.png)
### 3.拼接一張灰色調圖片
```python=
# 首先創建一個 ImageEnhance.Color 對象，然後使用 enhance 方法來調整圖片的顏色饱和度。增强後的圖片與原始圖片使用先前定義的 concatenate_images 函式進行左右合併，最後使用 matplotlib.pyplot 顯示合併後的圖片
# 创建一个颜色增强器对象
color_enhancer = ImageEnhance.Color(image)
# 调整颜色饱和度（1.0 表示原始饱和度，小于 1.0 减弱饱和度，大于 1.0 增强饱和度）
enhanced_image = color_enhancer.enhance(0.1)  # 增强颜色饱和度

# 將原始圖片和增強後的圖片進行左右合併
combined_image = concatenate_images(image, enhanced_image)

# 顯示合併後的圖片
plt.imshow(combined_image)
plt.axis('off')  # 不顯示座標軸
plt.show()
```
![download](https://hackmd.io/_uploads/rynZt3OE6.png)

### 4.拼接一張模糊圖片
```python=
# 首先導入 ImageFilter 模組，然後使用 GaussianBlur 濾鏡對原始圖片進行模糊處理。接著，將原始圖片和模糊處理後的圖片使用先前定義的 concatenate_images 函式進行左右合併，最後使用 matplotlib.pyplot 顯示合併後的圖片
# 使用模糊滤镜进行模糊处理
blurred_image = image.filter(ImageFilter.GaussianBlur(radius=100))

# 將原始圖片和模糊處理後的圖片進行左右合併
combined_image = concatenate_images(image, blurred_image)

# 顯示合併後的圖片
plt.imshow(combined_image)
plt.axis('off')  # 不顯示座標軸
plt.show()
```
![download](https://hackmd.io/_uploads/ryDdF2_VT.png)

### 5.拼接一張負片
```python=
# 創建一個與原始圖片大小相同的空白圖片，然後遍歷原始圖片的每個像素，將RGB值取反後放入新的圖片中。最後，將原始圖片和取反處理後的圖片進行左右合併
# 获取图片的宽度和高度
width, height = image.size

# 创建一个新的空白图片，与原始图片大小相同
negative_image = Image.new("RGB", (width, height))

# 遍历每个像素并取反RGB值
for x in range(width):
    for y in range(height):
        pixel = image.getpixel((x, y))  # 得到像素的值 tuple (R,G,B)
        inverted_pixel = tuple(255 - value for value in pixel)
        # 使用 for 循环生成 tuple 中的每个值，取反 RGB 值
        negative_image.putpixel((x, y), inverted_pixel)  # 把像素的(RGB)放回圖片中

# 將原始圖片和取反處理後的圖片進行左右合併
combined_image = concatenate_images(image, negative_image)

# 顯示合併後的圖片
plt.imshow(combined_image)
plt.axis('off')  # 不顯示座標軸
plt.show()

```
![download](https://hackmd.io/_uploads/ByCOY2ON6.png)

## 11/7運用Python進行遊戲設計
### 1.井字遊戲
```python=
def 印出井字盤(井字盤):
    """
    印出井字遊戲的遊戲盤。

    Parameters:
    - 井字盤 (list): 存放井字遊戲狀態的列表
    """
    print(井字盤[0] + '|' + 井字盤[1] + '|' + 井字盤[2])
    print('-+-+-')
    print(井字盤[3] + '|' + 井字盤[4] + '|' + 井字盤[5])
    print('-+-+-')
    print(井字盤[6] + '|' + 井字盤[7] + '|' + 井字盤[8])

def 檢查贏家(井字盤, 符號):
    """
    檢查是否有玩家贏得遊戲。

    Parameters:
    - 井字盤 (list): 存放井字遊戲狀態的列表
    - 符號 (str): 玩家的符號，'X' 或 'O'

    Returns:
    - bool: 若玩家贏得遊戲則返回 True，否則返回 False
    """
    贏的組合 = [
        [0, 1, 2], [3, 4, 5], [6, 7, 8],  # 水平
        [0, 3, 6], [1, 4, 7], [2, 5, 8],  # 垂直
        [0, 4, 8], [2, 4, 6]  # 對角線
    ]
    for 組合 in 贏的組合:
        if 井字盤[組合[0]] == 井字盤[組合[1]] == 井字盤[組合[2]] == 符號:
            return True
    return False

def 主程式():
    """
    井字遊戲的主程式。
    """
    井字盤 = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
    玩家 = 'X'
    輸贏平局 = None

    while True:
        印出井字盤(井字盤)
        輸入位置 = input(f'請玩家 {玩家} 輸入位置（1-9）：')

        if 輸入位置.isdigit() and 1 <= int(輸入位置) <= 9:
            輸入位置 = int(輸入位置) - 1
            if 井字盤[輸入位置] == 'X' or 井字盤[輸入位置] == 'O':
                print('該位置已被佔據，請重新輸入。')
            else:
                井字盤[輸入位置] = 玩家
                if 檢查贏家(井字盤, 玩家):
                    印出井字盤(井字盤)
                    print(f'恭喜玩家 {玩家} 獲勝！')
                    輸贏平局 = '贏'
                    break
                elif all(位置 == 'X' or 位置 == 'O' for 位置 in 井字盤):
                    印出井字盤(井字盤)
                    print('平局！')
                    輸贏平局 = '平局'
                    break
                玩家 = 'O' if 玩家 == 'X' else 'X'
        else:
            print('輸入無效，請輸入1到9之間的數字。')

    if 輸贏平局 is None:
        print('遊戲結束。')

if __name__ == '__main__':
    主程式()

```
:::success
1|2|3
-+-+-
4|5|6
-+-+-
7|8|9
請玩家 X 輸入位置（1-9）：5
1|2|3
-+-+-
4|X|6
-+-+-
7|8|9
請玩家 O 輸入位置（1-9）：1
O|2|3
-+-+-
4|X|6
-+-+-
7|8|9
請玩家 X 輸入位置（1-9）：4
O|2|3
-+-+-
X|X|6
-+-+-
7|8|9
請玩家 O 輸入位置（1-9）：8
O|2|3
-+-+-
X|X|6
-+-+-
7|O|9
請玩家 X 輸入位置（1-9）：6
O|2|3
-+-+-
X|X|X
-+-+-
7|O|9
恭喜玩家 X 獲勝！
:::

### 2.踩地雷
創建地雷地圖(行數, 列數, 地雷數): 生成一個地雷地圖，並在地雷位置標記為 'Ｘ'。
顯示遊戲地圖(遊戲地圖): 顯示遊戲地圖，玩家踩開的區域用 '□' 顯示。
檢查合法性(行, 列, 行數, 列數): 檢查座標是否合法。
計算周圍地雷數(地雷地圖, 行, 列): 計算指定位置周圍的地雷數。
檢查地雷(地雷地圖, 行, 列): 檢查指定位置是否有地雷。
顯示地雷地圖(地雷地圖): 顯示地雷地圖，用於在遊戲結束後顯示所有地雷位置。
整體主程式流程如下：

使用者輸入遊戲參數：行數、列數、地雷數。
生成地雷地圖並初始化遊戲地圖。
進入遊戲主迴圈：
使用者輸入檢查的位置。
檢查該位置是否合法。
若合法，檢查是否踩到地雷：
若踩到地雷，遊戲結束，顯示所有地雷位置。
若未踩到地雷，顯示周圍地雷數，繼續遊戲。
若不合法，提示重新輸入。
```python=
# 創造一個踩地雷遊戲呢?
#  創建地雷地圖
#  顯示遊戲地圖
#  檢查合法性
#  計算周圍地雷數
#  檢查地雷
#  顯示地雷地圖

import random

中文數字 = ['０', '１', '２', '３', '４', '５', '６', '７', '８', '９']

def 創建地雷地圖(行數, 列數, 地雷數):
    地雷地圖 = [['Ｏ' for _ in range(列數)] for _ in range(行數)]
    隨機地雷位置 = random.sample(range(行數 * 列數), 地雷數)

    for 位置 in 隨機地雷位置:
        行 = 位置 // 列數
        列 = 位置 % 列數
        地雷地圖[行][列] = 'Ｘ'

    return 地雷地圖

def 顯示遊戲地圖(遊戲地圖):
    for 行 in 遊戲地圖:
        print(' '.join(行))

def 檢查合法性(行, 列, 行數, 列數):
    return 0 <= 行 < 行數 and 0 <= 列 < 列數

def 計算周圍地雷數(地雷地圖, 行, 列):
    周圍地雷數 = 0
    鄰居方向 = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]

    for dx, dy in 鄰居方向:
        新行, 新列 = 行 + dx, 列 + dy
        if 檢查合法性(新行, 新列, len(地雷地圖), len(地雷地圖[0])) and 地雷地圖[新行][新列] == 'Ｘ':
            周圍地雷數 += 1

    return 周圍地雷數

def 檢查地雷(地雷地圖, 行, 列):
    if 地雷地圖[行][列] == 'Ｘ':
        return True
    return False

def 顯示地雷地圖(地雷地圖):
    for 行 in 地雷地圖:
        print(' '.join(行))


def 主程式():
    print('歡迎來到踩地雷遊戲！')
    行數 = int(input('請輸入行數：'))
    列數 = int(input('請輸入列數：'))
    地雷數 = int(input('請輸入地雷數：'))

    地雷地圖 = 創建地雷地圖(行數, 列數, 地雷數)
    遊戲地圖 = [['□' for _ in range(列數)] for _ in range(行數)]

    顯示遊戲地圖(遊戲地圖)

    while True:
        #try:
        #    行 = int(input('請輸入行數(1-{0}): '.format(行數))) - 1
        #    列 = int(input('請輸入列數(1-{0}): '.format(列數))) - 1
        #except ValueError:
        #    print('請輸入有效的數字。')
        #    continue
        位置 = input('請輸入要檢查的位置 (例如: 1,3)：')
        try:
            行, 列 = map(int, 位置.split(','))
            行 -= 1
            列 -= 1
        except ValueError:
            print('請輸入有效的位置 (例如: 1,3)。')
            continue
        if not 檢查合法性(行, 列, 行數, 列數) or 遊戲地圖[行][列] != '□':
            print('請輸入有效的行數和列數。')
            continue

        if 檢查地雷(地雷地圖, 行, 列):
            顯示地雷地圖(地雷地圖)
            print('踩到地雷，遊戲結束！')
            break
        else:
            周圍地雷數 = 計算周圍地雷數(地雷地圖, 行, 列)
            遊戲地圖[行][列] = 中文數字[周圍地雷數]
            顯示遊戲地圖(遊戲地圖)

if __name__ == "__main__":
    主程式()

```
:::success
歡迎來到踩地雷遊戲！
請輸入行數：10
請輸入列數：10
請輸入地雷數：90
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
請輸入要檢查的位置 (例如: 1,3)：3,1
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｏ Ｘ
Ｏ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｏ Ｘ
Ｘ Ｏ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ
Ｘ Ｘ Ｏ Ｘ Ｘ Ｘ Ｘ Ｘ Ｏ Ｘ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｏ Ｘ Ｏ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｏ Ｘ Ｘ Ｏ
Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ Ｘ
踩到地雷，遊戲結束！
:::

### 3.猜數字幾A幾B
```python=
import random

def 生成祕密數字():
    # 生成一個四位不重複的數字作為祕密數字
    數字列表 = [str(i) for i in range(10)]
    random.shuffle(數字列表)
    return ''.join(數字列表[:4])

def 獲取猜測():
    while True:
        # 輸入玩家的猜測，確保輸入的是四位不重複的數字
        猜測 = input("請猜一個四位數字（數字不重複）：")
        if len(猜測) == 4 and 猜測.isdigit() and len(set(猜測)) == 4:
            return 猜測
        print("無效的輸入！")

def 獲取提示(猜測, 祕密數字):
    # 檢查猜測和祕密數字的相符情況，並返回提示字串
    A的數量 = sum(1 for a, b in zip(猜測, 祕密數字) if a == b)
    B的數量 = sum(1 for g in 猜測 if g in 祕密數字) - A的數量
    return f"{A的數量}A{B的數量}B"

def 遊戲開始():
    # 初始化遊戲，生成祕密數字
    祕密數字 = 生成祕密數字()
    嘗試次數 = 0

    while True:
        # 玩家進行猜測
        猜測 = 獲取猜測()
        嘗試次數 += 1
        if 猜測 == 祕密數字:
            # 猜對時結束遊戲，顯示結果
            print(f"恭喜你猜對了！答案就是 {祕密數字}。你總共猜了 {嘗試次數} 次。")
            break
        提示 = 獲取提示(猜測, 祕密數字)
        print(f"提示：{提示}")

if __name__ == "__main__":
    # 啟動遊戲
    遊戲開始()

```
:::success
提示：0A1B
提示：1A1B
提示：1A1B
提示：1A1B
:::
## 11/14運用Python進行機器學習
```pyhton=
# 生成兩個圓形的數據點，並以散點圖的形式呈現。其中，generate_circle_points 函數用於生成在指定半徑範圍內均勻分布的圓形點。程式碼使用Matplotlib進行繪圖，其中兩個圓形的數據點分別以藍色和橙色的散點表示，並且加入了相應的標籤和標題。
import matplotlib.pyplot as plt
import numpy as np

# 定義生成圓形點的函數
def generate_circle_points(r_min, r_max, num_points):
    angles = np.random.uniform(0, 2 * np.pi, num_points)
    radii = np.sqrt(np.random.uniform(r_min**2, r_max**2, num_points))
    x = radii * np.cos(angles)
    y = radii * np.sin(angles)
    return x, y

# 定義圓形的半徑範圍和數據點數量
R0 = 0
R1 = 2
R2 = 1
R3 = 3
N = 200  # 原始點的數量

# 生成兩個圓形的數據點
x_o, y_o = generate_circle_points(R0, R1, N)
x_x, y_x = generate_circle_points(R2, R3, N)

# 繪製散點圖
plt.figure(figsize=(8, 8))
plt.scatter(x_o, y_o, c='blue', marker='o', label='Positive O')
plt.scatter(x_x, y_x, c='orange', marker='o', label='Negative O')

plt.xlabel('X')
plt.ylabel('Y')
plt.title('Scatter Plot with Different Classes')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()

```
![download](https://hackmd.io/_uploads/HJaUVYF4a.png)
```python=
import matplotlib.pyplot as plt
import numpy as np

def plot_predictions(X_train, y_train, X_test, y_test, model):
    # 使用模型對訓練集進行預測
    y_pred_train_continuous = model.predict(X_train)
    y_pred_train = np.where(y_pred_train_continuous.flatten() >= 0, 1, -1)

    # 使用模型對測試集進行預測
    y_pred_test_continuous = model.predict(X_test)
    y_pred_test = np.where(y_pred_test_continuous.flatten() >= 0, 1, -1)
    plt.figure(figsize=(8, 8))

    # 訓練集 - 預測正確
    correct_train = (y_train == y_pred_train)
    oc = (y_train == 1) & correct_train
    xc = (y_train == -1) & correct_train
    plt.scatter(X_train[oc, 0], X_train[oc, 1], c='blue', marker='o', label='Train Correct (Positive)')
    plt.scatter(X_train[xc, 0], X_train[xc, 1], c='orange', marker='o', label='Train Correct (Negative)')

    # 訓練集 - 預測錯誤
    incorrect_train = (y_train != y_pred_train)
    oi = (y_train == 1) & incorrect_train
    xi = (y_train == -1) & incorrect_train
    plt.scatter(X_train[oi, 0], X_train[oi, 1], c='blue', marker='x', label='Train Incorrect (Positive)')
    plt.scatter(X_train[xi, 0], X_train[xi, 1], c='orange', marker='x', label='Train Incorrect (Negative)')

    # 測試集 - 預測正確
    correct_test = (y_test == y_pred_test)
    oc = (y_test == 1) & correct_test
    xc = (y_test == -1) & correct_test
    plt.scatter(X_test[oc, 0], X_test[oc, 1], c='cyan', marker='o', label='Test Correct (Positive)')
    plt.scatter(X_test[xc, 0], X_test[xc, 1], c='pink', marker='o', label='Test Correct (Negative)')

    # 測試集 - 預測錯誤
    incorrect_test = (y_test != y_pred_test)
    oi = (y_test == 1) & incorrect_test
    xi = (y_test == -1) & incorrect_test
    plt.scatter(X_test[oi, 0], X_test[oi, 1], c='cyan', marker='x', label='Test Incorrect (Positive)')
    plt.scatter(X_test[xi, 0], X_test[xi, 1], c='pink', marker='x', label='Test Incorrect (Negative)')

    plt.xlabel('X Coordinate')
    plt.ylabel('Y Coordinate')
    plt.title('Model Predictions')
    plt.legend()
    plt.grid(True)
    plt.show()

```
```python=
# 整合並標記數據點
X = np.vstack((np.column_stack((x_o, y_o)), np.column_stack((x_x, y_x))))
y = np.array([1] * N + [-1] * N)  # 1代表o，-1代表x

# 分割數據集, 把 N 中的 20% 做為測試
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 創建神經網路模型
N1 = 3
model = Sequential()
model.add(Dense(N1, input_dim=2, activation='tanh'))  # 第一層有N1個神經元，使用tanh激活函數
model.add(Dense(2, input_dim=2, activation='tanh'))  # 第二層有2個神經元
model.add(Dense(1, activation='tanh'))  # 第三層有1個神經元

# 編譯模型
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])

```
```python=

# 訓練模型並記錄訓練過程
history = model.fit(X_train, y_train, epochs=1000, batch_size=5, verbose=0, validation_data=(X_test, y_test))

# 獲取損失函數值
loss_values = history.history['loss']

# 繪製損失函數圖
plt.figure(figsize=(8, 4))
plt.plot(loss_values, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Function During Training')
plt.legend()
plt.grid(True)
plt.show()

# 获取训练和验证集准确度
# train_acc = history.history['accuracy']
# val_acc = history.history['val_accuracy']

# 绘制准确度图
#plt.figure(figsize=(8, 4))
#plt.plot(train_acc, label='Training Accuracy')
#plt.plot(val_acc, label='Validation Accuracy')
#plt.xlabel('Epoch')
#plt.ylabel('Accuracy')
#plt.title('Model Accuracy during Training')
#plt.legend()
#plt.grid(True)
#plt.show()


plot_predictions(X_train, y_train, X_test, y_test, model)


# 獲取第一層的權重和偏置
weights, biases = model.layers[0].get_weights()

# 生成更多隨機點進行預測
x_a, y_a = generate_circle_points(R0, R3, Np)
additional_X = np.column_stack((x_a, y_a))
y_pred_additional = model.predict(additional_X)
y_pred_additional = np.where(y_pred_additional.flatten() >= 0, 1, -1)

# 繪製測試數據和預測結果
plt.figure(figsize=(8, 8))
plt.scatter(x_o, y_o, c='blue', marker='o', label='Class Positive')
plt.scatter(x_x, y_x, c='orange', marker='o', label='Class Negative')
plt.scatter(additional_X[y_pred_additional == 1, 0], additional_X[y_pred_additional == 1, 1], c='blue', marker='o', label='Predicted Positive')
plt.scatter(additional_X[y_pred_additional == -1, 0], additional_X[y_pred_additional == -1, 1], c='orange', marker='o', label='Predicted Negative')

# 繪製第一層的N1條直線
x_values = np.linspace(-2, 2, 100)
y_values = np.linspace(-2, 2, 100)
for i in range(N1):
    a, b = weights[:, i]
    c = biases[i]
    if abs(a) > abs(b):
        x_line = (-b * y_values - c) / a
        plt.plot(x_line, y_values, linestyle='--', label=f'Neuron {i+1} Boundary')
    else:
        y_line = (-a * x_values - c) / b
        plt.plot(x_values, y_line, linestyle='--', label=f'Neuron {i+1} Boundary')

plt.xlabel('X')
plt.ylabel('Y')
plt.title('Additional Points Classification with Neuron Boundaries')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()

```
![download](https://hackmd.io/_uploads/SyV7BYKNa.png)
![download](https://hackmd.io/_uploads/HyF7rYtVT.png)

:::info
在二元分類（Binary Classification）的混淆矩陣（Confusion Matrix）中，常見的術語包括：

1. **True Positive (TP):** 正樣本被正確地分類為正類。在這裡，指的是模型正確地預測為正類的實例數。

2. **True Negative (TN):** 負樣本被正確地分類為負類。在這裡，指的是模型正確地預測為負類的實例數。

3. **False Positive (FP):** 負樣本被錯誤地分類為正類。在這裡，指的是模型錯誤地將實際為負類的樣本預測為正類的實例數。

4. **False Negative (FN):** 正樣本被錯誤地分類為負類。在這裡，指的是模型錯誤地將實際為正類的樣本預測為負類的實例數。

這些術語的組合形成了混淆矩陣：

\[
\begin{array}{cc|c}
 & & \text{實際} \\
 & & \text{正類} & \text{負類} \\
\hline
\text{預測} & \text{正類} & TP & FP \\
 & \text{負類} & FN & TN \\
\end{array}
\]

進一步的評估指標：

當進行二元分類（Binary Classification）時，混淆矩陣（Confusion Matrix）是一個用來評估模型性能的重要工具，其中包含了以下術語：

1. **True Positive (TP):** 正樣本被正確地分類為正類。指的是模型正確地預測為正類的實例數。

2. **True Negative (TN):** 負樣本被正確地分類為負類。指的是模型正確地預測為負類的實例數。

3. **False Positive (FP):** 負樣本被錯誤地分類為正類。指的是模型錯誤地將實際為負類的樣本預測為正類的實例數。

4. **False Negative (FN):** 正樣本被錯誤地分類為負類。指的是模型錯誤地將實際為正類的樣本預測為負類的實例數。

混淆矩陣的形式如下：

\[ \begin{array}{ccc}
 & \text{實際正類} & \text{實際負類} \\
\hline
\text{預測正類} & TP & FP \\
\text{預測負類} & FN & TN \\
\end{array} \]

這裡還有一些常見的評估指標：

- **Accuracy (ACC):** 分類器正確預測的比例，計算方式為 $( \frac{{TP + TN}}{{TP + TN + FP + FN}} )$.

- **True Positive Rate (TPR), Sensitivity, Recall:** 正類實例中被分類為正類的比例，計算方式為 $( \frac{{TP}}{{TP + FN}} )$.

- **True Negative Rate (TNR), Specificity:** 負類實例中被分類為負類的比例，計算方式為 $( \frac{{TN}}{{TN + FP}} \)$.

- **False Positive Rate (FPR):** 負類實例中被誤分正類的比例，計算方式為$( 1 - \text{TNR} \) 或 \( \frac{{FP}}{{TN + FP}} )$.

- **False Negative Rate (FNR):** 正類實例中被誤分為負類的比例，計算方式為 $( 1 - \text{TPR} \) 或 \( \frac{{FN}}{{TP + FN}} )$.

- **Precision (Positive Predictive Value, PPV):** 被分類為正類的實例中真正為正類的比例，計算方式為 $( \frac{{TP}}{{TP + FP}} )$.

- **Negative Predictive Value (NPV):** 被分類為負類的實例中真正為負類的比例，計算方式為 $( \frac{{TN}}{{TN + FN}} )$.

- **F1 Score:** 精確度和召回率的調和平均值，計算方式為 $( \frac{{2 \cdot \text{PPV} \cdot \text{TPR}}}{{\text{PPV} + \text{TPR}}} )$.
:::
```python=
#loss, accuracy = model.evaluate(X_train, y_train)
#print('train loss: ', loss)
#print('train accuracy: ', accuracy)

y_pred_train_continuous = model.predict(X_train)
y_pred_train = np.where(y_pred_train_continuous.flatten() >= 0, 1, -1)

TP = sum((y_pred_train==1) & (y_train == 1))
TN = sum((y_pred_train==-1) & (y_train == -1))
FP = sum((y_pred_train==1) & (y_train == -1))
FN = sum((y_pred_train==-1) & (y_train == 1))
print("In training set:")
TPR = TP/(TP+FN)
TNR = TN/(TN+FP)
FPR = 1-TNR
FNR = 1-TPR
PPV = TP/(TP+FP)
NPV = TN/(TN+FN)
F1 = 2*PPV*TPR/(PPV+TPR)
ACC = (TP+TN)/(TP+TN+FP+FN)
print("TP=",TP,"TN=",TN,"FP=",FP,"FN=",FN)
print("Accuracy=",ACC)
print("TPR(Sensitivity, Recall)=",TPR,"TNR(Specificity)=",TNR)


#loss, accuracy = model.evaluate(X_test, y_test)
#print('test loss: ', loss)
#print('test accuracy: ', accuracy)

#y_pred_test_continuous = model.predict(X_test)
#y_pred_test = np.where(y_pred_test_continuous.flatten() >= 0, 1, -1)
```
:::success
10/10 [==============================] - 0s 2ms/step
In training set:
TP= 156 TN= 134 FP= 30 FN= 0
Accuracy= 0.90625
TPR(Sensitivity, Recall)= 1.0 TNR(Specificity)= 0.8170731707317073
:::