設計以下的簡單小遊戲。javascript
在面板(畫布)中放置10行10列共100個小方塊,每一個小方塊隨機在5種顏色中選一種顏色進行着色,在面板的下方,放置對應的5種顏色色塊,如圖1所示。html
圖1 「統一着色」遊戲界面java
遊戲要求經過每次對包含最左上角方塊的相鄰同色區域方塊改變着色的方式,最終使得面板中的100個小方塊着色統一。算法
例如,圖1中包含最左上角方塊的相鄰同色區域方塊只有1個,此時對其有效改變着色應該是選擇「綠色」(下方相鄰的方塊顏色)或「棕色」(左邊相鄰的方塊顏色),這樣擴大了包含最左上角方塊的相鄰同色區域;不然,不擴大包含最左上角方塊的相鄰同色區域,應是無效的着色選擇。canvas
單擊面板下方5個色塊中的某個色塊,就能夠將包含最左上角方塊的相鄰同色區域的全部方塊顏色改成所單擊色塊的顏色。一次遊戲過程如圖2所示。數組
圖2 「統一着色」遊戲過程示例dom
定義一個數組 函數
var colors = ["Aquamarine","Blue","BlueViolet","Brown","Chartreuse","Chocolate","Cyan",this
"DeepPink","Fuchsia","Green","Orange","Purple","Red","SkyBlue","Yellow"];spa
保存遊戲可供選擇的顏色。
每局遊戲選擇5個色塊,定義數組 var options=[];保存在colors數組中選擇的5種顏色所對應的下標。爲了達到隨機選擇5種顏色,採用對顏色數組進行簡單洗牌的方法來完成。
定義數組var blocks=[];保存面板中100個小方塊的着色,第i行第j列小方塊的着色保存在數組元素blocks[10*i+j]中。初始時,每一個小方塊的着色在選定的5種顏色中隨機選擇一種,一個簡單的循環可完成。
for (var i=0;i<100;i++)
blocks[i]=options[Math.floor(Math.random()*5)];
單擊面板下方5個小色塊中某個色塊後,調用函數setColor()完成改變着色的過程。
改變着色的區域是包含最左上角方塊的相鄰同色區域的全部方塊,所以關鍵問題是怎麼找到這個相鄰同色區域中的全部方塊。可採用廣度優先搜索算法的思想來完成。算法描述爲:
記下最左上角方塊的初始着色srcColor;
隊列初始化;
最左上角方塊編號 0入隊;
while (隊列非空)
{
隊頭元素出隊,賦給k;
改變方塊k的着色(修改blocks[k]的值爲所單擊色塊的顏色編號destColor);
if (方塊k右邊的方塊k+1存在且顏色爲srcColor)
方塊編號k+1入隊;
if (方塊k下邊的方塊k+10存在且顏色爲srcColor)
方塊編號k+10入隊;
}
實際上,一個方塊相鄰的方塊有上下左右四個,但算法中只需考慮右邊和下邊,無需考慮左邊和上邊。這是由於本遊戲的着色改變老是改變包含最左上角方塊的相鄰區域,即搜索老是從最左上角方塊開始,而最左上角方塊只能向右邊和下邊擴展,以後每一個方塊也只需向右邊和下邊擴展便可,無需向左邊和上邊擴展(由於左邊和上邊的方塊已被擴展處理過)。
獲勝判斷就更簡單了,由於獲勝的條件是全部方塊的着色統一,即數組blocks的元素值所有相同,所以用循環檢查元素blocks[1]~blocks[99],若它們的值所有與blocks[0]相同,則獲勝,不然只要有一個元素與blocks[0]不一樣,就沒有達到着色統一的獲勝要求。編寫爲一個簡單的函數。
function checkWin()
{
for (var i=1;i<blocks.length;i++)
if (blocks[i]!=blocks[0]) return false;
return true;
}
另外,爲避免遊戲過程當中的無效色塊單擊,記錄遊戲的步數(色塊單擊次數),若35步內不能完成統一着色,斷定遊戲失敗。
完整的HTML代碼以下。
<!DOCTYPE html> <html> <head> <title>統一着色</title> <style> .num { padding: 28px 0; border: 1px solid ; cursor: pointer; } .new-game { cursor: pointer; text-decoration: underline; color: #00bcd4; font:bold 24px Georgia, serif; } #mess { width:480px; padding:5px; border:2px solid gray; margin:0px; font:bold 24px Georgia, serif; color: #FF6600; } </style> </head> <body> <div class="new-game" onclick="newGame();">New Game</div><br/> <canvas id="myCanvas" width="500" height="500" style="border:3px double #996633;"> </canvas><br/> <table cellpadding="0" cellspacing="20"> <tbody><tr> <td width="60"><div id="c0" class="num" onclick="setColor(this);"></div></td> <td width="60"><div id="c1" class="num" onclick="setColor(this);"></div></td> <td width="60"><div id="c2" class="num" onclick="setColor(this);"></div></td> <td width="60"><div id="c3" class="num" onclick="setColor(this);"></div></td> <td width="60"><div id="c4" class="num" onclick="setColor(this);"></div></td> </tr> </tbody> </table><br/> <div id="mess"> </div><br/> <script type="text/javascript"> var canvas=document.getElementById('myCanvas'); ctx= canvas.getContext('2d'); var colors = ["Aquamarine","Blue","BlueViolet","Brown","Chartreuse","Chocolate","Cyan","DeepPink","Fuchsia ","Green","Orange","Purple","Red","SkyBlue","Yellow"]; var running = false; var steps=0; function shuffle(arr) // 數組arr洗牌 { for (var i = arr.length-1; i>=0; i--) { var j = Math.floor(Math.random() * i); var t=arr[i]; arr[i]=arr[j]; arr[j]=t; } } var colorNum=[]; for (var i=0;i<colors.length;i++) colorNum[i]=i; var options=[]; var blocks=[]; function newGame() { shuffle(colorNum); options=colorNum.slice(0,5); for (var i=0;i<100;i++) blocks[i]=options[Math.floor(Math.random()*5)]; running=true; steps=0; draw(); document.getElementById("c0").style.backgroundColor =colors[options[0]]; document.getElementById("c1").style.backgroundColor =colors[options[1]]; document.getElementById("c2").style.backgroundColor =colors[options[2]]; document.getElementById("c3").style.backgroundColor =colors[options[3]]; document.getElementById("c4").style.backgroundColor =colors[options[4]]; document.getElementById("mess").innerHTML ="Steps:"+steps+"/35"; } function draw() { for (var i=0;i<10;i++) { for (var j=0;j<10;j++) { ctx.fillStyle = colors[blocks[i*10+j]]; ctx.fillRect(j*50,i*50,50,50); } } ctx.fillStyle ="rgba(255,255,255,0.85)"; ctx.fillRect(20,20,10,10); } function setColor(d) { if (!running) { document.getElementById("mess").innerHTML ="請單擊 New Game 開始新遊戲!"; return; } var index= parseInt(d.id.charAt(1)); var srcColor=blocks[0]; var destColor=options[index]; if (srcColor==destColor) { document.getElementById("mess").innerHTML ="Steps:"+steps+"/35 未進行顏色改變,無效單擊!"; return; } var queue=[]; var front=0; var rear=0; queue[rear++]=0; while (front<rear) { var k=queue[front++]; blocks[k]=destColor; if (k%10!=9 && blocks[k+1]==srcColor) // 右邊的方格 queue[rear++]=k+1; if (k<90 && blocks[k+10]==srcColor) // 下邊的方格 queue[rear++]=k+10; } draw(); steps++; document.getElementById("mess").innerHTML ="Steps:"+steps+"/35"; if (checkWin()) { running=false; ctx.font = '50px PingFang SC'; ctx.fillStyle = "red"; ctx.textAlign = 'center'; ctx.baseline = 'middle'; ctx.fillText('You Win!',canvas.width/2, canvas.height/2); } else { if (steps==35) { running=false; ctx.font = '50px PingFang SC'; ctx.fillStyle = "black"; ctx.textAlign = 'center'; ctx.baseline = 'middle'; ctx.fillText('You failed!',canvas.width/2, canvas.height/2); } } } function checkWin() { for (var i=1;i<blocks.length;i++) if (blocks[i]!=blocks[0]) return false; return true; } newGame(); </script> </body> </html>