No Code AI(肉寇)AI自動化兩日精通|實體6小時+線上6小時
|

用GenAI生成連連看樣板

   

作者: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]六種授權條款

(作者為本刊專欄作家,本文同步表於作者部落格,原文連結;責任編輯:謝涵如)

Ted Lee

訂閱MakerPRO知識充電報

與40000位開發者一同掌握科技創新的技術資訊!

Author: Ted Lee

從工程師轉任中學教師,又為了捍衛教育理念,投身成為 STEAM 教育工作者,自稱「無可救藥的人文教育理想主義者」的李俊德(Ted Lee)。

Share This Post On
468 ad

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *