台灣最大程式設計社群網站
線上人數
675
 
會員總數:245981
討論主題:189559
歡迎您免費加入會員
討論區列表 >> 專欄文章 >> 線上五子棋的語法
[]  
[我要回覆]
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
線上五子棋的語法
價值 : 0 QP  點閱數:497 回應數:0
樓主

站務人員 站長
門外漢
0 1580
542 9
發送站內信

捐贈 VP 給 站務人員
這是用javascript寫出來的五子棋程式...參考看看吧..

<HTML>

<HEAD>

<META content="text/html; charset=big5" http-equiv=Content-Type>

<SCRIPT language=JavaScript>

<!--

if (self.location!=top.location) top.location=''+self.location;



ie4=(navigator.appName.indexOf("Microsoft")!=-1 && parseInt(navigator.appVersion)>3)?true:false;

ie3=(navigator.appName.indexOf("Microsoft")!=-1 && parseInt(navigator.appVersion)<4)?true:false;



boardSize=15;

userSq= 1;

machSq=-1;

blinkSq="b-1";

blinkHint="b1";

myTurn=false;

winningMove=9999999;

openFour =8888888;

twoThrees =7777777;



if (document.images) {

uImg=new Image(); uImg.src='s'+userSq+'.gif';

mImg=new Image(); mImg.src='s'+machSq+'.gif';

uIm1=new Image(); uIm1.src='sb1.gif';

mIm1=new Image(); mIm1.src='sb-1.gif';

bImg=new Image(); bImg.src='s0.gif';

}



f=new Array();

s=new Array();

q=new Array();



iMax=new Array();

jMax=new Array();

nMax=0;



for (i=0;i<20;i++) {

f[i]=new Array();

s[i]=new Array();

q[i]=new Array();

for (j=0;j<20;j++) {

f[i][j]=0;

s[i][j]=0;

q[i][j]=0;

}

}



iLastUserMove=0;

jLastUserMove=0;



function clk(iMove,jMove) {

if (myTurn || autoplayOn) return;

hideHint();



if (f[iMove][jMove]!=0) {alert('這一格已經有棋子了!'); return; }

f[iMove][jMove]=userSq;

drawSquare(iMove,jMove,userSq);

myTurn=true;

iLastUserMove=iMove;

jLastUserMove=jMove;



dly=(document.images)?10:boardSize*30;



if (winningPos(iMove,jMove,userSq)==winningMove) setTimeout('gameOver=1;alert("恭喜你,你贏了!")',dly);

else setTimeout("machineMove(iLastUserMove,jLastUserMove);",dly);

}



function getBestMachMove() {

maxS=evaluatePos(s,userSq);

maxQ=evaluatePos(q,machSq);



// alert ('maxS='+maxS+', maxQ='+maxQ);



if (maxQ>=maxS) {

maxS=-1;

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

if (q[i][j]==maxQ) {

if (s[i][j]>maxS) {maxS=s[i][j]; nMax=0}

if (s[i][j]==maxS) {iMax[nMax]=i;jMax[nMax]=j;nMax++}

}

}

}

}

else {

maxQ=-1;

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

if (s[i][j]==maxS) {

if (q[i][j]>maxQ) {maxQ=q[i][j]; nMax=0}

if (q[i][j]==maxQ) {iMax[nMax]=i;jMax[nMax]=j;nMax++}

}

}

}

}

// alert('nMax='+nMax+'\niMax: '+iMax+'\njMax: '+jMax)



randomK=Math.floor(nMax*Math.random());

iMach=iMax[randomK];

jMach=jMax[randomK];

}



function getBestUserMove() {

maxQ=evaluatePos(q,machSq);

maxS=evaluatePos(s,userSq);



if (maxS==-1) {

center=Math.floor(boardSize/2);

s[center][center]=1

maxS=1;

}



if (maxS>=maxQ) {

maxQ=-1;

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

if (s[i][j]==maxS) {

if (q[i][j]>maxQ) {maxQ=q[i][j]; nMax=0}

if (q[i][j]==maxQ) {iMax[nMax]=i;jMax[nMax]=j;nMax++}

}

}

}

}

