??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品久久波多野结衣,亚洲国产成人久久一区久久,久久精品国产一区二区http://www.shnenglu.com/woaidongmao/category/9130.html文章均收录自他h博客Q但不喜标题前加-[转脓(chung)]Q因其丑陋,见谅Q~zh-cnFri, 26 Dec 2008 00:32:26 GMTFri, 26 Dec 2008 00:32:26 GMT60Ragel 状态机?/title><link>http://www.shnenglu.com/woaidongmao/archive/2008/12/24/70245.html</link><dc:creator>肥仔</dc:creator><author>肥仔</author><pubDate>Wed, 24 Dec 2008 07:18:00 GMT</pubDate><guid>http://www.shnenglu.com/woaidongmao/archive/2008/12/24/70245.html</guid><wfw:comment>http://www.shnenglu.com/woaidongmao/comments/70245.html</wfw:comment><comments>http://www.shnenglu.com/woaidongmao/archive/2008/12/24/70245.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/woaidongmao/comments/commentRss/70245.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/woaidongmao/services/trackbacks/70245.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin-bottom: 12pt"><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">从今天开始我把我前一D|间用到的状态机工具<span lang="EN-US">Ragel</span>的用方法做一些ȝ<span lang="EN-US">,</span>希望大家斧正<span lang="EN-US">!<br><br><br>(</span>如果大家对状态机概念有模p的?span lang="EN-US">,</span>请参?span lang="EN-US"><<</span>~译原理<span lang="EN-US">>></span>一?span lang="EN-US">,</span>基本上有详尽的介l?span lang="EN-US">)<br><br></span>好闲a叙<span lang="EN-US">,</span>a归正?span lang="EN-US"><br><br>Ragel</span>可以从正规表辑ּ生成可执行有限状态机<span lang="EN-US">,</span>它可以生?span lang="EN-US">C,C++,Object-C,D,Java</span>?span lang="EN-US">Ruby</span>可执行代?span lang="EN-US"><br><br></span>官方|站<span lang="EN-US">:<a target="_blank"><span style="color: windowtext">http://www.cs.queensu.ca/home/thurston/ragel/</span></a><br><br></span>W一?span lang="EN-US"><br><br>Ragel</span>是一个可以生成协议处理代码的工具<span lang="EN-US">.</span> <span lang="EN-US"><br><br></span>先D个例子,单单的几行代?span lang="EN-US">,</span>实现的功能ؓ一个数字字W串转换成整敎ͼ<span lang="EN-US"><?xml:namespace prefix = o /><o:p></o:p></span></span></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: right" align="right"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma"><a ><span style="mso-bidi-font-family: arial">[Copy to clipboard]</span></a> <a ><span style="mso-bidi-font-family: arial">[ <span id="code0_symbol">-</span> ]</span></a><o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: left" align="left"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma">CODE:<o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #fdfff2"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">int atoi( char *str )<br>{<br>char *p = str;<br>int cs, val = 0;<br>bool neg = false;<br><br>%%{       //Ragel </span><span style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">的关键字<span lang="EN-US">,</span>用于声明状态机代码D늚开?span lang="EN-US"><br>  action see_neg {<br>   neg = true;<br>  }<br><br>  action add_digit {<br>   val = val * 10 + (fc - '0');<br>  }<br><br>  main :=<br>   ( '-'@see_neg | '+' )? ( digit @add_digit )+<br>   '\n' @{ fbreak; };<br><br>  # Initialize and execute.<br>  write init;                                  //</span>状态机关键?span lang="EN-US">,</span>q个会再接下来的内容中介l?span lang="EN-US"><br>  write exec noend;                     //</span>同上<span lang="EN-US"><br>}%%                                        //</span>状态机代码D늻束标?span lang="EN-US"><br><br>if ( neg )<br>  val = -1 * val;<br><br>if ( cs < atoi_first_final )<br>  cerr << "atoi: there was an error" << endl;<br><br>return val;<br>};<o:p></o:p></span></span></p> <p class="MsoNormal" style="margin-bottom: 12pt"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma"><br></span><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">?span lang="EN-US">c</span>里面?span lang="EN-US">500</span>多行实现?span lang="EN-US">atoi</span>函数更加高效<span lang="EN-US"><br><br></span>上面q段代码Q生成的<span lang="EN-US">C</span>语言代码如下<span lang="EN-US">:<o:p></o:p></span></span></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: right" align="right"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma"><a ><span style="mso-bidi-font-family: arial">[Copy to clipboard]</span></a> <a ><span style="mso-bidi-font-family: arial">[ <span id="code1_symbol">-</span> ]</span></a><o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: left" align="left"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma">CODE:<o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #fdfff2"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">int atoi( char *str )<br>{<br>char *p = str;<br>int cs, val = 0;<br>bool neg = false;<br><br>#line 27 "atoi.c"<br>{<br>cs = atoi_start;<br>}<br><br>#line 31 "atoi.c"<br>{<br>switch ( cs )<br>{<br>case 1:<br>switch( (*p) ) {<br>  case 43: goto st2;<br>  case 45: goto tr2;<br>}<br>if ( 48 <= (*p) && (*p) <= 57 )<br>  goto tr3;<br>goto st0;<br>st0:<br>goto _out0;<br>tr2:<br>#line 23 "atoi.rl"<br>{<br>   neg = true;<br>  }<br>goto st2;<br>st2:<br>p += 1;<br>case 2:<br>#line 52 "atoi.c"<br>if ( 48 <= (*p) && (*p) <= 57 )<br>  goto tr3;<br>goto st0;<br>tr3:<br>#line 27 "atoi.rl"<br>{<br>   val = val * 10 + ((*p) - '0');<br>  }<br>goto st3;<br>st3:<br>p += 1;<br>case 3:<br>#line 63 "atoi.c"<br>if ( (*p) == 10 )<br>  goto tr4;<br>if ( 48 <= (*p) && (*p) <= 57 )<br>  goto tr3;<br>goto st0;<br>tr4:<br>#line 33 "atoi.rl"<br>{ goto _out4; }<br>goto st4;<br>st4:<br>p += 1;<br>case 4:<br>#line 74 "atoi.c"<br>goto st0;<br>}<br>_out0: cs = 0; goto _out;<br>_out4: cs = 4; goto _out;<br><br>_out: {}<br>}<br>#line 38 "atoi.rl"<br><br><br>if ( neg )<br>  val = -1 * val;<br><br>if ( cs < atoi_first_final )<br>  cerr << "atoi: there was an error" << endl;<br><br>return val;<br>};<o:p></o:p></span></p> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma"><br></span><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">对应的状态图如下图所C?span lang="EN-US">:<span style="color: #333333"><br><br><a href="http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/Ragel_D708/clip_image001_2.gif"><img onmousewheel="return imgzoom(this);" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="108" alt="clip_image001" src="http://www.shnenglu.com/images/cppblog_com/woaidongmao/WindowsLiveWriter/Ragel_D708/clip_image001_thumb.gif" width="606" border="0" v:shapes="_x0000_i1025"></a><o:p></o:p></span></span></span></p> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma"><o:p> </o:p></span></p> <table class="MsoNormalTable" style="background: white; width: 100%; border-collapse: collapse; mso-padding-alt: 3.0pt 3.0pt 3.0pt 3.0pt" cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes"> <td style="border-right: medium none; padding-right: 7.5pt; border-top: #bbe9ff 1pt solid; padding-left: 7.5pt; padding-bottom: 1.5pt; border-left: medium none; padding-top: 7.5pt; border-bottom: medium none; mso-border-top-alt: solid #bbe9ff .75pt" valign="top"> <p class="MsoNormal" style="margin-bottom: 12pt"><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">正则表达式广泛应用于解析器中。它们通常被用来作?span lang="EN-US">?/span>黑盒<span lang="EN-US">?/span>与程序逻辑联系在一赗对正则表达式引擎在执行某些解析工作之后Q调用用戯定义行ؓ。加入新的自定义行ؓQ需要重新定义原来的格局Q然后粘贴到E序逻辑中。自定义行ؓ多Q正规表辑ּ的优势越?span lang="EN-US"><br><br>Ragel</span>是一个可以根据用户定义的正则表达式或是由正则表达式生成的状态图来生成健壮的Q无依赖的可执行代码Q包?span lang="EN-US">C</span>Q?span lang="EN-US">C++</span>Q?span lang="EN-US">Object-C, Java, Ruby </span>{等<span lang="EN-US">. </span>可以灉|控制已经生成状态机的变动,利用已经嵌入自定义行为的模式重构扫描?span lang="EN-US"><br><br>Ragel</span>ZM正规语言能被转化为有限状态自动机的原?span lang="EN-US"><br><br></span>基本的用步骤如?span lang="EN-US">:<br><br></span>首先<span lang="EN-US">,</span>Ҏ(gu)你的业务程逻辑与需?span lang="EN-US">,</span>按照<span lang="EN-US">ragel</span>提供的语法与关键字编?span lang="EN-US">.rl</span>文g<span lang="EN-US"><br><br>1</span>Q?span lang="EN-US">        </span>~写<span lang="EN-US">.rl</span>文g<span lang="EN-US">, </span>如下所C:<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: right" align="right"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma"><a ><span style="mso-bidi-font-family: arial">[Copy to clipboard]</span></a> <a ><span style="mso-bidi-font-family: arial">[ <span id="code0_symbol">-</span> ]</span></a><o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: left" align="left"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma">CODE:<o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #fdfff2"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">/*<br>* to parse a string started with “table?or “div?br>*/<br><br>#include <stdlib.h><br>#include <string.h><br>#include <stdio.h><br><br>%%{<br>                #</span><span style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">状态机的名?span lang="EN-US">(</span>必须有一个名字而且必须W合命名规则<span lang="EN-US">,</span>和变通的变量声明一?span lang="EN-US">)<br>        machine par_str;<br>        write data;<br>}%%<br>//</span>函数声明<span lang="EN-US">,</span>用于在用戯定义行ؓ中调?span lang="EN-US">,</span>用到了参数的传?span lang="EN-US">,</span>此函C可以是类成员函数<span lang="EN-US"><br>void printtable(int len)<br>{<br>   printf("there is a table,length is:%d\n",len);<br>}<br><br>//</span>另外一个函?span lang="EN-US">,</span>功能同上<span lang="EN-US">,</span>只是参数传递用的是引用传?span lang="EN-US"><br>void printdiv(char *p)<br>{<br>  printf("%s\n",(*p));<br>}<br>//</span>d理函?span lang="EN-US"><br>void par_str( char *str,int len )<br>{<br>        char *p = str, *pe = str + strlen( str );<br>        int cs;        //</span>状态机关键?span lang="EN-US">,</span>用于说明当明状?span lang="EN-US">,</span>以整型值标?span lang="EN-US">(current status</span>的羃?span lang="EN-US">)<br>                //</span>状态机自定义行为块<span lang="EN-US"><br>        %%{<br>                        #</span>调用自定义函?span lang="EN-US"><br>                        action see_table {<br>                                 printtable(len);<br>                }<br>               #invoke prindiv function to show the table information, as same as above<br>               action see_div { <br>                                  printdiv(p);<br>               }<br>               #</span>正则表达式声?span lang="EN-US">,</span>用于在状态机初始化时<span lang="EN-US">,</span>按照此规则匹配目?span lang="EN-US"><br>               main := <br>                                ([t][a][b][l][e]@see_table) ([d][i][v]@see_div)+'\n';<br>               # </span>初始?span lang="EN-US"><br>               write init;<br>               write exec;<br>        }%%<br><br>                if ( cs < par_str_first_final )<br>                fprintf( stderr, "par_str: there was an error\n" ); <br>};<br><br>#define BUFSIZE 1024<br>//</span>d?span lang="EN-US">,</span>用于试生成的状态机<span lang="EN-US"><br>int main()<br>{<br>        char buf[BUFSIZE];<br>        while ( fgets( buf, sizeof(buf), stdin ) != 0 ) <br>{<br>par_str(buf,10);<br>}<br>                return 0;<br>}<o:p></o:p></span></span></p> <p class="MsoNormal" style="margin-bottom: 12pt"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma"><br></span><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">接下?span lang="EN-US">,</span>?span lang="EN-US">ragel</span>命o生成目的语言文g<span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: left" align="left"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma">CODE:<o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #fdfff2"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma">ragel -o test.cpp test.rl<o:p></o:p></span></p> <p class="MsoNormal" style="margin-bottom: 12pt"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma"><br></span><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">用代码生成工?span lang="EN-US">,</span>直接生成可执行代?span lang="EN-US"><o:p></o:p></span></span></p> <p class="MsoNormal" style="background: #f3f8d7; text-align: left" align="left"><b><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: tahoma">CODE:<o:p></o:p></span></b></p> <p class="MsoNormal" style="background: #fdfff2"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">rlcodegen -o hello.cpp test.cpp<o:p></o:p></span></p> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma"><br></span><span style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma">最后编写对此代码的<span lang="EN-US">Makefile,make........<o:p></o:p></span></span></p> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: tahoma"><br style="mso-special-character: line-break" clear="all"><span style="color: #333333"><o:p></o:p></span></span></p></td></tr> <tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes"> <td style="padding-right: 7.5pt; padding-left: 7.5pt; padding-bottom: 1.5pt; padding-top: 1.5pt" valign="bottom"> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; color: #333333; font-family: 宋体; mso-bidi-font-family: tahoma"><o:p> </o:p></span></p></td></tr></tbody></table> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; font-family: 宋体; mso-bidi-font-family: arial"><o:p> </o:p></span></p><img src ="http://www.shnenglu.com/woaidongmao/aggbug/70245.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/woaidongmao/" target="_blank">肥仔</a> 2008-12-24 15:18 <a href="http://www.shnenglu.com/woaidongmao/archive/2008/12/24/70245.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>状态机的应用实?---?sh)子?/title><link>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69416.html</link><dc:creator>肥仔</dc:creator><author>肥仔</author><pubDate>Sun, 14 Dec 2008 11:33:00 GMT</pubDate><guid>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69416.html</guid><wfw:comment>http://www.shnenglu.com/woaidongmao/comments/69416.html</wfw:comment><comments>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69416.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/woaidongmao/comments/commentRss/69416.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/woaidongmao/services/trackbacks/69416.html</trackback:ping><description><![CDATA[<p></p> <p class="MsoNormal" style="line-height: 150%"><span lang="EN-US" style="font-size: 12pt; color: black; line-height: 150%; font-family: 宋体; mso-bidi-font-family: arial">  </span><span style="font-size: 12pt; color: black; line-height: 150%; font-family: 宋体; mso-bidi-font-family: arial">看看时候玩?span lang="EN-US">5</span>块钱那种最单的?sh)子表。只?span lang="EN-US">2</span>个按钮就能操?暂且UCؓ按钮<span lang="EN-US">A</span>和按?span lang="EN-US">B)?br>  </span>现给Z个完整的功能文字描述Q?span lang="EN-US"><br>     </span>在显C时间时?span lang="EN-US">A</span>Q屏q显C变成日?span lang="EN-US"><br>     </span>在显C日期时?span lang="EN-US">A</span>Q屏q显C变成秒?span lang="EN-US"><br>     </span>在显C秒钟时?span lang="EN-US">A</span>Q屏q显C变成时?span lang="EN-US"><br>     </span>在显C秒钟时?span lang="EN-US">B</span>Q秒钟归<span lang="EN-US">0<br>     </span>在显C时间时?span lang="EN-US">B</span>Q屏q?旉、日期交替显C?span lang="EN-US"><br>     </span>在时间、日期交替显C时?span lang="EN-US">B</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁<span lang="EN-US"><br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">B</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>?span lang="EN-US">1</span>Q超q?span lang="EN-US">23</span>?span lang="EN-US">0<br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">A</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁<span lang="EN-US"><br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">B</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>?span lang="EN-US">1</span>Q超q?span lang="EN-US">59</span>?span lang="EN-US">0<br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">A</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁<span lang="EN-US"><br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">B</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>?span lang="EN-US">1</span>Q超q?span lang="EN-US">12</span>?span lang="EN-US">0<br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">A</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁<span lang="EN-US"><br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">B</span>Q屏q?span lang="EN-US">?/span>?span lang="EN-US">?/span>?span lang="EN-US">1</span>Q超q?span lang="EN-US">31</span>?span lang="EN-US">0<br>     </span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>闪烁时按<span lang="EN-US">A</span>Q屏q回到时间显C?span lang="EN-US"><br><br>    </span>如果按照新手的思\Q尝试去LE图Q很快就会陷入一头雾_你会发现实现q个功能的程序根本就没有<span lang="EN-US">?/span>定的流E?span lang="EN-US">?/span>。因为程序实际流E是Ҏ(gu)人的操作而变化的。程序运行到什么地方,完全取决于两个键的次序,有无数种ơ序l合Q根本不可能d程图来?span lang="EN-US"><br>    </span>但是我们会发玎ͼq个?sh)子表功能?span lang="EN-US">?/span>语言描述<span lang="EN-US">?/span>在语法上g有某U规律,是Q?span lang="EN-US"><br>    </span>当系l处于某状态(<span lang="EN-US">S1</span>Q时Q如果发生了什么事?span lang="EN-US">(E)</span>Q就执行某功?span lang="EN-US">(F)</span>Q然后系l变成新状态(<span lang="EN-US">S2</span>Q?span lang="EN-US"><br>    </span>只要能用上面q句话描q的pȝQ都可以用一U状态蟩转机制很方便的实?span lang="EN-US"><br></span>Qƈ且一句话其实是一?span lang="EN-US">if(...)</span>Q无论有多少多复杂的功能Q只要能用上面这句话描述Q都可以通过状态机~程实现?span lang="EN-US">   <br>   <br></span>我们它们抽象。整个系l中?span lang="EN-US">2</span>个事件分别是Q?span lang="EN-US">A</span>按下Q?span lang="EN-US">B</span>按下<span lang="EN-US"><br><br>    A</span>按下<span lang="EN-US">(</span>可以是中?span lang="EN-US">)</span>时执行:<span lang="EN-US"><br>{<br>     if(Status==TIME)  //</span>当显C时间时按下<span lang="EN-US">A</span>?span lang="EN-US"><br>     {<br>        Status=DATE    //</span>变成昄日期<span lang="EN-US"><br>     }<br>     if(Status==DATE)  //</span>当显C日期时按下<span lang="EN-US">A</span>?span lang="EN-US"><br>     {<br>        Status=SEC     //</span>变成昄U钟<span lang="EN-US"><br>     }<br>     if(Status==SEC)  //</span>当显C秒钟时按下<span lang="EN-US">A</span>?span lang="EN-US"><br>     {<br>        Status=TIME     //</span>变成昄旉<span lang="EN-US"><br>     }<br>     if(Status==SET_HOUR)  //</span>当设|?span lang="EN-US">?/span>时<span lang="EN-US">?/span>时按?span lang="EN-US">A</span>?span lang="EN-US"><br>     {<br>        Status=SET_MINUT        //</span>变成讄<span lang="EN-US">?/span>分钟<span lang="EN-US">?br>     }<br>     if(Status==SET_MINUT)  //</span>当设|?span lang="EN-US">?/span>分钟<span lang="EN-US">?/span>时按?span lang="EN-US">A</span>?span lang="EN-US"><br>     {<br>        Status=SET_MONTH        //</span>变成讄<span lang="EN-US">?/span>?span lang="EN-US">?br>     }<br>     .....<br>     .....<br>}<br>  <br><br>    B</span>按下<span lang="EN-US">(</span>可以是中?span lang="EN-US">)</span>时执行:<span lang="EN-US"><br>{<br>      if(Status==SEC)  //</span>当显C秒钟时按下<span lang="EN-US">B</span>?span lang="EN-US"><br>     {<br>        Secound=0     //</span>U归<span lang="EN-US">0<br>     }<br>     if(Status==TIME)  //</span>当显C时间时按下<span lang="EN-US">B</span>?span lang="EN-US"><br>     {<br>        Status=TIMEDATE    //</span>变成旉日期交替昄<span lang="EN-US"><br>     } <br>     if(Status==TIMEDATE)  //</span>当日期交替显C时按下<span lang="EN-US">B</span>?span lang="EN-US"><br>     {<br>        Status=SET_HOUR    //</span>变成讄<span lang="EN-US">?/span>?span lang="EN-US">?/span>Q时闪烁Q?span lang="EN-US"><br>     }<br>     if(Status==SET_HOUR)  //</span>当设|?span lang="EN-US">?/span>?span lang="EN-US">?/span>时按?span lang="EN-US">B</span>?span lang="EN-US"><br>     {<br>        Status=Hour++      //</span>时加<span lang="EN-US">1<br>        if(Hour>23) Hour="0";      <br>     }<br><br>     .....<br>     .....        <br>}<br><br>     </span>和语a描述完全一_很快p写完E序。这是最单的状态机思想?span lang="EN-US"><br>     </span>当然Q上qC大堆<span lang="EN-US">if</span>可以?span lang="EN-US">switch case</span>来实?span lang="EN-US"><br>     </span>实际中,大量的ƈ发过E都可以表述为状态蟩转关p,从而将<span lang="EN-US">CPU</span>从过E中解放出来Q只需处理状态关p,因ؓ真正需?span lang="EN-US">CPU</span>的是状态变化的时刻Q而不是过E中大量的等待,q样大量的ƈ发过E都可以q行处理?span lang="EN-US"><?xml:namespace prefix = o /><o:p></o:p></span></span></p><img src ="http://www.shnenglu.com/woaidongmao/aggbug/69416.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/woaidongmao/" target="_blank">肥仔</a> 2008-12-14 19:33 <a href="http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69416.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是有限状态机FSMhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69415.html肥仔肥仔Sun, 14 Dec 2008 10:54:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69415.htmlhttp://www.shnenglu.com/woaidongmao/comments/69415.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69415.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69415.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69415.html?span lang="EN-US">

