易码技术论坛

 找回密码
 加入易码
搜索
12
返回列表 发新帖
楼主: 空小子

[原创]AI游戏事例极限井字棋代码分析!

[复制链接]
发表于 2005-7-5 14:59:00 | 显示全部楼层
<form name="game">
  <center>
<input type="button" name="m0"><input type="button" name="m1"><input type="button" name="m2">
<input type="button" name="m3"><input type="button" name="m4"><input type="button" name="m5">
<input type="button" name="m6"><input type="button" name="m7"><input type="button" name="m8">

      

          <th width="76">&quot;O&quot; 赢 </th>
          <tdwidth="69"><input size="5" value="0" name="rO">
        
        
          <th width="76">&quot;X&quot; 赢 </th>
          <tdwidth="69"><input size="5" value="0" name="rX">
        
        
          <th width="76">平 </th>
          <tdwidth="69"><input size="5" value="0" name="rd">
        
      

  </center>
</form>
<script language="Javascript" type="text/javascript">
<!--
<!-- 此特效使用《心梦网页特效精灵》编辑制作-->
<!-- 心梦家园:http://xmhome.in70s.com-->
var i,c;
var turn=0;
var flag=0;
var map=new Array(9);
map[0]=document.forms.game.m0;
map[1]=document.forms.game.m1;
map[2]=document.forms.game.m2;
map[3]=document.forms.game.m3;
map[4]=document.forms.game.m4;
map[5]=document.forms.game.m5;
map[6]=document.forms.game.m6;
map[7]=document.forms.game.m7;
map[8]=document.forms.game.m8;
for(i=0;i<9;i++){
    map.onclick=play
}
function checkwin1(u,c){
    switch(Number(c)){
        case0:return(((u==map[1].value)&&(u==map[2].value))||((u==map[3].value)&&(u==map[6].value))||((u==map[4].value)&&(u==map[8].value)));
        case1:return(((u==map[0].value)&&(u==map[2].value))||((u==map[4].value)&&(u==map[7].value)));
        case2:return(((u==map[0].value)&&(u==map[1].value))||((u==map[4].value)&&(u==map[6].value))||((u==map[5].value)&&(u==map[8].value)));
        case3:return(((u==map[0].value)&&(u==map[6].value))||((u==map[4].value)&&(u==map[5].value)));
        case4:return(((u==map[0].value)&&(u==map[8].value))||((u==map[1].value)&&(u==map[7].value))||((u==map[2].value)&&(u==map[6].value))||((u==map[3].value)&&(u==map[5].value)));
        case5:return(((u==map[2].value)&&(u==map[8].value))||((u==map[3].value)&&(u==map[4].value)));
        case6:return(((u==map[0].value)&&(u==map[3].value))||((u==map[2].value)&&(u==map[4].value))||((u==map[7].value)&&(u==map[8].value)));
        case7:return(((u==map[1].value)&&(u==map[4].value))||((u==map[6].value)&&(u==map[8].value)));
        case8:return(((u==map[0].value)&&(u==map[4].value))||((u==map[2].value)&&(u==map[5].value))||((u==map[6].value)&&(u==map[7].value)));
    }
    return false;
}
function checkwin2(u,c){
switch(Number(c)){
  case0:return((u==map[1].value)||(u==map[2].value)||(u==map[3].value)||(u==map[4].value)||(u==map[6].value)||(u==map[8].value));
  case 1:return((u==map[0].value)||(u==map[2].value)||(u==map[4].value)||(u==map[7].value));
  case2:return((u==map[0].value)||(u==map[1].value)||(u==map[4].value)||(u==map[5].value)||(u==map[6].value)||(u==map[8].value));
  case 3:return((u==map[0].value)||(u==map[4].value)||(u==map[5].value)||(u==map[6].value));
  case4:return((u==map[0].value)||(u==map[1].value)||(u==map[2].value)||(u==map[3].value)||(u==map[5].value)||(u==map[6].value)||(u==map[7].value)||(u==map[8].value));
  case 5:return((u==map[2].value)||(u==map[3].value)||(u==map[4].value)||(u==map[8].value));
  case6:return((u==map[0].value)||(u==map[2].value)||(u==map[3].value)||(u==map[4].value)||(u==map[7].value)||(u==map[8].value));
  case 7:return((u==map[1].value)||(u==map[4].value)||(u==map[6].value)||(u==map[8].value));
  case8:return((u==map[0].value)||(u==map[2].value)||(u==map[4].value)||(u==map[5].value)||(u==map[6].value)||(u==map[7].value));
}
return false;
}
function reset(){
    turn=0;
    for(i=0;i<9;i++){
        map.value=' ';
        map.style.backgroundColor="#FFFFFF";
        map.style.borderColor="#000000";
        map.style.borderStyle="solid";
        map.style.borderWidth="1px";
        map.style.fontWeight="bold";
        map.style.width="24px";
        map.style.height="24px";
        map.hideFocus="hideFocus";
    }
    if(flag) ai();
    flag=!flag;
}
function play(){
    if(this.value!=' ')return false;
    this.value='O';
    this.blur();
    this.style.color="#0000FF";
    this.style.backgroundColor="#0080FF";
    checkwin('O',this.name.substr(1,1));
}
function ai(){
    var p=[0,0,0,0,0,0,0,0,0];
    for(c=0;c<9;c++){
        do{
            l=Math.round(Math.random()*100)%9;
            if(!p[l])p[l]=c;
        }while(p[l]!=c);
    }
    for(l=0;l<9;l++){if((map[p[l]].value=='')                      )c=p[l];}
    for(l=0;l<9;l++){if((map[p[l]].value==' ')&&(checkwin2('O',p[l])))c=p[l];}
    for(l=0;l<9;l++){if((map[p[l]].value==' ')&&(checkwin2('X',p[l])))c=p[l];}
    for(l=0;l<9;l++){if((map[p[l]].value==' ')&&(checkwin1('O',p[l])))c=p[l];}
    for(l=0;l<9;l++){if((map[p[l]].value==' ')&&(checkwin1('X',p[l])))c=p[l];}
    map[c].value='X';
    map[c].blur();
    map[c].style.color="#FF0000";
    map[c].style.backgroundColor="#FF8000";
    checkwin('X',c);
}
function checkwin(p,c){
    if(checkwin1(p,c)){
        alert('胜利者:'+arguments[0]);
        document.forms.game['r'+arguments[0]].value++;
        reset();
    }else{
        if(turn>=8){
            alert('平局');
            reset();
            document.forms.game.rd.value++;
        }else{
            turn++;
            if(p=='O')ai();
        }
    }
}
reset();
-->
</script>

 楼主| 发表于 2004-8-29 13:56:13 | 显示全部楼层 |阅读模式
    棋类大概都是这样的:电脑方面跟人一样,首先看有没有赢的机会,要是有的话其他什么都不用管了(废话,都赢了,还管什么)
