【AI 加持下的 Python 編程實戰 2_09】DIY 拓展:從掃雷小游戲開發再探問題分解與 AI 代碼調試能力(上)

DIY 拓展:從掃雷小游戲開發再探問題分解與 AI 代碼調試能力(上)


1 起因

最近在看去年剛出了第 2 版《Learn AI-assisted Python Programming》,梳理完 第七章 的知識點后,總感覺這一章的話題很好——問題分解能力的培養——美中不足的是演示案例過于簡單,有點意猶未盡。今天就用一個前端掃雷小游戲的全流程開發再來落地實操一回。

最終效果如下:

圖 1:前端掃雷游戲最終效果圖

【圖 1:前端掃雷游戲最終效果圖】

2 思路分析

為了突出訓練重點,這里將掃雷游戲略作簡化,只保留核心功能:難度選擇和掃雷操作,其他像計時、聲音、排行榜等功能暫不考慮。因此整理后的需求描述如下:

  1. 支持 “初級”、“中級”、“高級” 三種難度;
  2. 記錄每局總地雷數以及實時排雷數;
  3. 根據選擇的難度生成指定尺寸、固定地雷數的網格區域,通過左鍵探雷、右鍵標記地雷(不考慮 “待定” 標記);
  4. 探雷時:
    1. 如果踩到地雷則游戲結束;
    2. 為安全區域,則:
      1. 周圍有雷:標記出周圍 8 個單元格存在的地雷總數;
      2. 周圍無雷:從當前單元格向四周擴散,直到發現標有地雷數的邊界區域。
  5. 排雷時,點擊鼠標右鍵即可標記為雷區,之后左鍵無法單擊繼續;
  6. 獲勝條件:正確探明所有安全區域才算獲勝(僅標注地雷不算勝出)。

那么按照上述需求,應該如何分類呢?每一局無論區域有多大,地雷有多少,都可以將整個界面剝離成兩類問題:

  1. 頁面的渲染問題;
  2. 頁面元素的事件綁定問題;

接下來就圍繞這兩類問題進行討論,看看問題分解如何發揮作用。

3 問題分解實戰

根據剛才的思路分析,頁面渲染和事件綁定存在明顯的先后順序和依賴關系:渲染出頁面后才能綁定事件,并且綁定事件還需要知道每個單元格的狀態(即地雷數據)。于是可以設計出如下兩個子函數:

let currentLv = 0;function start(lv = currentLv) {// init game boardconst mineCells = init(lv);// bind eventsbindEvents(lv, mineCells);
}start(currentLv);

在對這兩個任務做進一步分解前,需要先準備好游戲需要的靜態頁面。

3.1 靜態頁面與基礎樣式

這一步包括 HTML 基本結構和 CSS 基礎樣式。選型時為了更靈活地設置樣式,選用了 iconfont + 樣式類來實現所有的單元格圖案和標記:

圖 2:游戲界面用到的主要圖標字體(來源:阿里圖標庫)

【圖 2:游戲界面用到的主要圖標字體(來源:阿里圖標庫)】

使用方法:

<!-- 引入樣式 -->
<link rel="stylesheet" href="./iconfont.css">
<!-- 設置圖標 -->
<span class="mine ms-xxx"></span>

具體圖標從阿里圖標庫選取即可,這里不多贅述。對照最開始給出的頁面效果,再上網找出經典掃雷游戲需要的基本效果,于是有了如下兩個文件:

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Mine Sweeper Game</title><link prefetch rel="stylesheet" href="assets/font/iconfont.css"><link async rel="stylesheet" href="assets/css/index.css"><link async rel="shortcut icon" href="assets/favicon.png" type="image/x-icon">
</head>
<body><div class="container"><h1>掃雷游戲</h1><section class="level"><span>難度:</span><button data-level="1" class="active">初級</button><button data-level="2">中級</button><button data-level="3">高級</button><button class="restart hidden">重新開始</button></section><section class="stats"><div class="score">地雷數:<span id="mineCount"></span></div><div class="time">已排除:<span id="mineFound"></span></div><section class="game"><table class="gameBoard"></table></section></div><script src="assets/js/index.js" type="module"></script>
</body>
</html>

以及對應的樣式文件 index.css