有限状态机Q以下用FSM指代Q是一U算法思想Q简单而言Q有限状态机׃l状态、一个初始状态、输入和Ҏ(gu)输入及现有状态{换ؓ下一个状态的转换函数l成。在Gof?span lang="EN-US">23U设计模式里?span lang="EN-US">state模式是一U面向对象的状态机思想Q可以适应非常复杂的状态管理?span lang="EN-US">
?在,FSM被普遍用于搜索引擎的分词、编译器实现和我们普遍关注的游戏开发中。游戏开发中Q通常?span lang="EN-US">FSM实现NPC控制Q如?span lang="EN-US">NPC受到d时根据健店力量等选择逃跑q是反攻的行为,一般是?span lang="EN-US">FSM实现的?span lang="EN-US">FSM的实现方法有很多U,不能单地说孰优孰劣,但现代开发中Q一般都比较推荐面向对象的实现方式:因ؓ可重用性和健壮性更高,而且当需求变更的时候,也有很好的适应性?span lang="EN-US">
实践
?Z实践中来Q也要回到实践中厅R我们现在通过实例来探索一?span lang="EN-US">FSM的实现吧。首先假设有q样一个世界(WorldQ,世界里只有一台永不缺乏动力的汽R Q?span lang="EN-US">CarQ,汽R是次世代的,没有沚w方向盘之cȝ落后讑֤Q只有两个互斥的按钮—?/span>停止Q?span lang="EN-US">StopQ和行进Q?span lang="EN-US">RunQ,随着旉的流逝,汽RҎ(gu)N员的操作走走停停。下面的代码可以实现q种功能Q?span lang="EN-US">
       while True:
       key = get_key() # 按下什么键
       if key == "stop":
              stop(car)
       elif key == "run":
              go(car)
       keep(car) #
保持原?span lang="EN-US">  

?成了功能而且直观、简z的E序员万岁!但这时候客P{划或者玩Ӟ觉得走走停停太没意思了Q他们想要掉头、左转和双{的功能,我们p?span lang="EN-US">while循环 里增加更多的if...else分支Q他们想要更多的车,我们p要在每一个分枝里增加循环Q他们不仅仅惌Car了,他们q要要玩TruckQ这时我?需要在分枝的@环里判断当前的R是否支持q个操作Q如Truck的装卸货?span lang="EN-US">Car׃支持Q;他们…?
q个while循环l于无限地庞大v来,我们认识到这L设计的确是有炚w题的Q所以我们尝试用另一U方法去实现FSM。首先我们来实现汽RQ?span lang="EN-US">CarQ:
       class Car(object):
       def stop(self):
              print "Stop!!!"
       def go(self):
              print "Goooooo!!!" 

只有两个Ҏ(gu)stop?span lang="EN-US">goQ分别执?span lang="EN-US">Stop?span lang="EN-US">Run两个按钮功能。接下来我们~写两个状态管理的c,用以处理当按钮被按下、弹起和保持旉要工作的程Q?span lang="EN-US">
class stop_fsm(base_fsm):
       def enter_state(self, obj):
              print "Car%s enter stop state!"%(id(obj))
 
       def exec_state(self, obj):
              print "Car%s in stop state!"%(id(obj))
              obj.stop()
 
       def exit_state(self, obj):
              print "Car%s exit stop state!"%(id(obj)) 
class run_fsm(base_fsm):
       def enter_state(self, obj):
              print "Car%s enter run state!"%(id(obj))
 
       def exec_state(self, obj):
              print "Car%s in run state!"%(id(obj))
              obj.go()
 
       def exit_state(self, obj):
              print "Car%s exit run state!"%(id(obj)) 

stop_fsm?span lang="EN-US">run_fsm都承自base_fsmQ?span lang="EN-US">base_fsm是一个纯虚的接口c:
class base_fsm(object):
       def enter_state(self, obj):
              raise NotImplementedError()
 
       def exec_state(self, obj):
              raise NotImplementedError()
 
       def exit_state(self, obj):
              raise NotImplementedError() 

enter_state ?span lang="EN-US">objq入某状态的时候调?span lang="EN-US">—?/span>通常用来做一些初始化工作Q?span lang="EN-US">exit_state也离开某状态的时候调?span lang="EN-US">—?/span>通常做一些清理工作;?span lang="EN-US"> exec_state则在每一帧的时候都会被调用Q通常做一些必要的工作Q如自q消息队列q处理消息等。在stop_fsm?span lang="EN-US">run_fsm两个c??span lang="EN-US">exec_state函数中,p用了对象?span lang="EN-US">stop?span lang="EN-US">go函数Q让汽R保持原有的状态?span lang="EN-US">
至现在ؓ止,Carq没有接触到FSMQ所以我们需要提供一个接口,可以让它拥有一?span lang="EN-US">FSMQ?span lang="EN-US">
       def attach_fsm(self, state, fsm):
              self.fsm = fsm
              self.curr_state = state 

我们q需要ؓCar提供一个状态{换函敎ͼ
       def change_state(self, new_state, new_fsm):
              self.curr_state = new_state
              self.fsm.exit_state(self)
              self.fsm = new_fsm
              self.fsm.enter_state(self)
              self.fsm.exec_state(self) 

?span lang="EN-US">Car提供一个保持状态的函数Q?span lang="EN-US">
       def keep_state(self):
              self.fsm.exec_state(self) 

现在只有两个状态,但我们知道需求随时会改动Q所以我们最好弄一个状态机理器来理q些状态:
class fsm_mgr(object):
       def __init__(self):
              self._fsms = {}
              self._fsms[0] = stop_fsm()
              self._fsms[1] = run_fsm()
      
       def get_fsm(self, state):
              return self._fsms[state]
      
       def frame(self, objs, state):
              for obj in objs:
                     if state == obj.curr_state:
                            obj.keep_state()
                     else:
                            obj.change_state(state, self._fsms[state]) 

fsm_mgr最重要的函数就?span lang="EN-US">frameQ在每一帧都被调用。在q里Q?span lang="EN-US">frameҎ(gu)对象现在的状态和当前的输入决定让对象保持状态或者改变状态?span lang="EN-US">
q时候,我们的实例基本上完成了。但我们q要做一件事Q就是徏立一个世界(WorldQ来驱动状态机Q?span lang="EN-US">
class World(object):
       def init(self):
              self._cars = []
              self._fsm_mgr = fsm_mgr()
              self.__init_car()
 
       def __init_car(self):
              for i in xrange(1):   # 生汽R
                     tmp = Car()
                     tmp.attach_fsm(0, self._fsm_mgr.get_fsm(0))
                     self._cars.append(tmp)
 
       def __frame(self):
              self._fsm_mgr.frame(self._cars, state_factory())
 
       def run(self):
              while True:
                     self.__frame()
                     sleep(0.5) 

?代码可见Q?span lang="EN-US">World里有Car对象Q?span lang="EN-US">fsm_mgr对象Q在run函数里,?span lang="EN-US">0.5s执行一?span lang="EN-US">__frame函数Q?span lang="EN-US">FPS = 2Q,?span lang="EN-US">__frame函数只是驱动?span lang="EN-US">fsm_mgr来刷新对象,新的命o是从state_factory函数里取出来的,q个函数用以模拟N员的操作Q按?span lang="EN-US">Stop或?span lang="EN-US">Run按钮之一Q:
def state_factory():
       return random.randint(0, 1) 

现在我们p初始化世界(WorldQ可以跑h们的FSM了!
if __name__ == "__main__":
       world = World()
       world.init()
       world.run() 

?span lang="EN-US">python解释器执行上面的代码Q我们可以看到程序不停地输出Car的状态:
......
Car8453392 exit run state!
Car8453392 enter stop state!
Car8453392 in stop state!
Stop!!!
Car8453392 in stop state!
Stop!!!
Car8453392 exit stop state!
Car8453392 enter run state!
Car8453392 in run state!
Goooooo!!!
Car8453392 exit run state!
Car8453392 enter stop state!
Car8453392 in stop state!
Stop!!!
Car8453392 exit stop state!
Car8453392 enter run state!
Car8453392 in run state!
Goooooo!!!
Car8453392 in run state!
Goooooo!!!
Car8453392 exit run state!
Car8453392 enter stop state!
Car8453392 in stop state!
Stop!!!
Car8453392 in stop state!
Stop!!!
Car8453392 exit stop state!
Car8453392 enter run state!
Car8453392 in run state!
Goooooo!!!
...... 

 
l论
q时再回头来看看我们之前的问题:
1
、玩家想要功能更多的CarQ比如掉头?span lang="EN-US">
?们可以通过?span lang="EN-US">Car增加一个调_backQ的Ҏ(gu)来执行掉_然后?span lang="EN-US">base_fsm中承一?span lang="EN-US">back_fsm来处理调头。之后在fsm_mgr里增 加一?span lang="EN-US">back_fsm实例Q及?span lang="EN-US">state_factory产生调头指o。听hg比之?span lang="EN-US">while+if的方式还要麻烦不,其实不然Q这里只?span lang="EN-US"> back_fsm和ؓfsm_mgr增加back_fsm实例才是Ҏ(gu)的,其它步骤两种Ҏ(gu)都要执行?span lang="EN-US">
2、玩家要更多?span lang="EN-US">Car?span lang="EN-US">
q对于面向对象的FSM实现太单了Q我们只要把World.__init_car里的生数量修改一下就行了Q要多少有多?span lang="EN-US">
3、玩家要更多型号的RQ如Truck?span lang="EN-US">
?span lang="EN-US">Carz一?span lang="EN-US">TruckQ然后增加装货、卸货的接口。最大的改动在于Truck状态{换的时候需要一些判断,如不能直接从装货状态{换到开动状态,而是装货、停止再开动?span lang="EN-US">
?q这几个单的问题分析Q我们可以看刎ͼ使用面向对象的方式来设计FSMQ在需求变更的时候,一般都只增删代码,而仍需要改动已有代码,E序的扩展性、适应性和健壮性都得很大的提高Q因此,在世界庞大、物U烦多、状态复杂且条g交错的游戏开发中应用面向对象?span lang="EN-US">FSM实在是明Z选。还有一点,面向对象?span lang="EN-US"> FSM可以非常Ҏ(gu)地模拟消息机Ӟq有利于模块清晰化,更容易设计出正交的程序?

 



肥仔 2008-12-14 18:54 发表评论
]]>
为Linux应用构造有限状态机Ҏ(gu)http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69414.html肥仔肥仔Sun, 14 Dec 2008 10:40:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69414.htmlhttp://www.shnenglu.com/woaidongmao/comments/69414.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69414.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69414.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69414.html阅读全文

肥仔 2008-12-14 18:40 发表评论
]]>
游戏中的有限状态机http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69411.html肥仔肥仔Sun, 14 Dec 2008 09:56:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69411.htmlhttp://www.shnenglu.com/woaidongmao/comments/69411.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69411.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69411.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69411.htmlq是GAMEGEMS中的W三章的W一部分Q番的不好。你可以直接阅读原文。原本以是h工智能的部分Q看C半才发现只是一个简单的框架。如果你惛_人工Q这里没有,׃要浪Ҏ(gu)间了。由于本人水qx限,其中隑օ会出现原则性的错误Q希望指正?span lang="EN-US">

关键字:有限状态机、状态、输入、状态{换、输出状态当前状?span lang="EN-US">

一个有限状态机c?span lang="EN-US">
在这文章中Q我们创Z一个通用的有限状态机Q?span lang="EN-US">FSMQ的C++cR有限状态机是计机U学和数学理论的抽象Q它在许多的斚w是很有用处的。这里我们不去讲解有限状态机的理Z的知识。而是讲如何实C?span lang="EN-US">?/span>有限状态机?/span>Q?span lang="EN-US">?/span>有限状态机?/span>在游戏的人工斚w是很有用处的?span lang="EN-US">

?/span>有限状态机?/span>是由有限的状态组成的一个机制。一?span lang="EN-US">?/span>状?span lang="EN-US">?/span>是一个状c你考虑一下门Q它?span lang="EN-US">?/span>状?span lang="EN-US">?/span>?span lang="EN-US">?/span>开?/span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>以及?/span>?span lang="EN-US">?/span>?span lang="EN-US">?/span>未锁?/span>?span lang="EN-US">

对于一?span lang="EN-US">?/span>有限状态机?/span>Q它应该有一?span lang="EN-US">?/span>输入?/span>。这?span lang="EN-US">?/span>输入?/span>可以影响?/span>状态{?span lang="EN-US">?/span>?span lang="EN-US">?/span>有限状态机?/span>应该有一个简单(或复杂)的状态{换函敎ͼq个函数可以军_什么状态可以变?span lang="EN-US">?/span>当前状?span lang="EN-US">?/span>?span lang="EN-US">

q个当前的新状态被UCؓ?/span>有限状态机?/span>?span lang="EN-US">?/span>状态{?span lang="EN-US">?/span>?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>。如果你对这个概忉|些迷惑,把?/span>?span lang="EN-US">?/span>做ؓ理解?/span>有限状态机?/span>的例子。当一?span lang="EN-US">?/span>?span lang="EN-US">?/span>处于?/span>关闭?/span>状态和?/span>?span lang="EN-US">?/span>状态,当你输入?span lang="EN-US">?/span>使用钥匙?/span>Ӟ门的状态可以变?span lang="EN-US">?/span>未锁?/span>状态(?span lang="EN-US">?/span>状态{?span lang="EN-US">?/span>的输出状态,也就是门的当前状态)。当你输入了?/span>使用?span lang="EN-US">?/span>Ӟ门的状态可以{换成?/span>开?/span>的状态。当门处?span lang="EN-US">?/span>开?/span>的状态时Q我们输?span lang="EN-US">?/span>使用?span lang="EN-US">?/span>Ӟ会门的状态重新回?span lang="EN-US">?/span>?span lang="EN-US">?/span>的状态。当?/span>?span lang="EN-US">?/span>处于?/span>?span lang="EN-US">?/span>的状态时Q我们输?span lang="EN-US">?/span>使用钥匙?/span>Ӟq将会门重新回?span lang="EN-US">?/span>?span lang="EN-US">?/span>的状态。当门处?span lang="EN-US">?/span>?span lang="EN-US">?/span>的状态,我们输入?/span>使用?span lang="EN-US">?/span>Q就不能把门的状态{换到?/span>开?/span>的状态,门仍然会保持?/span>?span lang="EN-US">?/span>的状态。还有,当门处于?/span>开?/span>的状态时Q我们输?span lang="EN-US">?/span>使用钥匙?/span>是不能把门的状态{换成?/span>?span lang="EN-US">?/span>的状态的?span lang="EN-US">

MQ?span lang="EN-US">?/span>有限状态机?/span>是一个有限的状态组成的Q其中的一个状态是?/span>当前状?span lang="EN-US">?/span>?span lang="EN-US">?/span>有限状态机?/span>可以接受一?span lang="EN-US">?/span>输入?/span>Q这?span lang="EN-US">?/span>输入?/span>的结果将D一?span lang="EN-US">?/span>状态{?span lang="EN-US">?/span>的发生(即从?/span>当前状?span lang="EN-US">?/span>转换?span lang="EN-US">?/span>输出?/span>状态)。这?span lang="EN-US">?/span>状态{?span lang="EN-US">?/span>是基?span lang="EN-US">?/span>状态{换函?span lang="EN-US">?/span>的。状态{换完成之后,?/span>输出状?span lang="EN-US">?/span>卛_成了?/span>当前状?span lang="EN-US">?/span>?span lang="EN-US">

输入 状态{换函?span lang="EN-US">
当前状?span lang="EN-US">-----
》状态{?span lang="EN-US">-------------
》输出状态(当前状态)

那么Qh们是如何这个概念应用到游戏?span lang="EN-US">AI
pȝ中的呢?有限状态机的功能很多:理游戏世界、模?span lang="EN-US">NPC
的思维、维护游戏状态、分析玩游戏的h的输入,或者管理一个对象的状态?span lang="EN-US">

假如在一个冒险游戏中有一?span lang="EN-US">NPC
Q名字可以叫MONSTER。我们可以先假设q个MONSTER在游戏中有如下的状态:BERSERK?span lang="EN-US">RAGE
?span lang="EN-US">MAD
?span lang="EN-US">ANNOYED
以及UNCARING。(前几个状态不好分别)。假设,MONSTER对于不同的状态可以执行不同的操作Qƈ且假设你已经有了q些不同操作的代码。我们这时可以?span lang="EN-US">?/span>有限状态机?/span>来模拟这?span lang="EN-US">MONSTER的行Z。只要我们给Z同的?/span>输入?/span>Q?span lang="EN-US">MONSTER׃做出不同的反应。我们再来指?span lang="EN-US">?/span>输入?/span>是什么:PLAYER SEEN?span lang="EN-US">PLAYER ATTACKS?span lang="EN-US">PLAYERGONE?span lang="EN-US">MONSTER HURT
?span lang="EN-US">MONSTER HEALED
。这h们可以得C个状态{换的表格Q如下:游戏状态{换表Q?span lang="EN-US">

当前状?输入 输出状?span lang="EN-US">
UNCARING PLAYER SEEN ANNOYED
UNCARING PLAYER ATTACKS MAD
MAD MONSTER HURT RAGE
MAD MONSTER HEALED UNCARING
RAGE MONSTER HURT BERSERK
RAGE MONSTER HEALED ANNOYED
BERSERK MONSTER HURT BERSERK
BERSERK MONSTER HEALED RAGE
ANNOYED PLAYER GONE UNCARING
ANNOYED PLAYER ATTACKS RAGE
ANNOYED MONSTER HEALED UNCARING

Ҏ(gu)上面的这个表|我们可以很容易的d一?span lang="EN-US">MONSTER?span lang="EN-US">?/span>状态{换图?/span>Q?span lang="EN-US">MONSTER的每一个状态就是图中的点?span lang="EN-US">
因此Q根据当前状态和?span lang="EN-US">FSM
的输入,MONSTER的状态将被改变。这时根?span lang="EN-US">MONSTER
的状态执行相应操作的代码Q假讑ַl实玎ͼ被执行Q这?span lang="EN-US">MONSTER
好像是具备了人工。显Ӟ我们可以定义更多?span lang="EN-US">?/span>状?span lang="EN-US">?/span>Q写出更多的?/span>输入?/span>Q写出更多的?/span>状态{?span lang="EN-US">?/span>Q这PMONSTER可以表现的更真实Q生动,当然Q这些游戏的规则问题应该是策划制定的?span lang="EN-US">

FSMclass
以及FSMstate

现在Q我们如何把q些Ҏ(gu)变成现实Q?span lang="EN-US">FSMclass
和它的组成部?span lang="EN-US">FSMstate
可以实现q些x?span lang="EN-US">

定义FSMstate
class FSMstate
{
    unsigned m_usNumberOfTransition; //
状态的最大数
    int* m_piInputs; //
Z转换而用的输入数组
    int* m_piOutputState; //
输出状态数l?span lang="EN-US">
    int m_iStateID; //
q个状态的唯一标识W?span lang="EN-US">
public:
    //
一个构造函敎ͼ可以接受q个状态的ID和它支持的{换数?span lang="EN-US">
    FSMstate(int iStateID,unsigned usTransitions);
    //
析构函数Q清除分配的数组
    ~FSMstate();
    //
取这个状态的ID
    int GetID(){return m_iStateID;}
    //
向数l中增加状态{?span lang="EN-US">
    void AddTransition(int iInput,int iOutputID);
    //
从数l中删除一个状态{?span lang="EN-US">
    void DeleteTransition(int iOutputID);
    //
q行状态{换ƈ得到输出状?span lang="EN-US">
    int GetOutput(int iInput);
};


对这个类的分析:
功能Q主要是实现与一个状态相关的各种操作。我们前面假设了MONSTER的各U状态:
#define STATE_ID_UNCARING 1
#define STATE_ID_MAD 2
#define STATE_ID_RAGE 3
#define STATE_ID_BERSERK 4
#define STATE_ID_ANNOYED 5

状态{换所需的输入有Q?span lang="EN-US">
#define INPUT_ID_PLAYER_SEEN 1
#define INPUT_ID_PLAYER_ATTACK 2
#define INPUT_ID_PLAYER_GONE 3
#define INPUT_ID_MONSTER_HURT 4
#define INPUT_ID_MONSTER_HEALED 5


以上是五个状态的标识W?span lang="EN-US">
我们p声明5?span lang="EN-US">FSMstate
的实例,每一个实例代表一个状态和与之有关的操作。假设我们先处理状?span lang="EN-US">STATE_ID_MAD
cL员变?span lang="EN-US">m_iStateID
q?span lang="EN-US">STATE_ID_MAD
cL员变?span lang="EN-US">m_usNumberOfTransition
是可由q个状态{换成的状态的个数Q前面有一个表Q其中有两个状态可以由q个状态生,它们分别?span lang="EN-US">STATE_ID_UNCARING
?span lang="EN-US">STATE_ID_RAGE
?span lang="EN-US">
q时Q?span lang="EN-US">m_usNumberOfTransition
{于2?span lang="EN-US">

m_piInputs
是一个指针变量,它保存与q个状态相关的输入Q在前面的表中我们知道与STATE_ID_MAD相关的输入ؓ
INPUT_ID_MONSTER_HURT
?span lang="EN-US">INPUT_ID_MONSTER_HEALED
Q因?span lang="EN-US">m_piInputs
中存攄是这两个数据?span lang="EN-US">
?span lang="EN-US">m_piOutputState存放的是?span lang="EN-US">STATE_ID_MAD相关的状态,?span lang="EN-US">STATE_ID_RAGE?span lang="EN-US">STATE_ID_UNCARINGQ这Pm_piOutputState中存攄数据便是q两个倹{?span lang="EN-US">

以上是对成员变量的解释,下面解释成员函数Q?span lang="EN-US">
构造函?span lang="EN-US">
FSMstate::FSMstate(int iStateID,unsigned usTransitions)
{
    if(!usTransitions) //
如果l出的{换数量ؓ0Q就ؓ1
        m_usNumberOfTransitions=1;
    else
        m_usNumberOfTransitions=usTransitions;

    //
状态的ID保存h
    m_iStateID=iStateID;

    //
分配内存I间
    try
    {
        m_piInputs=new int[m_usNumberOfTransitions];
        for(int i=0;i<m_usNumberOfTransitions;++i)
            m_piInputs[i]=0;
    }
    catch(...)
    {
        throw;
    }
    try
    {
        m_piOutputState=new int[m_usNumberOfTransition];
        for(int i=0;i<m_usNumberOfTransitions;++i)
            m_piOutputState[i]=0;
    }
    catch(...)
    {
        delete [] m_piInputs;
        throw;
    }
}


q就是构造函敎ͼ?span lang="EN-US">FSMstatecM共有四个成员变量Q在q个函数中全部被初始化了?span lang="EN-US">FSMstate是一个类Q是否还记得MONSTER的状态(?span lang="EN-US">MAD?span lang="EN-US">UNCARINGQ。这个类是实现?span lang="EN-US">MONSTER的一个状态的理的。假如这个状态是STATE_ID_MADQ与q个状态相关的状态有两个Q上面已l讲q了。这时我们给成员变量赋|在这个具体例子中它们的值如下:

m_usNumberOfTransition=2
m_piInput[0]=0;
m_piInput[1]=0;
m_piOutputState[0]=0;
m_piOutputState[1]=0;
m_iStateID=STATE_ID_MAD;

析构函数Q?span lang="EN-US">
FSMState::~FSMState()
{
    delete [] m_piInputs;
    delete [] m_piOutputState;
}

析构函数动态分配的存储I间释放了?span lang="EN-US">

void FSMstate::AddTransition(int iInput,int iOutputID)
{
    for(int i=0;i<m_usNumberOfTransitions;++i)
        if(!m_piOutputState[i]) break;
            if(i<m_usNumberOfTransition)
            {
                m_piOutputState[i]=iOutputID;
                m_piInputs[i]=iInput;
            }
}


q个函数l两个前面构造函数动态分配的I间加入数据Q首先要扑ֈ两个数组中找到适当的位|,之后Q如果位|是合法?span lang="EN-US">
我们可以把数据加入q两个数l中。因?span lang="EN-US">STATE_ID_MAD与两个状态有养I因此Q我们可以调用两ơ这个函敎ͼ把这两个状态加入到cMQ?span lang="EN-US">

AddTransition(INPUT_ID_MONSTER_HURT,STATE_ID_RAGE);
AddTransition(INPUT_ID_MONSTER_HEALED,STATE_ID_UNCARING)

q样Q与状?span lang="EN-US">STATE_ID_MAD相关?span lang="EN-US">?/span>状?span lang="EN-US">?/span>?span lang="EN-US">?/span>输入?/span>也加入了?span lang="EN-US">

void FSMstate::DeleteTransition(int iOutputID)
{
    //
遍历每一个输出状?span lang="EN-US">
    for(int i=0;i<m_usNumberOfTransitions;++i)
    {
        //
如果扑ֈ输出状态,退出@?span lang="EN-US">
        if(m_piOutputState[i]==iOutputID)
            break;
    }
    //如果没有扑ֈ输出状态,q回
    if(i>=m_usNumberOfTransitions)
        return;
    //
输出状态的内容|?span lang="EN-US">0
    m_piInputs[i]=0;
    m_piOutputState[i]=0;

    //被删除的输出状态的后面的输出状态前U?span lang="EN-US">
    for(;i<(m_usNumberOfTransition-1);++i)
    {
        if(!m_piOUtputState[i])
            break;
        m_piInputs[i]=m_piInputs[i+1];
        m_piOutputState[i]=m_piOutputState[i+1];
    }
    //最后面的输出状态置0
    m_piInputs[i]=0;
    m_piOutputState[i]=0;
}


q个函数是要删除与一个状态相关的输出状态。设一个状?span lang="EN-US">STATE_ID_MADQ与之相关的状态有两个STATE_ID_RAGE,STATE_ID_UNCARINGQ当然这是经q初始化以及前面的添加状态函C后,产生了这两个相关的状态。你惛_除哪一个?如果你想删除相关的输出状态,只要在删除函C指出那个状态即可,例如Q?span lang="EN-US">

DeleteTransition(STATE_ID_RAGE);
你就可以删除输出状?span lang="EN-US">STATE_ID_RAGE了?span lang="EN-US">

int FSMstate::GetOutput(int iInput)
{
    //
先给输出状态赋|如果未找C输入对应的输出状态时Q返回这个|
    int iOutputID=m_iStateID;

    //
遍历输出状?span lang="EN-US">
    for(int i=0;i<m_usNumberOfTransitions;++i)
    {
        //
如果没找刎ͼ退出@?span lang="EN-US">
        if(!m_piOutputState[i])
            break;
        //如果扑ֈ了与?/span>输入?/span>相对应的?/span>输出状?span lang="EN-US">?/span>Q进行赋倹{?span lang="EN-US">
        if(iInput==m_piInputs[i])
        {
            iOutputID=m_piOutputState[i];
            break;
        }
    }
    //
q回?/span>输出状?span lang="EN-US">?br>    return(iOutputID);
}


q个函数功能是返回与?/span>输入?/span>相对应的?/span>输出状?span lang="EN-US">?/span>的标识。如果没有与?/span>输入?/span>相对应的?/span>输出状?span lang="EN-US">?/span>Q返回原来的状态,如果有与之对应的?/span>输出状?span lang="EN-US">?/span>Q返回这个状态的ID?span lang="EN-US">

下面定义的是FSMclassQ这个类用于l护FSMstate对象集合?span lang="EN-US">
class FSMclass
{
    State_Map m_map; //
包括了状态机的所有状?span lang="EN-US">
    int m_iCurrentState; //
当前状态的ID
public:
    FSMclass(int iStateID); //
初始化状?span lang="EN-US">
    ~FSMclass()
    //
q回当前状?span lang="EN-US">ID
    int GetCurrentState() {return m_iCurrentState;}
    //
讄当前状?span lang="EN-US">ID
    void SetCurrentState(int iStateID) {m_iCurrentState=iStateID;}
    //
q回FSMstate对象指针
    FSMstate* GetState(int iStateID);
    //
增加状态对象指?span lang="EN-US">
    void AddState(FSMstate* pState);
    //
删除状态对象指?span lang="EN-US">
    void DeleteState(int iStateID);
    //
Ҏ(gu)?/span>当前状?span lang="EN-US">?/span>?span lang="EN-US">?/span>输入?/span>完成?/span>状?span lang="EN-US">?/span>的{换?span lang="EN-US">
    int StateTransition(int iInput);
};


FSMclass::m_map
?span lang="EN-US">FSMstate对象的集合,是从STL<map>中实现的?span lang="EN-US">
FSMclass::m_iCurrentState
?span lang="EN-US">FSMstate
对象的状态标识,?span lang="EN-US">?/span>有限状态机?/span>的当前状态?span lang="EN-US">

FSMclass::GetCurrentState()
可以用之讉K当前?span lang="EN-US">FSMstate对象的状态的标识W?span lang="EN-US">
FSMclass::SetCurrentState()可以讄当前FSMstate对象的状态的标识W?span lang="EN-US">
FSMclass::GetState()可以取得有限状态机中的MFSMstate对象的指针?span lang="EN-US">
FSMclass::AddState()增加有限状态机中的FSMstate对象?span lang="EN-US">
FSMclass::DeleteState()删除有限状态机中的FSMstate对象
FSMclass::StateTransition()
初始化状态{换,Ҏ(gu)输入q回输出状态?span lang="EN-US">

q个cM用了STLQ我不知道它怎么用:Q。听说是高h才用它Q高v码要写过上万行的代码。因此不能详l介l这个类?span lang="EN-US">

MQ可以这么理解这两个c?span lang="EN-US">FSMstate,FSMclass.FSMstate代表了一个状态以及和状态相关的数据和操作。如?span lang="EN-US">MONSTER中有五个状态,我们p声明五个cȝ对象Q每个对象中包括了与q个状态相关的状态,输入和各U{换函数。可以说FSMstate是对每一个状态的装Q包括相x据和操作Q,游戏中的对象有多状态,p声明多少?span lang="EN-US">FSMstate对象。?span lang="EN-US">FSMclass则是对这若干?span lang="EN-US">FSMstate对象Q这个例子中MONSTER有五个状态)q行的封装。在FSMclass中指明了若干?span lang="EN-US">FSMstate中哪一个是当前?span lang="EN-US">MONSTER拥有的状态ƈ且可以设|,得到以及删除状态,q且可以q行状态间的{换?span lang="EN-US">

MQ游戏中?span lang="EN-US">MONSTER有多状态,游戏中就要声明多的FSMstate对象Q每一?span lang="EN-US">FSMstate对象包括了与特定的状态相关的数据和操作。?span lang="EN-US">FSMclass只有一个,它用于协调若q个FSMstate之间的关pd操作?span lang="EN-US">

下面是如何在游戏中用两个类的例子:

首先是创?span lang="EN-US">FSMstate对象Q若q个Q,有多状态就要@环多次Q下面是增加STATE_ID_UNCARING状态的例子Q?span lang="EN-US">
FSMstate* pFSMstate=NULL;
//创徏状?span lang="EN-US">
try
{
    //
W一个参数是增加状态的标识Q第二个参数指明了与q个
    //
状态相关的状态的个数?span lang="EN-US">
    pFSMstate=new FSMstate(STATE_ID_UNCARING,2);
}
catch(...)
{
    throw;
}

//之后l这个状态加入相关的?/span>输入?/span>?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>
pFSMstate->AddTransition(INPUT_ID_PLAYER_SEEN,STATE_ID_ANNOYED);
pFSMstate->AddTransition(INPUT_ID_PLAYER_ATTACKS,STATE_ID_MAD);


q个函数指明了与特定状态相关的?/span>输入?/span>?span lang="EN-US">?/span>输出状?span lang="EN-US">?br>比如W一个函敎ͼ它表明如果我要输入一?span lang="EN-US">INPUT_ID_PLAYER_SEENQ这时就会生一个输出状态,STATE_ID_ANNOYED?span lang="EN-US">
我们应该为每一个状态做上面的事情,q里qq了。之后我们要声明一?span lang="EN-US">FSMclass
对象Q用于协调上面的FSMstate对象之间的关pR?span lang="EN-US">

try
{
    m_pFSMclass=new FSMclass(STATE_ID_UNCARING);
}
catch(...)
{
    throw;
}


上面指明?span lang="EN-US">MONSTER的当前状态是STATE_ID_UNCARING最后将FSMstate对象分别加入?span lang="EN-US">FSMclass中?span lang="EN-US">

下面介绍如何使用FSMclass
使用十分单,只要我们l出一?span lang="EN-US">?/span>输入?/span>Q之后,我们便可以得C?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>Q根据这?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>我们执行相应的操作,最后,把这?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>变成MONSTER的当前状态?span lang="EN-US">

在游戏中发生了一些事情,如玩游戏的h指出他控制的?span lang="EN-US">MONSTERQ用鼠标点击?span lang="EN-US">MONSTERQ,q时会生一?span lang="EN-US">?/span>输入”iInputID=INPUT_ID_PLAYER_ATTACK;

q时Q我们调用状态{换函敎ͼ
m_iOutputState=m_pFSMclass->StateTransition(iInputID);

q时Q我们的?/span>输入?/span>?span lang="EN-US">MONSTER产生了刺ȀQ生了一?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>。这时我们根据这个输出状态调用相应的代码执行可以了Q这时的MONSTER好像有应反了Q我们说它有了简单的?span lang="EN-US">

if(m_iOutputState==STATE_ID_MAD)
{
    //some code for the monster to act mad
}


当然Q我们也应该把其它状态执行的操作也写出来Q但只写一个就可以了。用这个状态机是q么单。MQ?span lang="EN-US">FSMclass不是全部的h工智能,相反Q它只是一个框Ӟ一个开始智能需要的q很多。只要你可以分出?/span>状?span lang="EN-US">?/span>Qƈ且知道什?span lang="EN-US">?/span>输入?/span>产生什?span lang="EN-US">?/span>输出状?span lang="EN-US">?/span>可以了Q当然这是一个游戏的规则Q策划应当完成这个部分?

 



肥仔 2008-12-14 17:56 发表评论
]]>
有限状态机的思?/title><link>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69410.html</link><dc:creator>肥仔</dc:creator><author>肥仔</author><pubDate>Sun, 14 Dec 2008 09:54:00 GMT</pubDate><guid>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69410.html</guid><wfw:comment>http://www.shnenglu.com/woaidongmao/comments/69410.html</wfw:comment><comments>http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69410.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/woaidongmao/comments/commentRss/69410.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/woaidongmao/services/trackbacks/69410.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="word-break: break-all; line-height: 150%; mso-pagination: widow-orphan"><span style="font-size: 12pt; color: black; line-height: 150%; font-family: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">有限状态机Q?span lang="EN-US">Finite State Machine</span>或?span lang="EN-US">Finite State Automata)</span>是Y仉域中一U重要的工具Q很多东西的模型实际上就是有限状态机?span lang="EN-US"><br><br></span>最q看了一些游戏编E?span lang="EN-US">AI</span>的材料,感觉游戏中的<span lang="EN-US">AI</span>Q第一要说的就是有限状态机来实现精늚<span lang="EN-US">AI</span>Q然后才?span lang="EN-US">A*</span>寻\Q其他学术界讨论比较多的经|络、模p控制等问题q不是很热?span lang="EN-US"><br><br>FSM</span>的实现方式:<span lang="EN-US"><br><b style="mso-bidi-font-weight: normal">1</b></span><b style="mso-bidi-font-weight: normal">Q?span lang="EN-US"> switch/case</span>或?span lang="EN-US">if/else</span></b><span lang="EN-US"><br></span>q无意是最直观的方式,使用一堆条件判断,会编E的人都可以做到Q对单小巧的状态机来说最合适,但是毫无疑问Q这L方式比较原始Q对庞大的状态机难以l护?span lang="EN-US"><br><br><b style="mso-bidi-font-weight: normal"><font color="#ff0000">2</font></b></span><b style="mso-bidi-font-weight: normal"><font color="#ff0000">Q?状态表</font></b><span lang="EN-US"><br></span><font color="#ff0000">l护一个二l状态表Q横坐标表示当前状态,U坐标表C入,表中一个元素存储下一个状态和对应的操作。这一招易于维护,但是q行旉和存储空间的代h(hun)较大?/font><span lang="EN-US"><br><br><b style="mso-bidi-font-weight: normal">3</b></span><b style="mso-bidi-font-weight: normal">Q?使用<span lang="EN-US">State Pattern</span></b><span lang="EN-US"><br></span>使用<span lang="EN-US">State Pattern</span>使得代码的维护比<span lang="EN-US">switch/case</span>方式E好Q性能上也不会有很多的影响Q但是也不是<span lang="EN-US">100</span>Q完。不q?span lang="EN-US">Robert C. Martin</span>做了两个自动产生<span lang="EN-US">FSM</span>代码的工P<span lang="EN-US">for java</span>?span lang="EN-US">for C++</span>各一个,?span lang="EN-US">http://www.objectmentor.com/resources/index</span>上有免费下蝲Q这个工L输入是纯文本的状态机描述Q自动生符?span lang="EN-US">State Pattern</span>的代码,q样<span lang="EN-US">developer</span>的工作只需要维护状态机的文本描qͼ每必要冒引入<span lang="EN-US">bug</span>的风险去l护<span lang="EN-US">code</span>?span lang="EN-US"><br><br><b style="mso-bidi-font-weight: normal">4</b></span><b style="mso-bidi-font-weight: normal">Q?使用宏定义描q状态机</b><span lang="EN-US"><br></span>一般来_<span lang="EN-US">C++</span>~程中应该避免?span lang="EN-US">#define</span>Q但是这主要是因为如果用宏来定义函数的话Q很Ҏ(gu)产生q样那样的问题,但是巧妙的?span lang="EN-US">,</span>q是能够产生奇妙的效果?span lang="EN-US">MFC</span>是使用宏定义来实现大的架构的?span lang="EN-US"><br></span>在实?span lang="EN-US">FSM</span>的时候,可以把一些繁琐无比的<span lang="EN-US">if/else</span>q有花括Ll合攑֜宏中Q这P在代码中可以<span lang="EN-US">3</span>Q中状态机描述文本一样写Q通过~译器的预编译处理?span lang="EN-US">1</span>Q一L效果Q我见过产生<span lang="EN-US">C</span>代码的宏Q如果要产生<span lang="EN-US">C++</span>代码Q己?span lang="EN-US">MFC</span>可以Q那么理Z也是可行的?<span lang="EN-US"><?xml:namespace prefix = o /><o:p></o:p></span></span></p> <p class="MsoNormal"><span lang="EN-US" style="font-size: 12pt; color: black; font-family: 宋体; mso-bidi-font-family: arial"><o:p> </o:p></span></p><img src ="http://www.shnenglu.com/woaidongmao/aggbug/69410.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/woaidongmao/" target="_blank">肥仔</a> 2008-12-14 17:54 <a href="http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69410.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>状态机http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69409.html肥仔肥仔Sun, 14 Dec 2008 09:53:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69409.htmlhttp://www.shnenglu.com/woaidongmao/comments/69409.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69409.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69409.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69409.html 

关于状态机的一个极度确切的描述是它是一个有向图形,׃l节点和一l相应的转移函数l成。状态机通过响应一pd事g?span lang="EN-US">?/span>q行?/span>。每个事仉在属?span lang="EN-US">?/span>当前?节点的{Ud数的控制范围内,其中函数的范围是节点的一个子集。函数返?span lang="EN-US">?/span>下一?span lang="EN-US">?/span>Q也许是同一个)节点。这些节点中臛_有一个必Ll态。当到达l态, 状态机停止?/font>

 

包含一l状态集Q?span lang="EN-US">statesQ、一个v始状态(start stateQ、一l输入符号集Q?span lang="EN-US">alphabetQ、一个映输入符号和当前状态到下一状态的转换函数Q?span lang="EN-US">transition functionQ的计算模型。当输入W号Ԍ模型随即q入起始状态。它要改变到新的状态,依赖于{换函数。在有限状态机中,会有有许多变量,例如Q状态机有很多与动作Q?span lang="EN-US">actionsQ{?span lang="EN-US">(Mealy?span lang="EN-US">)或状态(摩尔机)兌的动作,多重起始状态,Z没有输入W号的{换,或者指定符号和状态(非定?限状态机Q的多个转换Q指z接收状态(识别者)的一个或多个状态,{等?span lang="EN-US">

 

  传统应用E序的控制流E基本是序的:遵@事先讑֮的逻辑Q从头到֜执行。很有事g能改变标准执行流E?/font>Q而且q些事g主要涉及异常情况?span lang="EN-US">?/span>命o行实用程?span lang="EN-US">?/span>是这U传l应用程序的典型例子?

 

另一cd用程序由外部发生的事件来驱动—?/span>换言之,事g在应用程序之外生成,无法由应用程序或E序员来控制?/font>具体需要执行的代码取决于接收到的事Ӟ或者它相对于其他事件的抵达旉。所以,控制程既不能是序的,也不能是事先讑֮好的Q因为它要依赖于外部事g。事仉动的GUI应用E序是这U应用程序的典型例子Q它们由命o和选择Q也是用户造成的事Ӟ来驱动?

 

Web应用E序由提交的表单和用戯求的|页来驱动,它们也可划归Cq类别。但是,GUI应用E序对于接收到的事g仍有一定程度的控制Q因些事件要依赖于向用户昄的窗口和控gQ而窗口和控g是由E序员控制的?span lang="EN-US">Web应用 E序则不Ӟ因ؓ一旦用户采取不在预料之中的操作Q比如用浏览器的历史记录、手工输入链接以及模拟一ơ表单提交等{)Q就很容易打p计好的应用程序逻辑?

 

昄Q必采取不同的技术来处理q些情况。它能处理Q何顺序的事gQƈ能提供有意义的响?span lang="EN-US">—?/span>即ɘq些事g发生的顺序和预计的不同。有限状态机正是Z满q方面的要求而设计的?

 

  有限状态机是一U概忉|机器,它能采取某种操作来响应一个外部事件。具体采取的操作不仅能取决于接收到的事gQ还能取决于各个事g的相对发生顺序。之所以能做到q一点,是因为机器能跟踪一个内部状态,它会在收C件后q行更新?font color="#ff0000">Z个事件而响应的行动不仅取决于事件本w,q取决于机器的内部状态。另外,采取 的行动还会决定ƈ更新机器的状态。这样一来,M逻辑都可建模成一pd事g/状态组合?/font>



肥仔 2008-12-14 17:53 发表评论
]]>
有限状态自动机http://www.shnenglu.com/woaidongmao/archive/2008/12/14/69408.html肥仔肥仔Sun, 14 Dec 2008 09:30:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69408.htmlhttp://www.shnenglu.com/woaidongmao/comments/69408.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/14/69408.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69408.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69408.html 

有限状态自动机是具有离散输入和输出的系l的一U数学模型?

  其主要特Ҏ(gu)以下几个斚wQ?

?(1)pȝh有限个状态,不同的状态代表不同的意义。按照实际的需要,pȝ可以在不同的状态下完成规定的Q务?

?(2)我们可以输入字W串中出现的字符汇集在一h成一个字母表。系l处理的所有字W串都是q个字母表上的字W串?

?(3)pȝ在Q何一个状态下Q从输入字符串中d一个字W,Ҏ(gu)当前状态和d的这个字W{到新的状态?

?(4)pȝ中有一个状态,它是pȝ的开始状态?

?(5)pȝ中还有一些状态表C它到目前ؓ止所d的字W构成的字符串是语言的一个句子?

?

  形式定义

?定义Q有限状态自动机(FA—finite automaton)是一个五元组Q?

?M=(Q, Σ, δ, q0, F)

?其中Q?

?Q——状态的非空有穷集合。∀q∈QQ?font color="#ff0000">qUCؓM的一个状?/font>?

?Σ——输入字母表?

?δ——状态{Ud敎ͼ有时又叫作状态{换函数或者移动函敎ͼδQQ×Σ→QQ?q,a)=p?/font>

?q0——M的开始状态,也可叫作初始状态或启动状?font color="#ff0000">。q0∈Q?/font>

?F——M的终止状态集合。F被Q包含。Qlq∈FQqUCؓM的终止状态?/p>

肥仔 2008-12-14 17:30 发表评论
]]>
NFA转DFAhttp://www.shnenglu.com/woaidongmao/archive/2008/12/13/69344.html肥仔肥仔Sat, 13 Dec 2008 07:21:00 GMThttp://www.shnenglu.com/woaidongmao/archive/2008/12/13/69344.htmlhttp://www.shnenglu.com/woaidongmao/comments/69344.htmlhttp://www.shnenglu.com/woaidongmao/archive/2008/12/13/69344.html#Feedback0http://www.shnenglu.com/woaidongmao/comments/commentRss/69344.htmlhttp://www.shnenglu.com/woaidongmao/services/trackbacks/69344.html一?span style="background: white; color: red">非确定自动机( NFA) 在读入符号串之后Qƈ不确切地知道自动机处于哪个状态。但可以肯定一定处于状态集中的某一状态。该状态集记做 {q1,q2,…qk} 。而一个等L定自动?/span>( DFA) d同样?span lang="EN-US"> w 一定处于某个确定的状态上。这P都是d同样?span lang="EN-US"> w Q?span lang="EN-US"> DFA 到达某一个状态,?span lang="EN-US"> NFA 到达某一个状态集。由 w 的Q意性,可将 NFA 的所有的状态集?span lang="EN-US"> DFA 的状态一一对应h。这U对应的前提是能识别同L输入丌Ӏ即 L(M1)=L(M2) ?span lang="EN-US">

       昄Q后一个状态集是依赖于前一个状态集的,是在前一个状态集的基上,Q其内Q意结点)l过同一条\径到辄。下面是一个简单的例子Q?span lang="EN-US">

   clip_image001

可以看出Q其核心是将 NFA 状态集归ƈ?span lang="EN-US"> DFA 中的状态。在 NFA 中,无论是从 1 ?span lang="EN-US"> 4 Q还?span lang="EN-US"> 1 ?span lang="EN-US"> 5 Q作为集合来讲都是集?span lang="EN-US"> 1 到集?span lang="EN-US"> 2 Q最为重要得是经q的条g都是 a 。因而从识别语言的效果是一L。这使得q些弧合q成为可能?span lang="EN-US">

考虑集合覆盖的情c?span lang="EN-US">

clip_image002

一个结点属于第一个集合又同时属于W二个集合。这U情况不一定好理解。但如果从\径的历史的角度进一步区分,即不同的旉l过同一个结点,其看成是不同的状态。按照这U时I的角度q一步区分,得到叛_。这和图 1 是类似的?span lang="EN-US">

再来看看带有l态结点的情况Q?span lang="EN-US">

   clip_image003

ab Q?span lang="EN-US"> abb 均ؓ?span lang="EN-US"> NFA 识别的句子,其{换如下:

     

 

I a

Ib

A{1,2}

{3}

Φ

B{3}

Φ

{3,4}

C{3,4}

Φ

{3,4}

从某U意义上说?span lang="EN-US"> NFA 中的状?span lang="EN-US"> 3 ?span lang="EN-US"> DFA 中被分离成两部分Q当首次到达 3 时应该是状?span lang="EN-US"> B Q而第二次以后再到?span lang="EN-US"> 3 则应该属于状?span lang="EN-US"> C ?span lang="EN-US">

Ҏ(gu)规则Q?span lang="EN-US"> C{3,4} ?span lang="EN-US"> DFA 的终态,但在 NFA 中,只有 4 为终态, C 中仍然有 3 为非l态,若有路径 1 à 3 à 3 映射?span lang="EN-US"> DFA 中也?span lang="EN-US"> A à B à C Q何解?

q里面最关键的是Q对L一个句子,d以在两个图中分别扑ֈ一条\径,形成对应关系。ƈ不是?span lang="EN-US"> NFA 中的每条路径都要?span lang="EN-US"> DFA 中的每条路径一一对应?span lang="EN-US">

当识别句?span lang="EN-US"> ab Ӟ选择?span lang="EN-US"> 3 直接到达 4 的\径。当识别句子 abb Ӟ则在状?span lang="EN-US"> 3 循环一ơ再到达 4 ?span lang="EN-US">

现在设想Q通过 1 à 3 à 3 l过的\径也?span lang="EN-US"> ab 。但此时q未到达l态。可以说Q在到达 C 中的 3 Ӟ必然选择了两?span lang="EN-US"> b 以上的句子?span lang="EN-US">

而这L路径与选择句子有关pR?span lang="EN-US">

对于 NFA 能识别的句子Q在 DFA 中也能识别?span lang="EN-US">

对于 NFA 不能识别的句子,?span lang="EN-US"> DFA 中也不能识别?span lang="EN-US">

 



肥仔 2008-12-13 15:21 发表评论
]]>
99þ99ֻѵľƷ| þݺҹҹվ| ƷŷþþӰ| þþ97ɫ | ɫۺɫþû| Ʒþ޲| һĻþ| þ޾Ʒһ | þ| þþþþþƷ| þݺҹҹվ| 99ȳ˾ƷѾþ| ƷþþþþĻ| Ʒþþþþҹ| þþžžþƷֱ| ˾þվ| ۺһ˾þþƷ| 99ŷþþþƷѿ| þ99Ʒžžžþ| ҹþþӰԺ| þþþƷҰ| WWWAVþþӰƬ| ۺϾþһ | þþƷ18| ߳߳þþ| ɫۺϾþҹɫƷ| Ʒþþþù| þþƷAV鶹 | þAVۺϺɫ| þþþúǿ׊ | þۺ³³| 91Ըߺþþþ| ݺɫþۺ| ޾þһ | ޹˾þһþ | Ʒ99þþþƷ| þۺϾɫۺŷȥ| ߳߳þþ91| ձþþþƷĻ| ľƷþþþùַ| Ʒþþþav|