没有赢,就考虑人方是否攻击,考虑最佳防守方式,要是这两种都不存在,那就可以随机了,当然随机也一定要合理
比如拿井字棋来说,最中间的位置是最好的位置,其次是边角,最后才考虑边缘,这些当然是最佳的,如果要将电脑智能降低就要采取
相应的改变,当然最低的智能就是全部随机,电脑方会按规矩落子就行了#¥%*¥%……—
    以下是实现代码:
/************************************************

程 序 名:极限井字棋
创 作 于:2004-8
修    改:
原    作:空小子
第二作者:
第三作者:
....
规    则:Copyleft(自由版权)
说    明:无
************************************************/
#include "main.h"
char box[10];
int x,y;              //棋子坐标
int vs_mode;          //对战,如:人机对战(player1 VS computer)
int piece_num;        //棋子数目,传统模式有9个,极限模式有6个
int player;           //当前下子的一方,如:ID_PLAYER1 表示玩家1
int AIOpPos;       //智能操作点

void set_xy(int key);
int set_menu();
int CheckKey();
int SeekAim(int AimID1_num, int AimID1,int AimID2,int SeekTimes);

void about();
void set();
void init();
void start();

void Player1();
void Player2();
void computer();

void main()
{
about();
set();
init();
start();
}

//关于
void about(void)
{
ClearScreen();

move12(3,2);
printf("编  写:空小子");
move12(4,2);
printf("规  则:自由版权");
move12(5,2);
printf("E-MAIL:kxz-kong@163.com");
UpdateLCD12(0xFFFF);

TextOut(20,8,"【极限井字棋】",1);

//画3D框
rectangle(1,1,155,75,1);
rectangle(3,3,153,73,1);
block(5, 75, 160, 80, 1);
block(155, 5, 160, 80, 1);

getchar();
}

//菜单
int set_menu(char *title,char *one, char *two)
{
ClearScreen();

gotoxy(0,0);
printf("%s",title);
gotoxy(5,1);
printf("%s",one);
gotoxy(5,3);
printf("%s",two);
move(10,10);//隐藏指针

UpdateLCD(0xFFFF);

CATCH_KEY:
switch(getchar())
{
  case 27 : JmpToNet();
  case 'b': return 1;
  case 'n': return 2;
}
goto CATCH_KEY;
}