* {margin: 0;padding: 0;box-sizing: border-box;font-family: Verdana, sans-serif;--cell-size: 25px;
}.container {margin-inline: auto;text-align: center;
}h1 {font-size: 1.7rem;margin-block: 1rem;
}.level {padding: .5em 0;&>button {padding: .3em .7em;border: none;border-radius: 5px;background-color: #cdd4d8;&.active {background-color: #0856df;color: #fff;font-weight: bold;}&.hidden {display: none;}}
}.stats {padding: .5em;
}#mineCount, #mineFound {font-weight: 700;color: maroon;
}.gameBoard {border: 6px solid #d4d4d4;outline: 1px solid #808080;margin: 1em auto;background-color: #c0c0c0;
}.cell {border-top: 3px solid #ffffff;border-left: 3px solid #ffffff;border-right: 3px solid #808080;border-bottom: 3px solid #808080;width: var(--cell-size);height: var(--cell-size);line-height: var(--cell-size);font-size: 1rem;cursor: pointer;&.invalid {background-color: violet;}&.mine {background: #c0c0c0;border: 1px solid #e4e4e4;opacity: 1;&.ms-mine {font-size: 1.2em;line-height: var(--cell-size);vertical-align: middle;color: #000;}&.ms-flag {font-size: 1em;line-height: var(--cell-size);vertical-align: middle;color: #f00;}&.ms-flag.correct {background: #6ad654;}}&.fail {background: #bb3d3d;border: 1px solid #808080;opacity: 1;}&.number {border-collapse: collapse;background: #c0c0c0;border: 1px solid #dddddd;font-weight: bold;}&.mc-0 {color: #c0c0c0;}&.mc-1 {color: #0000FF;}&.mc-2 {color: #008000;}&.mc-3 {color: #FF0000;}&.mc-4 {color: #000080;}&.mc-5 {color: #800000;}&.mc-6 {color: #008080;}&.mc-7 {color: #000000;}&.mc-8 {color: #808080;}
}

3.2 頁面渲染邏輯

設計好了靜態頁面,接下來就可以安心拆解 JavaScript 核心邏輯了。

首先是 init(lv) 方法。該方法應該有三個基本任務:

  1. 在頁面中心位置加載出掃雷區域;
  2. 頁面統計指標(總地雷數、已探明雷數)均設為初始值;
  3. 狀態矩陣。

前兩個不用多想,第三個任務要費點腦筋。這里絕不能將單元格的狀態信息放入頁面元素(例如 data-* 屬性),否則打開 F12 調試工具就能輕松破解游戲。

因此必須單獨維護一個與頁面每個單元格綁定的 狀態矩陣(即對象數組)。

這樣一來,init(lv) 就可以拆分為以下三個板塊:

let mineFound = 0;
function init(lv) {// 1. create table elementsconst doms = renderGameBoard(lv);// 2. render stats info$('#mineCount').innerHTML = lv.mine;$('#mineFound').innerHTML = mineFound;// 3. create mine arrayconst mines = generateMineCells(lv, doms);return mines;
}

由于中間那項過于簡單,就不必另外創建函數實現了。這里需要再次拆分的是負責加載 DOM 節點的渲染函數 renderGameBoard(lv) 以及對應的狀態矩陣生成函數 generateMineCells(lv, doms)

要渲染單元格,既可以使用 div 也可以使用 table 表格,這里我傾向用 table,因為掃雷的整體風格感覺就像一個 Excel,而且單元格什么的也叫習慣了(哈哈)。到時候根據關卡對象 lv 拿到總的行列數與地雷數,就能批量生成掃雷區域了。

比較燒腦的是狀態矩陣的數據結構:每個單元格要存放哪些信息呢?這一部分只能慢慢完善:

  1. id:即 ID 編號。該編號值設置不僅要保持統一,更重要的是要明確制定一套轉換公式,可以很方便地知道該 ID 值和頁面單元格坐標((iRow, jCol))的對應關系(屆時這些轉換公式都放入單獨的 utils.js 模塊,以免干擾核心邏輯)。
  2. isMine:即該單元格是否為地雷的定性標記;
  3. mineCount:如果當前單元格不是地雷,則用它表示周圍的地雷數,這樣進行鼠標操作時就能直接顯示,無需臨時計算;
  4. flagged:表示當前單元格是否被標為地雷,若已經標記,則該單元格不可再次點擊,除非取消標記;

先暫定上述四個基本狀態,后面需要增補再說。有了這樣的數據結構,整個掃雷游戲的數據流就清楚了:用戶通過各種操作觸發狀態矩陣的改變,狀態矩陣再將變化情況更新到掃雷區域:

點擊/標記等事件
更新數據
渲染界面
用戶頁面操作
掃雷狀態矩陣
頁面掃雷區域