else {

maxS=-1;

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

if (q[i][j]==maxQ) {

if (s[i][j]>maxS) {maxS=s[i][j]; nMax=0}

if (s[i][j]==maxS) {iMax[nMax]=i;jMax[nMax]=j;nMax++}

}

}

}

}



// alert('nMax='+nMax+'\niMax: '+iMax+'\njMax: '+jMax)



randomK=Math.floor(nMax*Math.random());

iHint=iMax[randomK];

jHint=jMax[randomK];

}



function machineMove(iUser,jUser) {

getBestMachMove();

f[iMach][jMach]=machSq;

if (document.images) {

drawSquare(iMach,jMach,blinkSq);

setTimeout("drawSquare(iMach,jMach,machSq)",900);

}

else {

drawSquare(iMach,jMach,machSq);

}

if (winningPos(iMach,jMach,machSq)==winningMove) setTimeout('gameOver=1;alert("你已經輸了!");',900);

else if (drawPos) setTimeout('gameOver=1;alert("此局是平局!")',900);

else setTimeout("myTurn=false;",950);

}



function hasNeighbors(i,j) {

if (j>0 && f[i][j-1]!=0) return 1;

if (j+1<boardSize && f[i][j+1]!=0) return 1;

if (i>0) {

if (f[i-1][j]!=0) return 1;

if (j>0 && f[i-1][j-1]!=0) return 1;

if (j+1<boardSize && f[i-1][j+1]!=0) return 1;

}

if (i+1<boardSize) {

if (f[i+1][j]!=0) return 1;

if (j>0 && f[i+1][j-1]!=0) return 1;

if (j+1<boardSize && f[i+1][j+1]!=0) return 1;

}

return 0;

}



w=new Array(0,20,17,15.4,14,10);

nPos=new Array();

dirA=new Array();



function winningPos(i,j,mySq) {

test3=0;

test4=0;



L=1;

m=1; while (j+m<boardSize && f[i][j+m]==mySq) {L++; m++} m1=m;

m=1; while (j-m>=0 && f[i][j-m]==mySq) {L++; m++} m2=m;

if (L>4) { return winningMove; }

side1=(j+m1<boardSize && f[i][j+m1]==0);

side2=(j-m2>=0 && f[i][j-m2]==0);



if (L==4 && (side1 || side2)) test3++;

if (side1 && side2) {

if (L==4) test4=1;

if (L==3) test3++;

}



L=1;

m=1; while (i+m<boardSize && f[i+m][j]==mySq) {L++; m++} m1=m;

m=1; while (i-m>=0 && f[i-m][j]==mySq) {L++; m++} m2=m;

if (L>4) { return winningMove; }

side1=(i+m1<boardSize && f[i+m1][j]==0);

side2=(i-m2>=0 && f[i-m2][j]==0);

if (L==4 && (side1 || side2)) test3++;

if (side1 && side2) {

if (L==4) test4=1;

if (L==3) test3++;

}



L=1;

m=1; while (i+m<boardSize && j+m<boardSize && f[i+m][j+m]==mySq) {L++; m++} m1=m;

m=1; while (i-m>=0 && j-m>=0 && f[i-m][j-m]==mySq) {L++; m++} m2=m;

if (L>4) { return winningMove; }

side1=(i+m1<boardSize && j+m1<boardSize && f[i+m1][j+m1]==0);

side2=(i-m2>=0 && j-m2>=0 && f[i-m2][j-m2]==0);

if (L==4 && (side1 || side2)) test3++;

if (side1 && side2) {

if (L==4) test4=1;

if (L==3) test3++;

}



L=1;

m=1; while (i+m<boardSize && j-m>=0 && f[i+m][j-m]==mySq) {L++; m++} m1=m;

m=1; while (i-m>=0 && j+m<boardSize && f[i-m][j+m]==mySq) {L++; m++} m2=m;

if (L>4) { return winningMove; }

side1=(i+m1<boardSize && j-m1>=0 && f[i+m1][j-m1]==0);

side2=(i-m2>=0 && j+m2<boardSize && f[i-m2][j+m2]==0);

if (L==4 && (side1 || side2)) test3++;

if (side1 && side2) {

if (L==4) test4=1;

if (L==3) test3++;

}



if (test4) return openFour;

if (test3>=2) return twoThrees;

return -1;

}



