專案背景
這是我在大學「動態網頁程式設計」課程中的期中作業。目標是使用原生 JavaScript、HTML 和 CSS,不依賴任何前端框架,來實作一個功能完整的 Blackjack (21點) 遊戲。
一個有趣的要求是,老師希望我們加上「作弊模式」作為警惕,告訴我們網路賭博都不可信。當你勾選左下角的 "cheat" 後,遊戲的隨機抽牌演算法會被調整,讓莊家擁有極高的勝率。
技術實現與挑戰
對於當時的我來說,這個專案最大的挑戰在於完全使用原生 JavaScript 來處理所有遊戲狀態和互動邏輯。那個時候還沒有 ChatGPT 哈哈哈,所以全部都是一個個 console.log
慢慢刻出來的,但也因此學到很多:
-
複雜的遊戲狀態管理:我使用了一系列全域變數來追蹤玩家與莊家的手牌、點數、金錢、當前回合等多個狀態。那時候對狀態管理還很不熟,現在回頭看,才發現自己當時手動實現了一個多麼脆弱的狀態機。
-
非同步動畫流程:為了模擬真實賭場的發牌節奏,我使用了
async/await
搭配自訂的sleep
函式。在每一次發牌的 DOM 操作之間創造出延遲,讓視覺動畫與遊戲邏輯能同步進行,這讓我對 JavaScript 的非同步有了更具體的認識。 -
Blackjack 核心規則實現:
- A 的彈性計分:在計分函式
countPoint
中,透過if/else
判斷式,處理了 Ace (A) 應被計算為 1 點或 11 點的關鍵邏輯。 - 分牌 (Split) 邏輯:當玩家拿到對子時,
split()
函式會動態地將單一玩家區域 (playerArea
) 分割成兩個獨立的手牌區域 (playerArea1
,playerArea2
),並分別追蹤它們的點數與爆牌狀態,這應該是整個專案中最複雜的狀態管理挑戰之一。 - 莊家 AI:在玩家
stand()
後,莊家會根據「點數小於 17 必須加牌」的規則自動行動,直到滿足條件為止。
- A 的彈性計分:在計分函式
-
原生 DOM 操作:遊戲中所有的視覺更新,例如動態生成卡牌
<img>
元素、更新計分板、顯示遊戲結果等,都是透過document.getElementById
和createElement
等原生 DOM API 來完成的。
學習與反思
透過這個專案,我對 JavaScript 的事件驅動編程、非同步處理和狀態管理有了非常深刻的實戰經驗。它讓我體會到,雖然現代框架很強大,但理解其底層的原生 JavaScript 運作原理,才是建立穩固基礎的關鍵。
如果現在要重做這個專案,我會選擇使用 React (Next.js) 來進行元件化管理,並用 useState
或 useReducer
Hook 來處理複雜的遊戲狀態,取代直接操作 DOM。這樣不僅能讓程式碼的結構更清晰、更容易維護,也能更好地將 UI 表現與遊戲邏輯分離。
註:本文案使用 Gemini 2.5 Pro 進行最終的文字潤飾。