网页功能: 加入收藏 设为首页 网站搜索  
浅谈电脑游戏中的人工智能制作
发表日期:2006-09-03作者:[转贴] 出处:  

  电脑游戏随着硬件执行效率与显示解析度等大幅提升,以往很多不可能或非常难以实现的电脑游戏如此都得以顺利完成。虽然电脑游戏的呈现是那么地多样化,然而却与我们今日所要探讨的主题,人工智能几乎都有着密不可分的关系。
  在角色扮演游戏中,程序员与企划人员需要精确地在电脑上将一个个所谓的“怪物”在战门过程中栩栩如生地制作出来;所以半兽人受了重伤懂得逃跑,法师懂得施展攻性法术。
  目前能让人立刻想到与人工智能有密切关系的游戏有两种:一是所谓的战棋/策略模拟游戏,二则是棋弈游戏。人工智能的比重与深浅度,在不同的游戏类型中各有不一。有的电脑游戏非标榜着高人工智能不可,不然没有人买;有的则是几乎渺茫到让玩家无法感觉有任何人工智能的存在。            

导向式思考

  AI最容易制作的的方式,同时也是早期游戏AI发展的主要方向就是规则导向或称之为假设导向。在一些比较简单的电脑游戏中,程序员可以好不困难地将游戏中的规则与设定转化成一条条的规则,然后将它们写成电脑程序。让我们以角色扮演游戏为例。决大多数的企画在设定所谓电脑怪物时,所设定的属性通常有以下几种:

  生命值 攻击力 防御力 法力  属性

  最后一个“属性”是我在设定时喜欢增加的项目之一。透过这项属性的设定,我可以把怪物设定成“贪生怕死的”,也可以把战士设定为“视死如归”。以目前我们所掌握的资料,在战门系统中的大纲如是诞生了:                          

规则一

if (生命值< 10) // 边临死亡了吗 
{  if (属性== 贪生怕死)               
   结果 = 试图逃跑               
  if (有任何恢复生命值的物品或法术可用)      
   结果 = 使用或施展相关物品或法术       
}

规则二
 
if (可施攻击性法术 && 有足够法力)
{                        
   结果 = 施展攻攻击性法术             
}                        

  由以上一连串的“如果--就--”规则设定,建立了最基本的AI。说这样的制方式只能建立基本AI其实并不当然正确。只要建立足够及精确的规则,这样的方式仍然有一定水准的表现。
 规则导向的最大优点就是易学易用。在没有深奥的理论概念的前提下,仍有广大的使用群。所以很多老道的玩家常常没两下就摸清楚敌人的攻击策略,移动方式等等。

 推论式思考

  相信曾经接触过电脑语言课程,或是自习过相关书籍的朋友们,都曾曾经听过一个著名的程序,那就是井字游戏。用井字游戏作为讨论AI的入门教材,我个人觉得是最适当的例子。或许有人还不知道井字游戏怎么玩。只要任何一方在三乘三的方格中先先成一线便胜利了。我们在前面谈过的规则导向,在这里也可以派得上用场。

 if任何一线已有我方两子&&另外一格仍空//我方即将成一线吗
  结果 = 该空格                     
 if任何一线已有敌方两子&&另外一格仍空//防止敌方作成一线 
  结果 = 该空格                     
 if任何一线已有我方一子&&另外两格仍空//作成两子    
  结果 = 该空格

  有一次我在某本电脑书上,同样地也看到某些以井字游戏为介绍的范例。不同的是,我几乎看不到任何规则导向的影子。但在仔细分析该程序码后,我得到了极大的启发,原来AI是可以不用这么多规则来制作的。它用的方法正是在电脑AI课程中重要的概念:极大极小法。我在这里只说明这法则的概念。继续以井字游戏为例,电脑先在某处下子,接着会以假设的方式,替对方下子,当然,必须假设对方下的是最佳位置,否则一切则毫无意义。在假设对方下子的过程中,自然又需要假设我方的下一步回应,如此一来一往,直到下完整局游戏为止。

底下是节录书中的程序片段:

bestMove(int p, int*v)
{
    int i;
    int lastTie;
    int lastMove;
    int subV;
    /*First, check for a tie*/
    if (isTie()) {
        *v=0;
        return(0);
    };
    /*If not a tie, try each potential move*/
    for (*v=-1, lastTie=lastMove=-1,i=0;i<9;i++)
  {
        /*If this isn't a possible, skip it*/
        if (board[i]!=0) continue;
        /* Make the move. */
        lastMove=i;
        board[i]=p;
        /* Did it win? */
        if (hasWon(p)) *v=1;
        else{
            /*If not, find out how good the other side can do*/
            bestMove(-p,&subV);
            /* If they can only lose, this is still a win.*/
            if (subV==-1) *v=1;
            /* Or, if it's a tie, remember it. */ 
            else if (subV==0){
                *v=0;
                lastTie=i; 
            };
        };
        /* Take back the move. */
        board[i]=0;
        /*If we found a win, return immediately (can't do any better than that)*/
        if (*v==1) return(i);
            /*If we didn't find any wins, return a tie move.*/
        if (*v==0) return(lastTie);
        /*If there weren't even any ties, return a loosing move.*/
        else return(lastMove);
};   

  国外的一些论坛曾举行过256字节的游戏设计比赛。作品非常多,其中有一件作品正巧也是井字游戏。作者用区区两百多行就写了与上述程序演算方式完全相同的作品,可见功力确实了的。另外,我也很希望类似的活动能在国内推展起来。对了,在这样的比赛条件限制下,除了汇编语言外,几乎没有其它的选择了。    

 

.386c
  code segment byte public use16
          assume cs:code, ds:code

          org 100h

  tictac proc far

  start:
          push cs
          pop ds
          mov ax,0B800h ; 清除屏幕
          mov es,ax ;
          xor di,di ;
          mov cx,7D0h ;
          mov ax,0F20h ;
          rep stosw ;
          xor cx,cx ;
          mov dl,5
  loc_1:
          call printBoard
  loc_2:
          mov ah,8 ; 等待按键
          int 21h

          movzx bx,al

          sub bl,31h ; 如果不是1..9
          jc loc_2 ; 则重新输入
          cmp bl,8
          ja loc_2
          cmp data_1[bx],al
          jne loc_2
          mov byte ptr data_1[bx],'x'
          dec dl
          jz short loc_3
          mov al,'o'
          call bestMove
          mov [si],al
          call isWin ; 判断是否已取得胜利
          jnc loc_1
  loc_3:
          call printBoard
          mov ax,4C00h
          int 21h
  
  data_1 db '12'
  data_2 db '3456789'
  data_3 db 0
  
  tictac endp
  
  
  printBoard proc near
          mov si,offset data_1
          mov di,548h
          mov cl,3
  
  locloop_4:
          movsb
          add di,5
          movsb
          add di,5
          movsb
          add di,133h
          loop locloop_4
  
          retn
  printBoard endp
  
  
  isWin proc near
          mov bx,1
          mov bp,3
          call sub_3 ; 检查横向是否完成
          inc bx
          inc bx
          dec bp
          dec bp
          call sub_3 ; 检查纵向是否完成
          call sub_4 ; 检查斜向是否完成
          clc
          retn
  isWin endp
  
  loc_5:
          stc
          retn
  
  sub_3 proc near
          mov ah,3
          mov si,offset data_1
  loc_6:
          mov di,si
          call sub_5
          add si,bp
          dec ah
          jnz loc_6
          retn
  sub_3 endp
 
  sub_4 proc near
          mov di,offset data_1
          inc bx
          call sub_5
          mov di,offset data_2
          dec bx
          dec bx
          call sub_5
          retn
  sub_4 endp
  
  
  sub_5 proc near
          mov cl,3
  
  locloop_7:
          cmp [di],al
          jne short loc_ret_8
          add di,bx
          loop locloop_7
  
          add sp,4
          jmp short loc_5
  
  loc_ret_8:
          retn
  sub_5 endp
      
  bestMove proc near
          mov bx,31FEh
          mov cl,9
          mov di,offset data_1
      
  locloop_9:
          cmp [di],bh ; #empty?
          jne short loc_12 ; #no, skip
          mov [di],al
          pusha
          call isWin ; #CY: Win
          popa ;
          jnc short loc_10 ;
          mov bl,1
          mov si,di
          mov [di],bh
          retn
  loc_10:
          pusha
          xor al,17h ; toggle 'o' / 'x'
          call bestMove
          mov data_3,bl
          popa
          mov ah,data_3
          neg ah
          cmp ah,bl
          jle short loc_11
          mov bl,ah
          mov si,di
  loc_11:
          mov [di],bh
  loc_12:
          inc bh
          inc di
          loop locloop_9
      
          cmp bl,0FEh
          jne short loc_ret_13
          xor bl,bl
      
  loc_ret_13:
          retn
  bestMove endp
  code ends

          end start

我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 浅谈电脑游戏中的人工智能制作
本类热点文章
  A*寻路算法(For 初学者)
  A*寻路初探 GameDev.net
  用有限状态机实现的迷宫求解
  计算机中随机数的产生
  精美的随机数生成器程序
  即时战略游戏中如何协调对象移动
  计算几何算法概览
  飞行射击游戏中的碰撞检测
  电脑AI浅谈
  五子棋算法探讨
  小谈网络游戏同步
  五子棋算法
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00432