function evaluatePos(a,mySq) {

maxA=-1;

drawPos=true;



for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {



// Compute "value" a[i][j] of the (i,j) move



if (f[i][j]!=0) {a[i][j]=-1; continue;}

if (hasNeighbors(i,j)==0) {a[i][j]=-1; continue;}



wp=winningPos(i,j,mySq);

if (wp>0) a[i][j]=wp;

else {

minM=i-4; if (minM<0) minM=0;

minN=j-4; if (minN<0) minN=0;

maxM=i+5; if (maxM>boardSize) maxM=boardSize;

maxN=j+5; if (maxN>boardSize) maxN=boardSize;



nPos[1]=1; A1=0;

m=1; while (j+m<maxN && f[i][j+m]!=-mySq) {nPos[1]++; A1+=w[m]*f[i][j+m]; m++}

if (j+m>=boardSize || f[i][j+m]==-mySq) A1-=(f[i][j+m-1]==mySq)?(w[5]*mySq):0;

m=1; while (j-m>=minN && f[i][j-m]!=-mySq) {nPos[1]++; A1+=w[m]*f[i][j-m]; m++}

if (j-m<0 || f[i][j-m]==-mySq) A1-=(f[i][j-m+1]==mySq)?(w[5]*mySq):0;

if (nPos[1]>4) drawPos=false;



nPos[2]=1; A2=0;

m=1; while (i+m<maxM && f[i+m][j]!=-mySq) {nPos[2]++; A2+=w[m]*f[i+m][j]; m++}

if (i+m>=boardSize || f[i+m][j]==-mySq) A2-=(f[i+m-1][j]==mySq)?(w[5]*mySq):0;

m=1; while (i-m>=minM && f[i-m][j]!=-mySq) {nPos[2]++; A2+=w[m]*f[i-m][j]; m++}

if (i-m<0 || f[i-m][j]==-mySq) A2-=(f[i-m+1][j]==mySq)?(w[5]*mySq):0;

if (nPos[2]>4) drawPos=false;



nPos[3]=1; A3=0;

m=1; while (i+m<maxM && j+m<maxN && f[i+m][j+m]!=-mySq) {nPos[3]++; A3+=w[m]*f[i+m][j+m]; m++}

if (i+m>=boardSize || j+m>=boardSize || f[i+m][j+m]==-mySq) A3-=(f[i+m-1][j+m-1]==mySq)?(w[5]*mySq):0;

m=1; while (i-m>=minM && j-m>=minN && f[i-m][j-m]!=-mySq) {nPos[3]++; A3+=w[m]*f[i-m][j-m]; m++}

if (i-m<0 || j-m<0 || f[i-m][j-m]==-mySq) A3-=(f[i-m+1][j-m+1]==mySq)?(w[5]*mySq):0;

if (nPos[3]>4) drawPos=false;



nPos[4]=1; A4=0;

m=1; while (i+m<maxM && j-m>=minN && f[i+m][j-m]!=-mySq) {nPos[4]++; A4+=w[m]*f[i+m][j-m]; m++;}

if (i+m>=boardSize || j-m<0 || f[i+m][j-m]==-mySq) A4-=(f[i+m-1][j-m+1]==mySq)?(w[5]*mySq):0;

m=1; while (i-m>=minM && j+m<maxN && f[i-m][j+m]!=-mySq) {nPos[4]++; A4+=w[m]*f[i-m][j+m]; m++;}

if (i-m<0 || j+m>=boardSize || f[i-m][j+m]==-mySq) A4-=(f[i-m+1][j+m-1]==mySq)?(w[5]*mySq):0;

if (nPos[4]>4) drawPos=false;



dirA[1] = (nPos[1]>4) ? A1*A1 : 0;

dirA[2] = (nPos[2]>4) ? A2*A2 : 0;

dirA[3] = (nPos[3]>4) ? A3*A3 : 0;

dirA[4] = (nPos[4]>4) ? A4*A4 : 0;



A1=0; A2=0;

for (k=1;k<5;k++) {

if (dirA[k]>=A1) {A2=A1; A1=dirA[k]}

}

a[i][j]=A1+A2;

}

if (a[i][j]>maxA) {

maxA=a[i][j];

}

}

}