//设置
void set()
{
vs_mode=set_menu("对战:","1.人机对战","2.人脑对战");

  //设置棋子数目
piece_num=(set_menu("模式:","1.极限模式","2.传统模式"))*3 + 3;

//设置优先级
if (vs_mode==MAN_VS_COMPUTER) player=set_menu("优先:"," 1.人先行 "," 2.电脑先 ");
else player=ID_PLAYER1;
}

//初始化
void init()
{
int i;

//数组初始化
for(i=1;i<10;i++) box=0;

ClearScreen();
move(10,10);//隐藏指针
//棋盘
rectangle(48,8,112,72,1);
rectangle(50,10,110,70,1);
rectangle(70,10,90,70,1);
rectangle(50,30,110,50,1);
//阴影
block(112,15,115,72,1);
block(55,72,115,75,1);

}

//....
int CheckKey(int key)
{
switch(key)
{
  case 27: return 27;
  case 98: return 1;
  case 110: return 2;
  case 109: return 3;
  case 103: return 4;
  case 104: return 5;
  case 106: return 6;
  case 116: return 7;
  case 121: return 8;
  case 117: return 9;
  default: return 0;
}
}

//设置棋子坐标
void set_xy(int key)
{
if (key==1||key==4||key==7) x=60;
if (key==2||key==5||key==8) x=80;
if (key==3||key==6||key==9) x=100;
if (key==1||key==2||key==3) y=60;
if (key==4||key==5||key==6) y=40;
if (key==7||key==8||key==9) y=20;
}

//检测目标
int SeekAim(int AimID1_num, int AimID1,int AimID2,int SeekTimes)
{
int i,Num,OpPos;

Num=AimID1_num;
AIOpPos=0;
for(i=1;i<10;i+=4)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 1;

Num=AimID1_num;
AIOpPos=0;
for(i=3;i<8;i+=2)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 2;

Num=AimID1_num;
AIOpPos=0;
for(i=1;i<4;i++)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 3;

Num=AimID1_num;
AIOpPos=0;
for(i=4;i<7;i++)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 4;

Num=AimID1_num;
AIOpPos=0;
for(i=7;i<10;i++)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 5;

Num=AimID1_num;
AIOpPos=0;
for(i=1;i<8;i+=3)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 6;

Num=AimID1_num;
AIOpPos=0;
for(i=2;i<9;i+=3)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 7;

Num=AimID1_num;
AIOpPos=0;
for(i=3;i<10;i+=3)
{
  if (box==AimID1) Num--;
  if (box==AimID2) AIOpPos=i;
}
if (0==Num && AIOpPos!=0) SeekTimes--;
if (0==SeekTimes) return 8;

return 0;
}


void start()
{
while(1)
{
  if (vs_mode==MAN_VS_COMPUTER)
  {
   if (player==ID_PLAYER1) Player1(); else computer();
  }
  else
  {
   Player1();
   Player2();
  }
}
}

void Player1()
{
char key,OldKey;
OldKey=0;
while(player==ID_PLAYER1)
{
  key=CheckKey(getchar());
  if (key==27) JmpToNet();
  set_xy(key);
  if (key!=OldKey && piece_num>0 && box[key]==ID_BLANK)
  {
   box[key]=ID_PLAYER1;
   piece_num--;
   DrawCircle(x,y,7,1);
   if (vs_mode==MAN_VS_COMPUTER) player=ID_COMPUTER; else player=ID_PLAYER2;
  }
  else if (piece_num==0 && box[key]==ID_PLAYER1)
  {
   OldKey=key;
   box[key]=ID_BLANK;
   piece_num++;
   DrawCircle(x,y,7,0);
   player=ID_PLAYER1;
  }
}

//胜利后的效果待如,可采用积分制
if (SeekAim(3,ID_PLAYER1,ID_PLAYER1,1))
{
  TextOut(20,8,"玩家1获胜!",1);
}
}


void Player2()
{
char key,OldKey;
OldKey=0;
while(player==ID_PLAYER2)
{
  key=CheckKey(getchar());
  if (key==27) JmpToNet();
  set_xy(key);
  if (key!=OldKey && piece_num>0 && box[key]==ID_BLANK)
  {
   box[key]=ID_PLAYER2;
   piece_num--;
   FillCircle(x,y,7,1);
   player=ID_PLAYER1;
  }
  else if (piece_num==0 && box[key]==ID_PLAYER2)
  {
   OldKey=key;
   box[key]=ID_BLANK;
   piece_num++;
   FillCircle(x,y,7,0);
   player=ID_PLAYER2;
  }
}

//胜利后的效果待如,可采用积分制
if (SeekAim(3,ID_PLAYER2,ID_PLAYER2,1))
{
  TextOut(20,8,"玩家2获胜!",1);
}
}

void computer()
{
int i,j,BakAIOpPos,UnHoldPos1,UnHoldPos2,Win;

//赢
Win=SeekAim(2,ID_COMPUTER,ID_BLANK,1);
if (Win)
{
  if (0==piece_num)
  for(i=1;i<10;i++)
  //直线中的子不许提
  if ((Win==1 && i!=1 && i!=5 && i!=9 && box==ID_COMPUTER) ||
      (Win==2 && i!=3 && i!=5 && i!=7 && box==ID_COMPUTER) ||
      (Win==3 && i!=1 && i!=2 && i!=3 && box==ID_COMPUTER) ||
      (Win==4 && i!=4 && i!=5 && i!=6 && box==ID_COMPUTER) ||
      (Win==5 && i!=7 && i!=8 && i!=9 && box==ID_COMPUTER) ||
      (Win==6 && i!=1 && i!=4 && i!=7 && box==ID_COMPUTER) ||
      (Win==7 && i!=2 && i!=5 && i!=8 && box==ID_COMPUTER) ||
      (Win==8 && i!=3 && i!=6 && i!=9 && box==ID_COMPUTER))
  {
   set_xy(i);
   FillCircle(x,y,7,0);
   break;
  }
  set_xy(AIOpPos);
  FillCircle(x,y,7,1);

  //胜利后的效果待如,可采用积分制
  TextOut(20,8,"电脑获胜!",1);
}

//禁止提子位置
if (0==piece_num)
{
  UnHoldPos1=0;
  UnHoldPos2=0;
  if (SeekAim(2,ID_PLAYER1,ID_COMPUTER,1)) UnHoldPos1=AIOpPos;
  if (SeekAim(2,ID_PLAYER1,ID_COMPUTER,2)) UnHoldPos2=AIOpPos;
}

//防
if (SeekAim(2,ID_PLAYER1,ID_BLANK,1))
{
  if (0==piece_num)
  for(i=1;i<10;i++)
  if (i!=UnHoldPos1 && i!=UnHoldPos2 && box==ID_COMPUTER)
  {
   box=ID_BLANK;
   set_xy(i);
   FillCircle(x,y,7,0);
   piece_num++;
   break;
  }
  box[AIOpPos]=ID_COMPUTER;
  set_xy(AIOpPos);
  FillCircle(x,y,7,1);
  player=ID_PLAYER1;
  piece_num--;
  return;
}

//中间优先
else if (box[5]==ID_BLANK)
{
  if (0==piece_num)
  for(i=1;i<10;i++)
  if (i!=UnHoldPos1 && i!=UnHoldPos2 && box==ID_COMPUTER)
  {
   box=ID_BLANK;
   set_xy(i);
   FillCircle(x,y,7,0);
   piece_num++;
   break;
  }
  box[5]=ID_COMPUTER;
  set_xy(5);
  FillCircle(x,y,7,1);
  player=ID_PLAYER1;
  piece_num--;
  return;
}

//边角次之,随机代码待加
for(j=1;j<10;j+=2)
if (box[j]==ID_BLANK)
{
  if (0==piece_num)
  for(i=1;i<10;i++)
  if (i!=UnHoldPos1 && i!=UnHoldPos2 && box==ID_COMPUTER)
  {
   box=ID_BLANK;
   set_xy(i);
   FillCircle(x,y,7,0);
   piece_num++;
   break;
  }
  box[j]=ID_COMPUTER;
  set_xy(j);
  FillCircle(x,y,7,1);
  player=ID_PLAYER1;
  piece_num--;
  return;
}

//边缘最后,随机代码待加
for(j=2;j<9;j+=2)
if (box[j]==ID_BLANK)
{
  if (0==piece_num)
  for(i=1;i<10;i++)
  if (i!=UnHoldPos1 && i!=UnHoldPos2 && box==ID_COMPUTER)
  {
   box=ID_BLANK;
   set_xy(i);
   FillCircle(x,y,7,0);
   piece_num++;
   break;
  }
  box[j]=ID_COMPUTER;
  set_xy(j);
  FillCircle(x,y,7,1);
  player=ID_PLAYER1;
  piece_num--;
  return;
}
}
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-3-28 20:39 , Processed in 0.010195 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表