走井是個古老的親子游戲,在電子游戲,電腦,手機(jī)沒有普及時間相信很多孩子都跟大人玩過這個游戲,沙地上找4個石子畫個框就能走起。不過為了讓電子時代的小鮮肉們也能知道后面在說什么,下面我們介紹一下走井游戲。
走井規(guī)則
走井的有兩名玩家,每個玩家有兩粒棋子,兩名玩家交替走子,當(dāng)一名玩家移動完自己的子之后,對方無子可動即獲得勝利?。

翻譯成計算機(jī)語言
按照上圖0,1,2,3,4這5個位置,列出每個位置的可移動狀態(tài),如下表
| 位置\可移動位置 | 0 | 1 | 2 | 3 | 4 | 十進(jìn)制 | 十六進(jìn)制 |
|---|---|---|---|---|---|---|---|
| 0 | NA | 1 | 1 | 1 | 1 | 31 | 0x1F |
| 1 | 1 | NA | 1 | 0 | 0 | 5 | 0x5 |
| 2 | 1 | 1 | NA | 1 | 0 | 11 | 0xB |
| 3 | 1 | 0 | 1 | NA | 1 | 21 | 0x15 |
| 4 | 1 | 0 | 0 | 1 | NA | 9 | 0x9 |
該表格查看方式類似于公交梯型票價圖,如按行查看,位置1可以的移動的目標(biāo)位置為
0,2,按位組合后為000101即十進(jìn)制數(shù)字5,十六進(jìn)制為0x5。其它的位置如查表即可得到。
將棋盤上唯的空位按照其所處的位置表示成一個5bit的數(shù)字,1的位置(可移動的目標(biāo)位置或者說是空著的位置)在5bit中來回移動。如開局時空為位于0,該值為00001--(hex)-->0x1。
SVG
一種矢量圖元描述格式,常用于作圖形軟件的數(shù)據(jù)交換。具體參見教程(內(nèi)網(wǎng))。
svg導(dǎo)學(xué)(互聯(lián)網(wǎng))
一個基本的svg結(jié)構(gòu)如下所示:
<html>
<body>
<h1>My first SVG</h1>
<svg width="100%" height="100%">
<!---->
<path d="M32 32 l128 0 l0 128 l-128 0 l128,-128" fill="none" stroke="black"></path>
<line x1="32" y1="32" x2="160" y2="160" stroke="black" />
<circle cx="96" cy="96" r="20" class="invisible" id='p0' />
<circle cx="32" cy="32" r="20" class="gray" id='p1' />
<circle cx="160" cy="32" r="20" class="black" id='p2' />
<circle cx="160" cy="160" r="20" class="black" id='p3' />
<circle cx="32" cy="160" r="20" class="gray" id='p4' />
<rect id="turnSide" x="200" y="16" width="64" height="32" class="black"></rect>
</svg>
</body>
</html>
CSS 樣式
我們可以通過css模式直接控制svg元素的顯示屬性。
.black {
fill: black
}
.gray {
fill: gray
}
.invisible {
display: none
}
我們定義黑色(black)、灰色(gray)、和不可見(invisible)三個顯示。
DOM事件
由于svg節(jié)點(diǎn)也是DOM節(jié)點(diǎn),DOM事件也是可用的,我們通過向節(jié)點(diǎn)增加click事件,來處理按鍵點(diǎn)擊。
function init() {
elements = document.querySelectorAll('circle');
for (var ele of elements) {
console.log(ele);
ele.addEventListener('click', pawnclick);
}
}
通過選擇器,選擇所有的
circle標(biāo)簽,為它們增加點(diǎn)擊事件。
將邏輯連接起來
有了每個位置的可移動位置及當(dāng)前棋盤上的空位,我們可以通過位運(yùn)算得出點(diǎn)中子是否可移動,以及其移動的去向。如果子可動則把目標(biāo)位置置為當(dāng)前點(diǎn)擊位置的顏色(css class),點(diǎn)擊位置置為空(.invisible),并進(jìn)入下一手next()。下面是pawnclick()的實(shí)現(xiàn)。
function pawnclick() {
if (this.className.baseVal != current_player[round % 2]) {
console.log('not your turn');
return;
}
console.log(`click me ${this.id}`);
//獲取可移動位置
var moveDest = moveCandiate[this.id] & blankPos;
if (moveDest != 0) {
console.log(`move dest ${moveDest} boardPost ${mask2pos[moveDest]}`);
blankPos = pos2mask[this.id];//將空位置為當(dāng)前子的位置
//如果可以移動,則移動該子,并取消事件監(jiān)聽,進(jìn)入下一輪
//獲取目標(biāo)位置
var destPos = document.getElementById(mask2pos[moveDest]);
destPos.className.baseVal = this.className.baseVal;
this.className.baseVal = "invisible";
nextTurn();//換手
}
else//沒有氣不可移動
{
console.log(`${this.id} 不可動`);
}
}
為了方便快速查找
翻譯成計算機(jī)語言中的表格,我們定義了moveCandiate,mask2pos,pos2mask三個查找表。
var moveCandiate = {
'p0': 0x1F,
'p1': 0x5,
'p2': 0xB,
'p3': 0x15,
'p4': 0x9
};
// 移動目標(biāo)位轉(zhuǎn)棋盤位置
var mask2pos = {
1: 'p0',
2: 'p1',
4: 'p2',
8: 'p3',
16: 'p4'
}
var pos2mask = {
'p0': 1,
'p1': 2,
'p2': 4,
'p3': 8,
'p4': 16
}
勝負(fù)判定
換手后++round,我們需要判斷當(dāng)前方是否還有子可動,如果無子可動則游戲結(jié)束。
function nextTurn()
{
++round;
var class_selector = current_player[round % 2];//根據(jù)手?jǐn)?shù)確定是哪邊
document.getElementById('turnSide').className.baseVal = class_selector;
var pawns = document.getElementsByClassName(class_selector);
var hasMove = 0;
for( var pawn of pawns)
{
hasMove |= (moveCandiate[pawn.id] & blankPos);
}
if(!hasMove)
{
console.log(`${class_selector} loose!`);
}
console.log(pawns);
}
在
nextTurn()中還增加表示當(dāng)前移動方的指示方格document.getElementById('turnSide').className.baseVal = class_selector,對應(yīng)svg部分的<rect id="turnSide" x="200" y="16" width="64" height="32" class="black"></rect>。