return maxA;

}



function drawSquare(par1,par2,par3) {

if (document.images) {

eval('self.f1.document.s'+par1+'_'+par2+'.src="s'+par3+'.gif"');

}

else setTimeout("writeBoard()",50);

}



hintShown=false;

iHint=jHint=6;



function showHint () {

if (myTurn && autoplayOn) return;

if (hintShown) {hideHint();return;}

hintShown=1;

getBestUserMove();



if (document.images) {

drawSquare(iHint,jHint,blinkHint);

}

}



function hideHint() {

hintShown=0;

drawSquare(iHint,jHint,f[iHint][jHint]);

}



function autoplay() {

if (autoplayOn) {

if (myTurn) {

getBestMachMove();

f[iMach][jMach]=machSq;

drawSquare(iMach,jMach,blinkSq);

timerDR=setTimeout("drawSquare(iMach,jMach,machSq);",900);

if (winningPos(iMach,jMach,machSq)==winningMove) setTimeout('gameOver=1;alert("白棋獲勝!黑棋負!")',900);

else if (drawPos) setTimeout('alert("此局是平局!")',900);

else { myTurn=false; timerAP=setTimeout("autoplay()",950); }

}

else {

getBestUserMove();

f[iHint][jHint]=userSq;

drawSquare(iHint,jHint,blinkHint);

timerDR=setTimeout("drawSquare(iHint,jHint,userSq)",900);

if (winningPos(iHint,jHint,userSq)==winningMove) setTimeout('gameOver=1;alert("黑棋獲勝!白棋負!")',900);

else { myTurn=true; timerAP=setTimeout("autoplay()",950); }

}

}

}



autoplayOn=0;

timerAP=0;

function setAutoplay() {

if (gameOver) resetGame();

if (autoplayOn) {

if (myTurn) { setTimeout("setAutoplay()",950); return; }

autoplayOn=0;clearTimeout(timerAP);return;

}

if (document.images) setTimeout("hideHint();autoplayOn=1;autoplay();",100);

else alert('Sorry, Autoplay Mode is not supported for your browser!');

}



buf='';



function writeBoard () {

if (parseInt(navigator.appVersion)>3) docID=top.f1.document.open("text/html","replace");

buf+='<html><head><title>五子棋</title>';

if (navigator.appName=="Netscape") buf+='<base href="'+top.document.location+'">';

buf+='</head><body leftmargin=0 topmargin=0><a name="s"></a><center><pre';

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

buf+='\n><a href="#s" onClick="top.clk('+i+','+j+');if(top.ie4)this.blur();return false;" >
<img name="s'+i+'_'+j+'" src="s'+f[i][j]+'.gif" width=21 height=21 border=0></a';

}

buf+='\n><br';

if (buf.length>10000) {top.f1.document.writeln(buf); buf='';}

}

buf+='\n></pre></center></body></html>';

top.f1.document.writeln(buf);

top.f1.document.close();

buf='';

}