【圖 3:掃雷基本數據流向示意圖】

這樣,init() 的拆分就暫告一個段落了,如下圖所示:

flowchart LRA[start] --> B[init]A --> C[bindEvents]B --> D[renderGameBoard]B --> E[renderStatsInfo(無需創建)]B --> F[generateMineCells]

【圖 4 初步確定的 init() 函數拆分方案】

3.2 事件綁定邏輯

(未完待續)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76862.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76862.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76862.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用DeepSeek-Prover-V1.5解決數學問題

DeepSeek-Prover-V1.5-RLRMaxTS是一個結合強化學習和搜索策略的自動定理證明系統。 1. 初等代數&#xff1a;二次方程求解 問題&#xff1a;解方程 x - 5x 6 0 操作步驟&#xff1a; 將問題轉換為Coq形式&#xff1a; Theorem quadratic : exists x : Z, x^2 - 5*x 6 0…

3.3 技術框架:LangChain、ReAct、Memory與Tool Integration

隨著人工智能技術的飛速發展&#xff0c;智能代理&#xff08;Agent&#xff09;已成為企業實現自動化、智能化和個性化服務的核心工具。在2025年&#xff0c;技術框架如LangChain、ReAct、Memory和Tool Integration在構建高效、靈活的AI代理系統中占據了重要地位。這些框架通過…

STM32F103 單片機(基于 ARM Cortex-M3 內核)的啟動過程涉及硬件初始化、固件配置和程序執行流程。

1. 啟動模式與地址映射 STM32F103 的啟動模式由 BOOT0 和 BOOT1 引腳配置決定&#xff0c;不同的啟動模式對應不同的存儲器映射&#xff1a; 啟動模式 映射地址范圍 說明 主 Flash 0x08000000~0x0807FFFF 用戶程序存儲在 Flash 中&#xff0c;復位后從 Flash 啟動&#xff08…

【C語言-選擇排序算法】實現對十個數進行排序

目錄 前言 一、選擇排序算法原理 二、選擇排序算法實現對十個數進行排序 三、代碼運行示例 四、選擇排序算法的時間復雜度和空間復雜度分析 五、選擇排序算法的優缺點 六、總結 前言 在計算機科學領域&#xff0c;排序算法是基石般的存在&#xff0c;它們就像是整理雜亂…

配置Intel Realsense D405驅動與ROS包

配置sdk使用 Ubuntu20.04LTS下安裝Intel Realsense D435i驅動與ROS包_realsense的驅動包-CSDN博客 中的方法一 之后不通過apt安裝包&#xff0c;使用官方的安裝步驟直接clone https://github.com/IntelRealSense/realsense-ros/tree/ros1-legacy 從這一步開始 執行完 這一步…

基于SpringBoot的中華詩詞文化分享平臺-項目分享

基于SpringBoot的中華詩詞文化分享平臺-項目分享 項目介紹項目摘要管理員功能圖會員功能圖系統功能圖項目預覽會員主頁面詩詞頁面發布問題回復評論 最后 項目介紹 使用者&#xff1a;管理員、會員 開發技術&#xff1a;MySQLJavaSpringBootVue 項目摘要 本文旨在設計與實現一…

ProxySQL 性能調優工具推薦

