作者:Ted Lee
日前報名台文博覽會的台語開講會的十鐘分享,心理就一直構思著要如何結合個人近期的台語與 GenAI 的研究(圖 1)來介紹自己最近兩年的研究成果。

圖 1:筆者近期援用 GenAI 結合台語的研究著述
於是,我們整理出下列五道題目和答案,想用「連連看」的作答方式來增加和線上觀眾的互動交流:
題目:
台語有一个真有名的阿姨叫做?
台語的老爸叫做?
佗一个是「火」的泉腔讀音?
佗一个是「雞」的泉腔讀音?
佗一个是「豬」的泉腔讀音?
答案:
文音(文英阿姨)
語言(語言是文化的 daddy(底蒂))
hér/hé(央元音 er)
kere/kue(複央元音 ere)
tir/ti(央元音 ir)
萬事齊備,開展咒語:
(人設)你是台文和 Python 大師
(任務)以下是五題試題的資料,產生連連看的 Python 試窗程式碼題號 題目 答案 解釋
1 台語有一个真有名的阿姨叫做? 文音 文英阿姨
2 台語的老爸叫做? 語言 語言是文化的 daddy(底蒂)
3 佗一个是「火」的泉腔讀音? hér/hé 央元音er
4 佗一个是「雞」的泉腔讀音? kere/kue 複央元音ere
5 佗一个是「豬」的泉腔讀音? tir/ti 央元音ir
於是乎,我們走向了第一站的魔法 Python 旅程~。
魔法第一站:Python Stop
經過我們拜請GPT 大神加持後,Python Tkinter 視窗程式碼的執行結果如圖 2 所示:

圖 2:Pyhon 視窗版的連連看
(註 1:我們指揮 GPT 生成的是桌面應用程式版的 Python 程式(使用 Tkinter 視窗套件)。想要在像 Colab 的網頁版 Python 編輯器上開發網頁視窗的讀者們,可以再委派 GPT 代勞。)
完整的 Python 程式碼如下:
連連看.py
import tkinter as tk
import random
# 修正後的試題資料
questions = [
{"題號": 1, "題目": "台語有一个真有名的阿姨叫做?", "答案": "文音", "解釋": "文英阿姨"},
{"題號": 2, "題目": "台語的老爸叫做?", "答案": "語言", "解釋": "語言是文化的 daddy(底蒂)"},
{"題號": 3, "題目": "佗二个是「火」的泉腔讀音?", "答案": "hér/hé", "解釋": "央元音 er"},
{"題號": 4, "題目": "佗二个是「雞」的泉腔讀音?", "答案": "kere/kue", "解釋": "複央元音 ere"},
{"題號": 5, "題目": "佗二个是「豬」的泉腔讀音?", "答案": "tir/ti", "解釋": "央元音 ir"},
]
# 隨機打亂
question_texts = [q["題目"] for q in questions]
answer_texts = [q["答案"] for q in questions]
random.shuffle(question_texts)
random.shuffle(answer_texts)
class MatchingGame:
def __init__(self, root):
self.root = root
self.root.title("台文連連看練習")
self.selected_question = None
self.selected_answer = None
self.left_frame = tk.Frame(root)
self.right_frame = tk.Frame(root)
self.bottom_frame = tk.Frame(root)
self.left_frame.pack(side=tk.LEFT, padx=10, pady=10)
self.right_frame.pack(side=tk.LEFT, padx=10, pady=10)
self.bottom_frame.pack(side=tk.BOTTOM, pady=10)
self.question_labels = []
self.answer_labels = []
for q_text in question_texts:
label = tk.Label(self.left_frame, text=q_text, width=40, bg="white", relief="groove", anchor="w")
label.bind("", lambda e, text=q_text: self.select_question(text, e.widget))
label.pack(pady=5)
self.question_labels.append(label)
for a_text in answer_texts:
label = tk.Label(self.right_frame, text=a_text, width=20, bg="white", relief="groove", anchor="w")
label.bind("", lambda e, text=a_text: self.select_answer(text, e.widget))
label.pack(pady=5)
self.answer_labels.append(label)
self.result_label = tk.Label(self.bottom_frame, text="請點選題目與答案配對", fg="blue")
self.result_label.pack()
def select_question(self, text, widget):
self.selected_question = text
self.highlight(widget, self.question_labels)
def select_answer(self, text, widget):
self.selected_answer = text
self.highlight(widget, self.answer_labels)
if self.selected_question and self.selected_answer:
self.check_answer()
def highlight(self, widget, group):
for w in group:
w.config(bg="white")
widget.config(bg="lightblue")
def check_answer(self):
for q in questions:
if q["題目"] == self.selected_question and q["答案"] == self.selected_answer:
self.result_label.config(text=f"✅ 正確:{q['解釋']}", fg="green")
break
else:
self.result_label.config(text="❌ 錯誤,請再試一次", fg="red")
# 重置選擇
self.selected_question = None
self.selected_answer = None
for w in self.question_labels + self.answer_labels:
w.config(bg="white")
# 啟動視窗
if __name__ == "__main__":
root = tk.Tk()
app = MatchingGame(root)
root.mainloop()
註 2:在沒有特別指定程式碼的樣式風格(design pattern)下,經以上實測 GPT 會自動生成物件導向版的程式碼。程式碼解析的方法請自行參考上一節筆者所列出的先前著作。
魔法第二站:網頁 Stop
我使用 Websim.ai 來改寫上一小節生妥的「連連看.py」。請讀者下達以下咒語:
根據以下 Python 程式碼的功能,產生 HTML+CSS+JS
(複製上一小節的 連連看.py)
經過反覆的修整後,完成的網頁版連連看的執行畫面如圖 3 所示:

圖 3:網頁版的連連看
圖 3 所對應的 index.html、style.css、script.js 原始碼詳列如下:
index.html
style.css
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
/* @tweakable Main title font size */
h1 {
font-size: 2em;
margin-bottom: 5px;
}
/* @tweakable Author font size */
p {
font-size: 1.1em;
margin-bottom: 20px;
}
.container {
display: flex;
justify-content: center;
align-items: flex-start;
margin-bottom: 20px;
}
.left-column, .right-column {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
margin: 0 10px;
}
.left-column h2, .right-column h2 {
margin-bottom: 10px;
color: #333;
}
.item {
padding: 10px 15px;
margin: 5px 0;
background-color: #eee;
border-radius: 5px;
cursor: pointer;
width: 250px;
text-align: center;
user-select: none;
}
.item.selected {
background-color: lightblue;
}
.result-area {
font-size: 1.2em;
padding: 10px 20px;
border-radius: 5px;
margin-top: 20px;
}
.result-area.correct {
color: green;
background-color: #d4edda;
border: 1px solid #c3e6cb;
}
.result-area.incorrect {
color: red;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
}
script.js
onst questionsData = [
{"題號": 1, "題目": "台語有一个真有名的阿姨叫做?", "答案": "文音", "解釋": "文英阿姨"},
{"題號": 2, "題目": "台語的老爸叫做?", "答案": "語言", "解釋": "語言是文化的 daddy(底蒂)"},
{"題號": 3, "題目": "佗二个是「火」的泉腔讀音?", "答案": "hér/hé", "解釋": "央元音 er"},
{"題號": 4, "題目": "佗二个是「雞」的泉腔讀音?", "答案": "kere/kue", "解釋": "複央元音 ere"},
{"題號": 5, "題目": "佗二个是「豬」的泉腔讀音?", "答案": "tir/ti", "解釋": "央元音 ir"},
];
/* @tweakable the background color for correct answers */
const correctColor = "#d4edda";
/* @tweakable the background color for incorrect answers */
const incorrectColor = "#f8d7da";
/* @tweakable the highlight color for selected items */
const highlightColor = "lightblue";
const questionContainer = document.getElementById('question-container');
const answerContainer = document.getElementById('answer-container');
const resultDiv = document.getElementById('result');
let selectedQuestion = null;
let selectedAnswer = null;
let questions = questionsData.map(q => q["題目"]);
let answers = questionsData.map(q => q["答案"]);
// Shuffle arrays
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
shuffleArray(questions);
shuffleArray(answers);
// Function to create item elements
function createItem(text, container, isQuestion) {
const item = document.createElement('div');
item.classList.add('item');
item.textContent = text;
item.addEventListener('click', () => selectItem(text, item, isQuestion));
container.appendChild(item);
return item;
}
// Populate questions and answers
const questionElements = questions.map(text => createItem(text, questionContainer, true));
const answerElements = answers.map(text => createItem(text, answerContainer, false));
// Selection function
let selectedQuestionText = null;
let selectedAnswerText = null;
function selectItem(text, element, isQuestion) {
if (isQuestion) {
if (selectedQuestion) {
selectedQuestion.classList.remove('selected');
}
selectedQuestion = element;
selectedQuestionText = text;
selectedAnswerText = null; // Clear the answer when a new question is selected
if (selectedAnswer) selectedAnswer.classList.remove('selected');
selectedAnswer = null;
} else {
if (selectedAnswer) {
selectedAnswer.classList.remove('selected');
}
selectedAnswer = element;
selectedAnswerText = text;
}
element.classList.add('selected');
if (selectedQuestionText && selectedAnswerText) {
checkAnswer();
}
}
// Check answer function
function checkAnswer() {
const correct = questionsData.some(q => q["題目"] === selectedQuestionText && q["答案"] === selectedAnswerText);
if (correct) {
const explanation = questionsData.find(q => q["題目"] === selectedQuestionText)["解釋"];
resultDiv.textContent = `✅ 正確:${explanation}`;
resultDiv.className = "result-area correct";
} else {
resultDiv.textContent = "❌ 錯誤,請再試一次";
resultDiv.className = "result-area incorrect";
}
// Reset selections after a short delay
setTimeout(() => {
if (selectedQuestion) selectedQuestion.classList.remove('selected');
if (selectedAnswer) selectedAnswer.classList.remove('selected');
selectedQuestion = null;
selectedAnswer = null;
selectedQuestionText = null;
selectedAnswerText = null;
resultDiv.textContent = "請點選題目與答案配對";
resultDiv.className = "result-area"; // Reset class
}, /* @tweakable Time in ms to reset the selections */ 1500);
}
更好玩的在後頭──讓想像奔馳
GPT 的神助攻,讓我們不怕做不到,只怕想不到!
讀者們,是否己磨拳擦掌、躍躍欲試了呢?我們提供下列幾個任務給您動手練練功:
加上發音和音效
讀入題目資料檔
改寫成「闖關」遊戲
改寫成「多人搶答」遊戲
……
[1]六種授權條款。
(作者為本刊專欄作家,本文同步表於作者部落格,原文連結;責任編輯:謝涵如)
- 用GenAI生成連連看樣板 - 2025/05/15
- 細談「春仔產生器」的專案拆解 - 2025/04/17
- 用生成式AI打造「春仔」產生器 - 2025/03/12
訂閱MakerPRO知識充電報
與40000位開發者一同掌握科技創新的技術資訊!