function resetGame() {

if (autoplayOn) {autoplayOn=0;clearTimeout(timerAP);clearTimeout(timerDR);}

drawPos=0;

myTurn=0;

autoplayOn=0;

gameOver=0;



for (i=0;i<20;i++) {

for (j=0;j<20;j++) {

f[i][j]=0;

}

}



if (!top.f1.document) return;

if (document.images) {

if (!top.f1.document.s9_9) return;

for (i=0;i<boardSize;i++) {

for (j=0;j<boardSize;j++) {

eval('self.f1.document.s'+i+'_'+j+'.src=bImg.src');

}

}

}

else writeBoard();

}



function init() {

if (autoplayOn) {autoplayOn=0;clearTimeout(timerAP);clearTimeout(timerDR);}

writeBoard();

resetGame();

}



//-->



</SCRIPT>

<title>五子棋</title></HEAD>

<body leftmargin="0" topmargin="0">

<table width="420" border="0" cellspacing="1" cellpadding="0" bgcolor="#000000" align="center">

<tr>

<td>
<iframe src=button.htm width=420 height=40 marginwidth=0 marginheight=0
hspace=0 vspace=0 frameborder=0 scrolling=NO name=fb></iframe>

</td>

</tr>

<tr>

<td>
<iframe src=main.htm width=420 height=420 marginwidth=0 marginheight=0
hspace=0 vspace=0 frameborder=0 scrolling=NO name=f1></iframe>

</td>

</tr>

</table>

</HTML>



39 回應者: 小桶子 日期: 2002/6/4 上午 01:16:41

上面那個程式的AI很高喔...

存成.htm就可以使用了...參考看看吧

40 回應者: song 日期: 2002/6/4 上午 01:27:54

<td><iframe src=button.htm width=420 height=40 marginwidth=0 marginheight=0 <td>
<iframe src=main.htm width=420 height=420 marginwidth=0 marginheight=0



用了兩個iframe ,安裝方式是否少了什麼?



song..

41 回應者: 小桶子 日期: 2002/6/4 上午 01:39:24

button.htm原如檔如下:

<HTML>

<HEAD>

<META content="text/html; charset=big5" http-equiv=Content-Type>

<SCRIPT language=JavaScript>

<!--

newSize=0;

function init() {}

function resetGame() {window.location="main.htm"}



//-->

</SCRIPT>

<META content="MSHTML 5.00.3315.2870" name=GENERATOR>

<link rel="stylesheet" href="style.css" type="text/css">

<title>五子棋</title></HEAD>

<BODY bgProperties=fixed oncontextmenu=window.event.returnValue=false

ondragstart=window.event.returnValue=false

onselectstart=event.returnValue=false leftmargin="0" topmargin="0">

<CENTER>

</CENTER>

<TABLE border=0 align="center" cellpadding="0" cellspacing="0" width="420" height="40">

<TR>

<TD align="center" bgcolor="#FFBE39" width="420" height="20">歡 樂 五 子 棋</TD>

</TR>

<FORM name=form1>

<TR >

<TD align="center" bgcolor="#FFBE39" width="420" height="20" Style="border-TOP: 1 solid #000000">

<input type="button" onclick=top.boardSize=parseInt(20);top.init() name="Button" value="點擊開始" class="bt">

<INPUT name=newgame onclick="setTimeout('top.resetGame()',100)" type=button value=重新開始 class="bt">

<INPUT name=autoplay onclick=top.setAutoplay() type=button value=遊戲演示 class="bt">

</TD>

</TR>



</FORM>

</TABLE>

</BODY>

</HTML>



main.htm檔案如下

<html>

<head>

<title>Untitled Document</title>

<meta http-equiv="Content-Type" content="text/html; charset=big5">

</head>



<body bgcolor="#FFFFFF" text="#000000" leftmargin="0" topmargin="0">

<table width="420" border="0" cellspacing="0" cellpadding="0" height="420" background="sb-1.gif">

<tr>

<td align="center"> </td>

</tr>

</table>

</body>

</html>



上面的sb-1.gif圖檔我放在這裡...........自己去載吧..

http://home.kimo.com.tw/sunkiss789/sb-1.gif

http://home.kimo.com.tw/sunkiss789/sb1.gif

http://home.kimo.com.tw/sunkiss789/s0.gif

如有遺失在告知



==============================================================================

回應者: 龍 alvin_lau@yahoo.com



根據五子棋的玩法,可以歸納出電腦可以作出以下兩種行為:



1. 比快 - 不理會玩家下什麼棋,專心地以最快的速度完成一行連續五隻棋子



2. 封殺 - 攔截玩家所下的棋,使玩家不能順利地完成一行五隻棋子



比快和封殺可以是兩個獨立的函式(Sub or Function),因為兩者的運作沒有關連。

何時用比快,何時用封殺呢?那就要用 AI (人工智能) 去判斷了。



AI 方面至少要有三重思考,但事先要作一些準備工作

首先我們要找出玩家下一步棋的可能性,方法就是以玩家下的棋子為中心,找出這棋子外圍的八隻棋子的位置,如下圖:

○○○

○●○

○○○



圖內黑色的圓點●就是玩家下的棋,白色的圓點○就是電腦找出來玩家下一步極有可能下棋的位置。

現在假設玩家已下了三步棋,電腦已下了二步:



  ●

 ● ●

◎ ◎



那麼電腦分析出來的結果就是:

 56789

5 ○○○

6○○●○○

7○●○●○

8◎○◎○○



上圖已附加了座標,黑點●是玩家下的棋,白點○是電腦分析出來玩家下一步可能下棋的位置,雙圓點◎是電腦已下棋的位置。


有了上圖,電腦可以跑 AI 了。到了這裡是不是覺得圖內的白點太多呢?我們可以用 AI 將最大可能的白點找出來:


第一重思考 - 連環

首先找出其中一個黑點,然後以它為中心向外圍的八個位置找出任何其他的黑點,然後就固定這個方向(連環兩個黑點就能定出方向),向前和向後尋找最先遇到的白點,這樣就能找出連環一行頭尾兩端的白點,就是玩家最有可能下的位置。重覆這個動直至所有黑點所有方向都被檢查過了,再將找出來的那些位置檢查,將有重覆的部份移除(重覆的我們只需要一個而已)。根據上圖,我們找出了三點,分別是: 6,5 9,8 8,5


第二重思考 - 間斷

我們要找出玩家最有可能下棋的非連環點(間斷點),這次要反向思考,將焦點放於白點之上。檢查每一個白點的外圍八個位置,找出被兩個或更多黑點包圍的白點。根據上圖,我們找出了三點,分別是: 6,6 8,6 7,7


第三重思考 - 危機偵測(hazard detection)

在五子棋中,所謂的危機就是當玩家有連續三隻或以上的棋子出現在同一行的時候,這時若電腦不加以攔截的話,那下一步棋玩家就贏定了。要令電腦有預知能力,就要使它懂得作假設,假設就即是代入法,我們在第一重思考和第二重思考中共找出了六點,電腦現在就要以玩家的身份在這六點內代入黑點,檢查是否有危機存在。如果出現危機,那電腦就應該以封殺的方式行動,相反如果沒有危機出現,那就代表玩家下的棋對電腦沒有威脅,電腦就可以安心以比快的方式行動了。


以上的只是初步的分析,能不能寫成程式就看自己了。以上的三重思考可以順序地連續執行數次(用迴圈或遞迴可自行決定),這樣得出來的結果會更準確。不過,這只是基本思考,還有更多下棋的策略(strategies)要自行開發了,我對這遊戲的認識不太深....^^

本篇文章發表於2002-06-04 00:00
目前尚無任何回覆
   

回覆
如要回應,請先登入.