網頁版的量子戰艦遊戲根據先前的文字版本,利用 Python CGI 指令碼處理後端邏輯,並透過 AJAX 技術與前端 JavaScript 進行非同步資料交換。前端使用 HTML 表格與 JavaScript 動態產生遊戲棋盤,讓玩家放置船艦與投擲炸彈。後端 CGI 指令碼接收前端請求,使用 Qiskit 執行量子計算,模擬戰艦受損狀態,並將結果以 JSON 格式回傳前端。前端再根據回傳結果更新遊戲介面,顯示戰艦損傷情況。遊戲規則的驗證邏輯在前端 JavaScript 中實作,確保玩家的操作符合遊戲規則,例如船艦數量限制、炸彈投擲時機等。此外,專案整合了 jQuery、Bootstrap 和 Bootstrap-Growl 等第三方函式庫,提升使用者經驗和介面互動性。
量子戰艦遊戲網頁版實作與佈署
在前一個練習中,我們建立了一個文字版的量子戰艦遊戲。現在,我們將透過Python CGI指令碼和AJAX技術,將這個遊戲轉換為網頁版,並佈署在Apache HTTPD伺服器上。
網頁版遊戲機制
網頁版的遊戲機制與文字版完全相同。每個玩家在棋盤上放置三艘船,然後輪流投擲炸彈並點選「提交」按鈕。Python CGI指令碼會接收AJAX請求,執行量子程式,並傳回損傷報告以在JavaScript中呈現。
程式碼實作
首先,我們需要建立一個Python CGI指令碼,用於接收HTTP請求並傳回JSON格式的損傷報告。以下是指令碼的第一部分:
import sys
from qiskit import QuantumProgram
import Qconfig
import getpass, random, numpy, math
import cgi
import cgitb
# 解決QISKit的相對依賴問題
sys.path.append('../../qiskit-sdk-py/')
# 啟用除錯模式
cgitb.enable(display=0, logdir=".")
# 初始化遊戲狀態
shipPos = [ [-1]*3 for _ in range(2)]
bomb = [ [0]*5 for _ in range(2)]
內容解密:
import cgi和import cgitb:匯入用於處理HTTP請求和除錯的Python函式庫。cgitb.enable(display=0, logdir="."):啟用除錯模式,將錯誤報告儲存到當前工作目錄,而不是直接顯示在網頁上。shipPos和bomb:初始化用於儲存遊戲狀態的資料結構,分別用於儲存船隻位置和炸彈投擲次數。
接下來,指令碼會讀取HTTP請求中的遊戲資料:
# 解析HTTP請求
form = cgi.FieldStorage()
ships1 = form["ships1"].value
ships2 = form["ships2"].value
bombs1 = form["bombs1"].value
bombs2 = form["bombs2"].value
device = str(form["device"].value)
# 解析船隻位置和炸彈投擲次數
shipPos[0] = list(map(int, ships1.split(",")))
shipPos[1] = list(map(int, ships2.split(",")))
bomb[0] = list(map(int, bombs1.split(",")))
bomb[1] = list(map(int, bombs2.split(",")))
內容解密:
cgi.FieldStorage():用於解析HTTP請求中的資料,傳回一個字典或雜湊對映。ships1、ships2、bombs1、bombs2:從HTTP請求中提取的玩家船隻位置和炸彈投擲次數。device:指定使用的量子裝置或模擬器。
佈署與測試
完成Python CGI指令碼後,我們需要將其佈署到Apache HTTPD伺服器上。首先,確保伺服器已安裝並組態正確。然後,將指令碼放置在伺服器的CGI目錄中,並設定正確的許可權。
量子戰艦遊戲實作:前後端整合與量子計算應用
前端設計與使用者介面
量子戰艦遊戲採用2x2的HTML表格結構來呈現四個3x3的子表格,分別代表兩位玩家的艦船佈置與炸彈投放狀態,如圖4所示。前端使用JavaScript動態生成這些表格,程式碼如下:
<form id="frm1">
裝置選擇
<select id="device" name="device">
<option value="local_qasm_simulator">本地模擬器</option>
<option value="ibmqx_qasm_simulator">IBM量子模擬器</option>
<option value="ibmqx2">ibmqx2真機</option>
</select>
請放置3艘艦船並投放炸彈後提交
<table>
<tr>
<td>
<div><h3>玩家1艦船</h3></div>
<script type="text/javascript">table(1, 's')</script>
</td>
<td>
<div><h3>玩家2艦船</h3></div>
<script type="text/javascript">table(2, 's')</script>
</td>
</tr>
<tr>
<td>
<div><h3>玩家1炸彈</h3></div>
<script type="text/javascript">table(1, 'b')</script>
</td>
<td>
<div><h3>玩家2炸彈</h3></div>
<script type="text/javascript">table(2, 'b')</script>
</td>
</tr>
</table>
</form>
內容解密:
- 使用
<form>標籤建立表單,包含裝置選擇下拉選單與資料提交功能 - 採用2x2表格結構呈現雙玩家的操作介面
- JavaScript函式
table(玩家編號, 's/b')動態生成3x3的子表格,用於艦船佈置與炸彈投放 - 介面設計兼顧操作直觀性與資料收集需求
後端量子計算實作
後端採用Python CGI處理前端請求,並呼叫QISKit進行量子計算。主要流程如下:
# 初始化量子程式
Q_program = QuantumProgram()
Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"])
# 宣告量子暫存器與經典暫存器
q = Q_program.create_quantum_register("q", 5)
c = Q_program.create_classical_register("c", 5)
# 建立量子電路
gridScript = Q_program.create_circuit("gridScript", [q], [c])
# 根據對手炸彈佈局施加量子操作
for position in range(5):
for n in range(bomb[(player+1)%2][position]):
for ship in [0,1,2]:
if position == shipPos[player][ship]:
frac = 1/(ship+1)
gridScript.u3(frac * math.pi, 0.0, 0.0, q[position])
# 測量結果
for position in range(5):
gridScript.measure(q[position], c[position])
# 執行量子電路
results = Q_program.execute(["gridScript"], backend=device, shots=shots)
內容解密:
- 使用QISKit建立量子程式並設定API憑證
- 根據玩家艦船位置與對手炸彈佈局建立量子電路
- 對每個量子位元施加受控的U3旋轉門操作,模擬炸彈效果
- 執行電路並測量結果以評估傷害程度
資料交換與處理流程
系統透過AJAX非同步請求實作前後端資料交換,主要流程如下:
- 前端收集玩家輸入的艦船位置與炸彈佈局
- 將資料封裝為JSON格式透過HTTP請求傳送至後端
- 後端Python CGI指令碼解析請求引數並執行量子計算
- 將計算結果以JSON格式回傳前端並更新介面顯示
JSON回應格式範例:
{
"status": 200,
"message": "Device ibmqx_qasm_simulator",
"damage": [[0.5, 0, 0, 0, 0], [0, 0.9, 0, 0, 0]]
}
內容解密:
- 狀態碼(status)表示處理結果
- 訊息欄位(message)提供執行裝置資訊或其他除錯資訊
- 傷害評估(damage)以二維陣列形式呈現雙方受損情況
系統整合關鍵點
- 前後端協同:透過AJAX實作非同步資料交換,確保遊戲流程的連貫性
- 量子計算整合:將QISKit量子計算框架無縫整合至Web應用中,實作真實的量子遊戲體驗
- 介面互動設計:採用直觀的表格介面簡化玩家操作,同時滿足資料收集需求
本實作展示瞭如何將複雜的量子計算概念轉化為互動式Web應用,不僅展現了量子程式設計的技術實力,也為遊戲化科學普及提供了創新思路。
雲端戰艦遊戲的使用者介面與遊戲規則實作
雲端戰艦遊戲採用動態渲染的3x3棋盤,使用document.write()系統呼叫實作,如清單6-10所示。
清單6-10:使用document.write()動態渲染表格
// type: 's' (ship) = checkbox, 'b' (bomb) = radio
function table(player, type) {
var d = document;
var html = '<table border="1">\n';
var qubit = 0;
for (var i = 0; i < 3; i++) {
html += '<tr>';
for (var j = 0; j < 3; j++) {
if ((i + j) % 2 == 0) {
var id = 'p' + player + type + qubit++;
// checkbox = ship, radio = bomb
var itype = type == 's' ? 'checkbox' : 'radio';
var extra = type == 'b' ? ' onclick="cell_click_bomb(this)"'
: ' onclick="return cell_click_ship(this)"';
// <TD> SHIP-INDEX DAMAGE IMAGE </TD>
html += '<td>' + (qubit - 1)
+ ' <span id="' + type + player + (qubit - 1) + '"></span>'
+ '<input id="' + id + '" name="' + id + '" type="' + itype
+ '"' + extra + '>'
+ '<label for="' + id + '" class="ship"> </label></td>';
} else {
html += '<td> </td>';
}
}
html += '</tr>\n';
}
html += '</table>';
d.write(html);
}
內容解密:
table函式:根據玩家和型別(ship或bomb)動態生成3x3的表格。document.write(html):將生成的HTML字串寫入檔案,實作動態渲染。if ((i + j) % 2 == 0):控制表格單元格的顯示,只有偶數索引的單元格才會顯示內容。var itype = type == 's' ? 'checkbox' : 'radio';:根據型別決定輸入框是核取方塊還是單選按鈕。var extra:為輸入框新增點選事件處理函式,根據型別分別呼叫cell_click_ship或cell_click_bomb。
使用者介面的主要特點
表格6-1展示了雲端戰艦遊戲使用者介面的主要特點。
表格6-1:雲端戰艦遊戲使用者介面提示與技巧
- 隱藏核取方塊和單選按鈕,使用樣式表控制顯示。
- 每個船隻單元格包含:
- Qubit編號
- 用於顯示損傷百分比的HTML span元素
- 經過CSS修改的
<input type="checkbox">,使用100x100畫素的圖片代替預設控制項
- 每個炸彈單元格包含:
- Qubit編號
- 用於顯示炸彈計數的HTML span元素
- 經過CSS修改的
<input type="radio">,使用100x100畫素的圖片代替預設控制項
CSS樣式控制
input[type=checkbox]:not(old),
input[type=radio]:not(old) {
width: 104px;
margin: 0;
padding: 0;
opacity: 0;
}
input[type=checkbox]:not(old) + label {
display: inline-block;
margin-left: -104px;
padding-left: 104px;
background: url('img/ship.png') no-repeat 0 0;
line-height: 100px;
}
input[type=radio]:not(old) + label {
display: inline-block;
margin-left: -104px;
padding-left: 104px;
background: url('img/bomb.png') no-repeat 0 0;
line-height: 100px;
}
input[type=checkbox]:not(old):checked + label {
background-position: 0 -100px;
}
input[type=radio]:not(old):checked + label {
background-position: 0 -100px;
}
內容解密:
- 隱藏預設控制項:使用
opacity: 0;隱藏核取方塊和單選按鈕。 - 自訂標籤樣式:使用
background屬性設定自訂圖片,並調整margin和padding以正確定位。 - 選中狀態處理:使用
:checked偽類別改變選中時的圖片顯示。
遊戲規則與驗證
由於HTTP是無狀態協定,所有資料結構和驗證邏輯必須移到客戶端。例如:
- 玩家不能在棋盤上放置超過三艘船。
- 在炸彈放置後,不允許更改船隻位置。
- 在所有玩家放置船隻之前,不能放置炸彈。
這些規則可以透過在點選船隻或炸彈單元格時增加回呼函式來強制執行,如清單6-11所示。
清單6-11:使用點選回呼函式強制執行遊戲規則
// 當點選船隻單元格時觸發
function cell_click_ship(obj) {
var id = obj.id;
var player = parseInt(id.charAt(1));
var qubit = parseInt(id.charAt(3));
var json = countShipsBombs();
LOGD('Cell Clicked ' + id + ' Counts:' + JSON.stringify(json));
if (json.ships[0] > 3 || json.ships[1] > 3) {
return error('所有玩家必須只放置3艘船。');
}
// 在炸彈放置後不允許更改船隻
if (json.bombs[0] > 0 || json.bombs[1] > 0) {
return error('炸彈放置後不允許更改船隻。');
}
return true;
}
// 當點選炸彈單元格時觸發
function cell_click_bomb(obj) {
var id = obj.id; // For Bombs: p[PLAYER]b[QUBIT]
var player = parseInt(id.charAt(1));
var qubit = parseInt(id.charAt(3));
// validate: { 'ships': [s1, s2], 'bombs': [b1, b2]}
var json = countShipsBombs();
LOGD('Bomb Clicked ' + id + ' Counts:' + JSON.stringify(json));
if (json.ships[0] < 3 || json.ships[1] < 3) {
$('#' + id).attr('checked', false);
return error('所有玩家必須先放置3艘船。');
}
if (mustSubmit) {
return error('炸彈已放置,請點選提交。');
}
}
內容解密:
cell_click_ship函式:檢查玩家是否放置超過三艘船,以及是否在炸彈放置後試圖更改船隻位置。cell_click_bomb函式:檢查所有玩家是否都已放置三艘船,以及是否已經提交過炸彈。countShipsBombs():計算當前船隻和炸彈的數量,用於驗證遊戲規則。
使用第三方函式庫提升使用者經驗
雲端戰艦遊戲使用了多個第三方函式庫來增強使用者經驗,包括jQuery、Bootstrap和Bootstrap-Growl,用於渲染訊息和除錯資訊。
<script type="text/javascript" src="js/log.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/bootstrap-growl.js"></script>
<script type="text/javascript" src="js/notify.js"></script>
使用Bootstrap-Growl顯示訊息
notify('炸彈準備就緒,請點選提交', info);
內容解密:
- 引入第三方函式庫:使用jQuery、Bootstrap和Bootstrap-Growl等函式庫增強使用者介面和互動體驗。
notify函式:使用Bootstrap-Growl顯示訊息,例如「炸彈準備就緒,請點選提交」。