ProxySQL 的性能優化需結合?實時監控工具?與?自動化分析平臺?,以下為常用工具分類與推薦: 一、?內置診斷工具? ProxySQL Admin 接口? 通過內置管理表直接分析性能數據: sql Copy Code SELECT * FROM stats_mysql_query_digest; – 高頻查詢分析(執行次數、平均耗…

unity TEngine學習記錄3

上一篇講了怎么使用te框架&#xff0c;本篇主要學習的是UI&#xff0c;一個游戲百分之70%都是UI的展示效果&#xff0c;現在讓我們繼續打開te官網找到UI部分繼續學習。 ui創建以及加載 我們根據文檔首先打開命名規則界面,大家第一次看就知道這個是干啥的&#xff0c;你想使用此…

23種設計模式-創建型模式之單例模式(Java版本)

Java 單例模式&#xff08;Singleton Pattern&#xff09;詳解 &#x1f31f; 什么是單例模式&#xff1f; 單例模式確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來訪問它。 &#x1f9e0; 使用場景 配置管理類&#xff08;如讀取配置文件&#xff09;日志工具類…

2025能源網絡安全大賽CTF --- Crypto wp

文章目錄 前言simpleSigninNumberTheory 前言 大半年以來寫的第一篇文章&#xff01;&#xff01;&#xff01; simpleSignin 題目&#xff1a; from Crypto.Util.number import * from gmpy2 import * import osflag bxxx p next_prime(bytes_to_long(os.urandom(128))…

加密與解密完全指南,使用Java實現

文章目錄 1. 加密基礎知識1.1 什么是加密&#xff1f;1.2 加密的歷史簡介1.2.1 古典加密1.2.2 現代加密的起源 1.3 加密的基本概念1.3.1 密碼學中的關鍵術語1.3.2 加密的基本原則 1.4 加密的分類1.4.1 對稱加密&#xff08;Symmetric Encryption&#xff09;1.4.2 非對稱加密&a…

十一、數據庫day03--SQL語句02

文章目錄 一、查詢語句1. 基本查詢2. 條件查詢2.1 ?較運算符&邏輯運算符2.2 模糊查詢2.3 范圍查詢2.4 判斷空 3. 其他復雜查詢3.1 排序3.2 聚合函數3.3 分組3.4 分頁查詢 二、回顧1. 使? Navicat ?具中的命令列2.命令?基本操作步驟 提示&#xff1a;以下是本篇文章正文…

Flowable 與 bpmn.io@7.0 完整集成示例 Demo

Flowable 與 bpmn.io7.0 完整集成示例 Demo 下面是一個完整的前后端集成示例&#xff0c;包含前端使用 bpmn.js 7.0 和與 Flowable 后端交互的實現。 1. 后端實現 (Spring Boot Flowable) 1.1 添加依賴 (pom.xml) <dependencies><!-- Spring Boot --><depe…

ROS2 安裝詳細教程,Ubuntu 22.04.5 LTS 64 位 操作系統

一、完整安裝流程&#xff08;推薦&#xff09; 1. 安裝依賴工具 sudo apt update && sudo apt install -y software-properties-common curl gnupg2 2. 添加 ROS 2 GPG 密鑰 sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /…

STM32 基本GPIO控制

目錄 GPIO基礎知識 ?編輯IO八種工作模式 固件庫實現LED點燈 蜂鳴器 按鍵基礎知識 ?編輯繼電器 震動傳感器 433M無線模塊 GPIO基礎知識 GPIO(General-Purpose input/output,通用輸入/輸出接口) 用于感知外部信號&#xff08;輸入模式&#xff09;和控制外部設備&…

14.Chromium指紋瀏覽器開發教程之WebGL指紋定制

WebGL指紋概述 當在瀏覽器打開的網頁上瀏覽內容時&#xff0c;看到的大多是平面的、靜態的圖像和文字。但是有時想要在網頁上看到更加生動、立體的圖像&#xff0c;如3D游戲、虛擬現實應用等。這時&#xff0c;就需要用到WebGL。 簡單來說&#xff0c;WebGL&#xff08;Web G…

C# foreach 循環中獲取索引的完整方案

一、手動維護索引變量 ?實現方式?&#xff1a; 在循環外部聲明索引變量&#xff0c;每次迭代手動遞增&#xff1a; int index 0; foreach (var item in collection) { Console.WriteLine($"{index}: {item}"); index; } ?特點?&#xff1a; 簡單直接&#…

Android 下拉欄中的禁用攝像頭和麥克風隱藏

Android 下拉欄中的禁用攝像頭和麥克風隱藏 文章目錄 Android 下拉欄中的禁用攝像頭和麥克風隱藏一、前言二、下拉框中的禁用攝像頭和麥克風隱藏實現1、設置支持屬性為false2、修改代碼 三、其他1、下拉欄中的禁用攝像頭和麥克風隱藏小結2、 Android SensorPrivacyService ps&a…

數字后端設計 (四):時鐘樹綜合——讓芯片的「心跳」同步到每個角落

—— 試想全城的人要在同一秒按下開關——如果有的表快、有的表慢&#xff0c;結果會亂套&#xff01;時鐘樹綜合就是給芯片內部裝一套精準的“廣播對時系統”&#xff0c;讓所有電路踩著同一個節拍工作。 1. 為什么時鐘如此重要&#xff1f; 芯片的「心跳」&#xff1a;時鐘信…

華為網路設備學習-19 路由策略

一、 二、 注意&#xff1a; 當該節點匹配模式為permit下時&#xff0c;參考if else 當該節點匹配模式為deny下時&#xff1a; 1、該節點中的apply子語句不會執行。 2、如果滿足所有判斷&#xff08;if-match&#xff09;條件時&#xff0c;拒絕該節點并跳出&#xff08;即不…