Code Golf:有限状态机!

时间:2011-01-11 19:38:07

标签: python language-agnostic code-golf state-machine

有限状态机

确定性有限状态机是一种简单的计算模型,广泛用于基础CS课程中自动机理论的介绍。它是一个简单的模型,相当于正则表达式,它确定某个输入字符串 Accepted Rejected Leaving some formalities aside,有限状态机的运行由:

组成
  1. 字母,一组字符。
  2. 陈述,通常可视化为圆圈。其中一个州必须是开始状态。有些州可能接受,通常可视化为双圈。
  3. 过渡,通常可视化为状态之间的定向拱,是与字母相关联的状态之间的有向链接。
  4. 输入字符串字母字符列表。
  5. 机器上的运行从启动状态开始。读取输入字符串的每个字母;如果当前状态与对应于该字母的另一个状态之间存在转换,则当前状态将更改为新状态。在读取最后一个字母后,如果当前状态是接受状态,则接受输入字符串。如果最后一个状态不是接受状态,或者一个字母在运行期间没有来自状态的相应拱门,则拒绝输入字符串。

    注意:这种短暂的破坏远不是FSM的完整,正式的定义; Wikipedia's fine article是对该主题的精彩介绍。

    实施例

    例如,以下机器会告知从左到右读取的二进制数是否具有偶数个0 s:

    http://en.wikipedia.org/wiki/Finite-state_machine

    1. 字母表是集{0,1}
    2. 状态为S1和S2。
    3. 转换为(S1, 0) -> S2(S1, 1) -> S1(S2, 0) -> S1(S2, 1) -> S2
    4. 输入字符串是任何二进制数,包括空字符串。
    5. 规则:

      使用您选择的语言实施FSM。

      输入

      FSM应接受以下输入:

      <States>       List of state, separated by space mark.
                     The first state in the list is the start state.
                     Accepting states begin with a capital letter.
      <transitions>  One or more lines. 
                     Each line is a three-tuple:
                     origin state, letter, destination state)
      <input word>   Zero or more characters, followed by a newline.
      

      例如,上述带有1001010作为输入字符串的机器将写为:

      S1 s2
      S1 0 s2
      S1 1 S1
      s2 0 S1
      s2 1 s2
      1001010
      

      输出

      FSM的运行,写为<State> <letter> -> <state>,然后是最终状态。示例输入的输出将是:

      S1 1 -> S1
      S1 0 -> s2
      s2 0 -> S1
      S1 1 -> S1
      S1 0 -> s2
      s2 1 -> s2
      s2 0 -> S1
      ACCEPT
      

      对于空输入''

      S1
      ACCEPT
      

      注意:根据您的评论,S1行(显示第一个状态)可能会被省略,并且以下输出也可以接受:

      ACCEPT
      

      101

      S1 1 -> S1
      S1 0 -> s2
      s2 1 -> s2
      REJECT
      

      '10X'

      S1 1 -> S1
      S1 0 -> s2
      s2 X
      REJECT
      

      最短的解决方案将获得250个代表奖金。

      参考实施

      可以使用参考Python实现here。请注意,空字符串输入已放宽输出要求。

      附录

      输出格式

      根据大众需求,空输入字符串也可接受以下输出:

      ACCEPT
      

      REJECT
      

      没有上一行写的第一个状态。

      州名

      有效的州名是一个英文字母,后跟任意数量的字母_和数字,很像变量名,例如State1state0STATE_0

      输入格式

      与大多数代码高尔夫球一样,您可以假设输入正确。

      答案摘要:

      sed 137 solution是最短的,ruby 145是#2。目前,我无法使用sed解决方案:

      cat test.fsm | sed -r solution.sed
      sed -r solution.sed test.fsm
      

      都给了我:

      sed: -e expression #1, char 12: unterminated `s' command
      

      所以,除非有澄清,否则赏金将归入红宝石解决方案。

20 个答案:

答案 0 :(得分:23)

Python 2.7 +, 201 192 187 181 179 175 171个字符

PS。问题放松后(无需在空输入上输出状态行),这里的新代码明显更短。如果您使用的是版本<2.7,则没有字典理解,因此代替{c+o:s for o,c,s in i[1:-1]}尝试dict((c+o,s)for o,c,s in i[1:-1]),价格为+5。

import sys
i=map(str.split,sys.stdin)
s=i[0][0]
for c in''.join(i[-1]):
    if s:o=s;s={c+o:s for o,c,s in i[1:-1]}.get(c+s,());print o,c,'->',s
print'ARCECJEEPCTT'[s>'Z'::2]

其测试输出:

# for empty input
ACCEPT

# for input '1001010'
S1 1  ->  S1
S1 0  ->  s2
s2 0  ->  S1
S1 1  ->  S1
S1 0  ->  s2
s2 1  ->  s2
s2 0  ->  S1
ACCEPT

# for input '101'
S1 1  ->  S1
S1 0  ->  s2
s2 1  ->  s2
REJECT

# for input '10X'
S1 1  ->  S1
S1 0  ->  s2
s2 X  ->  ()
REJECT

# for input 'X10'
S1 X  ->  ()
REJECT

之前的条目(len 201):

import sys
i=list(sys.stdin)
s=i[0].split()[0]
t={}
for r in i[1:-1]:a,b,c=r.split();t[a,b]=c
try:
    for c in i[-1]:print s,c.strip(),;s=t[s,c];print' ->',s
except:print('ACCEPT','REJECT')[s>'Z'or' '<c]

我想在有人抨击我之前道歉:代码行为与原始规范略有不同 - 每个问题 - 评论讨论。这是我讨论的例子。

PS。虽然我喜欢与最终状态在同一行上的ACCEPT / REJECT分辨率,但我可以通过添加{{1来移动到孤独(例如想象结果由愚蠢的脚本解析,只关心最后一行接受或拒绝) (+ 5个字符)到最后'\n'+的价格为+5个字符。

示例输出:

print

答案 1 :(得分:21)

我今天感觉很复古,我这个任务的首选语言是IBM Enterprise Cobol - 字数<24> 4078(对不起,从屏幕导向的设备粘贴,尾随空间是一个悲剧性的副作用):

 Identification Division.               
 Program-ID. FSM.                       
 Environment Division.                  
 Data Division.                         
 Working-Storage Section.               

 01 FSM-Storage.                        

*> The current state                    
   05 Start-State      Pic X(2).        
   05 Next-State       Pic X(2).        

*> List of valid states                 
   05 FSM-State-Cnt    Pic 9.           
   05 FSM-States       Occurs 9         
                       Pic X(2).        

*> List of valid transitions            
   05 FSM-Trans-Cnt    Pic 999.         
   05 FSM-Trans        Occurs 999.      
     10 Trans-Start    Pic X(2).        
     10 Trans-Char     Pic X.           
     10 Trans-End      Pic X(2).        

*> Input                                
   05 In-Buff          Pic X(72).      

*> Some work fields                     
   05 II               Pic s9(8) binary.
   05 JJ               Pic s9(8) binary.

   05 Wk-Start         Pic X(2).        
   05 Wk-Char          Pic X.           
   05 Wk-End           Pic X(2).        
   05 Wk-Cnt           Pic 999.         

   05                  Pic X value ' '. 
     88 Valid-Input        value 'V'.   

   05                  Pic X value ' '.                 
     88 Valid-State        value 'V'.                   

   05                  Pic X value ' '.                 
     88 End-Of-States      value 'E'.                   

   05                  Pic X value ' '.                 
     88 Trans-Not-Found    value ' '.                   
     88 Trans-Found        value 'T'.                   


 Linkage Section.                                       

 01 The-Char-Area.                                      
   05 The-Char         Pic X.                           
     88 End-Of-Input       value x'13'.                 
   05 The-Next-Char    Pic X.                           

 Procedure Division.                                    

      Perform Load-States                               
      Perform Load-Transitions                          
      Perform Load-Input                                
      Perform Process-Input                             

      Goback.                                           

*> Run the machine...                                   
 Process-Input.                                         

      Move FSM-States (1) to Start-State                
      Set address of The-Char-Area to address of In-Buff

      Perform until End-Of-Input                        

        Perform Get-Next-State                          
        Set address of The-Char-Area to address of The-Next-Char

        Move Next-State to Start-State                          

      End-Perform                                               

      If Start-State (1:1) is Alphabetic-Lower                  
        Display 'REJECT'                                        
      Else                                                      
        Display 'ACCEPT'                                        
      End-If                                                    

      Exit.                                                     

*> Look up the first valid transition...                        
 Get-Next-State.                                                

      Set Trans-Not-Found to true                               
      Perform varying II from 1 by 1                            
        until (II > FSM-State-Cnt)                              
           or Trans-Found                                       

        If Start-State = Trans-Start (II)                       
          and The-Char = Trans-Char (II)                        

          Move Trans-End (II) to Next-State                     
          Set Trans-Found to true                               

        End-If                                                  

      End-Perform                                               
      Display Start-State ' ' The-Char ' -> ' Next-State        

      Exit.                                                     

*> Read the states in...                                        
 Load-States.                                                   

      Move low-values to In-Buff                         
      Accept In-Buff from SYSIN                          

      Move 0 to FSM-State-Cnt                            
      Unstring In-Buff                                   
        delimited by ' '                                 
        into FSM-States (1) FSM-States (2) FSM-States (3)
             FSM-States (4) FSM-States (5) FSM-States (6)
             FSM-States (7) FSM-States (8) FSM-States (9)
        count in FSM-State-Cnt                           
      End-Unstring                                       

      Exit.                                              

*> Read the transitions in...                            
 Load-Transitions.                                       

      Move low-values to In-Buff                         
      Accept In-Buff from SYSIN                          

      Perform varying II from 1 by 1                     
        until End-Of-States                              

        Move 0 to Wk-Cnt                                 
        Unstring In-Buff                                 
          delimited by ' '                               
          into Wk-Start Wk-Char Wk-End                   
          count in Wk-Cnt                                
        End-Unstring                                     

        If Wk-Cnt = 3                                    

          Add 1 to FSM-Trans-Cnt                         
          Move Wk-Start to Trans-Start (FSM-Trans-Cnt)   
          Move Wk-Char  to Trans-Char  (FSM-Trans-Cnt)   
          Move Wk-End   to Trans-End   (FSM-Trans-Cnt)   

          Move low-values to In-Buff                     
          Accept In-Buff from SYSIN                           

        Else                                                  

          Set End-Of-States to true                           

        End-If                                                

      End-Perform                                             

      Exit.                                                   

*> Fix input so it has newlines...the joys of mainframes      
 Load-Input.                                                  

      Perform varying II from length of In-Buff by -1         
        until Valid-Input                                     

        If In-Buff (II:1) = ' ' or In-Buff (II:1) = low-values
          Move x'13' to In-Buff (II:1)                        
        Else                                                  
          Set Valid-Input to true                             
        End-If                                                

      End-Perform                                             

      Exit.                                                   

  End Program FSM.    

答案 2 :(得分:19)

sed - 118 137个字符

这是使用-r标志(+3),总共134 + 3 = 137个字符。

$!{H;D}
/:/!{G;s/(\S*)..(\S*)/\2 \1:/}
s/(.* .)(.*\n\1 (\S*))/\1 -> \3\n\3 \2/
/-/{P;D}
/^[A-Z].* :/cACCEPT
s/( .).*/\1/
/:/!P
cREJECT

这应该处理没有正确转换的输入...希望它现在完全符合规范......

答案 3 :(得分:8)

Ruby 1.9.2 - 178 190 182 177 153 161 158 154 145个字符

h={}
o=s=p
$<.map{|l|o,b,c=l.split;h[[o,b]]=c;s||=o}
o.chars{|c|puts s+' '+c+((s=h[[s,c]])?' -> '+s :'')}rescue 0
puts s&&s<'['?:ACCEPT: :REJECT

测试脚本

[
  "S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
1001010",
  "S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
101",
  "S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
",
  "S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
10X"
].each do |b|
  puts "------"
  puts "Input:"
  puts b
  puts
  puts "Output:"
  puts `echo "#{b}" | ruby fsm-golf.rb`
  puts "------"
end

输出

所有输入均以:

开头
S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2

Input: '1001010'
Output:
S1 1 -> S1
S1 0 -> s2
s2 0 -> S1
S1 1 -> S1
S1 0 -> s2
s2 1 -> s2
s2 0 -> S1
ACCEPT

Input: '101'
Output:
S1 1 -> S1
S1 0 -> s2
s2 1 -> s2
REJECT

Input: 'X10'
Output:
S1 X
REJECT

Input: ''
Output:
ACCEPT

Input: '10X'
Output:
S1 1 -> S1
S1 0 -> s2
s2 X
REJECT

答案 4 :(得分:5)

Adam提供了一个参考实现。我在制作之前没有看到它,但逻辑是相似的:

编辑:这是Python 2.6代码。我没有尽量减少长度;我只是试着让它在概念上变得简单。

import sys
a = sys.stdin.read().split('\n')
states = a[0].split()
transitions = a[1:-2]
input = a[-2]
statelist = {}
for state in states:
    statelist[state] = {}

for start, char, end in [x.split() for x in transitions]:
    statelist[start][char] = end

state = states[0]
for char in input:
    if char not in statelist[state]:
        print state,char
        print "REJECT"
        exit()
    newstate = statelist[state][char]
    print state, char, '->', newstate
    state = newstate
if state[0].upper() == state[0]:
    print "ACCEPT"
else:
    print "REJECT"

答案 5 :(得分:4)

Perl - 184个字符

(排除所有新行的计数,这是可选的。)

($s)=split' ',<>;$\=$/;
while(<>){chomp;$r{$_[1].$_[0]}=$_[2]if split>2;$t=$_}
$_=$t;
1 while$s&&s/(.)(.*)/print"$s $1",($s=$r{$1.$s})?" -> $s":"";$2/e;
print$s=~/^[A-Z]/?"ACCEPT":"REJECT"

此外,这个155个字符的程序不实现中间输出,而是完全执行机器作为整个FSM定义的重复替换(更改开始状态和输入字符串)。它的灵感来自于sed解决方案,但并非来自(?:...)解决方案。通过将(...)转换为$/="";$_=<>; 1 while s/\A(\S+)(?: +\S+)*\n(.*\n)?\1 +(.) +(.+)\n(.*\n)?\3([^\n]*)\n\z/$4\n$2$1 $3 $4\n$5$6\n/s; print/\A[A-Z].*\n\n\z/s?"ACCEPT\n":"REJECT\n" 并根据需要重新编号,可以缩短2个字符。

{{1}}

答案 6 :(得分:4)

MIXAL 898个字符

    ORIG    3910
A   ALF ACCEP
    ALF T    
    ORIG    3940
R   ALF REJEC
    ALF T    
    ORIG    3970
O   CON 0
    ALF ->   
    ORIG    3000
S   ENT6    0
T   IN  0,6(19)
    INC6    14
    JBUS    *(19)
    LDA -14,6
    JANZ    T
    LDA -28,6(9)
    DECA    30
    JAZ C
    DECA    1
    JANZ    B
C   LD2 0(10)
    ENT4    -28,6
    ENT5    9
D   JMP G
    ENT3    0
F   INC3    14
    LD1 0,3(10)
    DEC2    0,1
    J2Z M
    INC2    0,1
    DEC3    -28,6
    J3NN    U
    INC3    -28,6
    JMP F
M   INC2    0,1
    LD1 0,3(36)
    DECA    0,1
    JAZ H
    INCA    0,1
    JMP F
H   INCA    0,1
    ST2 O(10)
    LD2 1,3(10)
    STA O(36)
    ST2 O+1(37)
    OUT O(18)
    JBUS    *(18)
    JMP D
    HLT
E   LD1 0(10)
    DEC1    0,2
    J1Z B
U   OUT R(18)
    JBUS    *(18)
    HLT
B   OUT A(18)
    JBUS    *(18)
    HLT
G   STJ K
    ST5 *+1(36)
    LDA 0,4
    JAZ E
    DECA    30
    JAZ I
    DECA    1
    JANZ    W
    INCA    1
I   INCA    30
    DEC5    45
    J5NN    J
    INC5    54
    JMP K
J   INC4    1
    ENT5    9
K   JMP *
W   ST2 O(10)
    INCA    31
    STA O(36)
    STZ O+1
    OUT O(18)
    JBUS    *(18)
    JMP B
    END S

Deify Knuth!

答案 7 :(得分:4)

Python 3,Chars:203

输出格式似乎有点难以适应。

import sys
L=[i.split()for i in sys.stdin]
N,P=L[0][0],print
for c in L[-1]and L[-1][-1]:
 if N:O,N=N,{(i[0],i[1]):i[2]for i in L[1:-1]}.get((N,c),'');P(O,c,N and'-> '+N)
P(('REJECT','ACCEPT')[''<N<'_'])

答案 8 :(得分:4)

Haskell - 252 216 204 197 192个字符

s%(c:d,t)=s++' ':c:maybe('\n':x)(\[u]->" -> "++u++'\n':u%(d,t))(lookup[s,[c]]t)
s%_|s<"["="ACCEPT\n"|1<3=x
x="REJECT\n"
p(i:j)=(words i!!0)%(last j,map(splitAt 2.words)j)
main=interact$p.lines

符合输出规范。

Ungolf'd版本:

type State = String
type Transition = ((State, Char), State)

run :: [Transition] -> State -> String -> [String]
run ts s (c:cs) =  maybe notFound found $ lookup (s,c) ts
  where
    notFound =  stateText                 : ["REJECT"]
    found u  = (stateText ++ " -> " ++ u) : run ts u cs
    stateText = s ++ " " ++ [c]

run _ (s:_) "" | s >= 'A' && s <= 'Z' = ["ACCEPT"]
               | otherwise            = ["REJECT"]

prepAndRun :: [String] -> [String]
prepAndRun (l0:ls) = run ts s0 input
  where
    s0 = head $ words l0
    input = last ls
    ts = map (makeEntry . words) $ init ls
    makeEntry [s,(c:_),t] = ((s,c),t)

main' = interact $ unlines . prepAndRun . lines

一个很好的谜题是高尔夫版本中不需要init的原因!除此之外,休息都是标准的Haskell高尔夫技术。

答案 9 :(得分:4)

Python,218个字符

import sys
T=sys.stdin.read()
P=T.split()
S=P[0]
n="\n"
for L in P[-1]if T[-2]!=n else"":
 i=T.find(n+S+" "+L)
 if i<0:print S,L;S=n;break
 S=T[i:].split()[2];print S,L,"->",S
print ("REJECT","ACCEPT")[S[0].isupper()]

答案 10 :(得分:3)

Haskell - 189个字符

main=interact$r.lines
r f=g t z$last f where{(z:_):t=map words f;g _ s""|s<"["="ACCEPT\n";g([q,j,p]:_)s(i:k)|i:s==j++q=s++' ':i:" -> "++p++'\n':g t p k;g(_:y)s i=g y s i;g _ _ _="REJECT\n"}

编辑:没有正确实现无转换拒绝的输出。

换行版本和变量指南:

-- r: run FSM
-- f: fsm definition as lines
-- z: initial state

-- g: loop function
-- t: transition table
-- s: current state
-- i: current input
-- k: rest of input

-- q: transition table match state
-- j: transition table match input
-- p: transition table next state
-- y: tail of transition table

main=interact$r.lines;
r f=g t z$last f where{
(z:_):t=map words f;
g _ s""|s<"["="ACCEPT\n";
g([q,j,p]:_)s(i:k)|i:s==j++q=s++' ':i:" -> "++p++'\n':g t p k;
g(_:y)s i=g y s i;
g _ _ _="REJECT\n"}

我从MtnViewMark的解决方案中获得了s<"["技术;其余的是我自己的设计。显着特征:

  • 输入在转换表中保留为垃圾。只要输入不包含两个空格,这就没问题;但请注意,无论如何,过渡规则格式对空间角色的过渡都是不友好的。
  • 单步执行输入字符串并搜索转换表是相同的功能。
  • 两个REJECT案件都由同一个案件处理。

答案 11 :(得分:3)

Common Lisp - 725

(defun split (string)
  (loop for i = 0 then (1+ j)
     as j = (position #\Space string :start i)
     collect (subseq string i j)
     while j))

(defun do-fsm ()
  (let* ((lines (loop for l = (read-line *standard-input* nil)
      until (not l)
     collect (split l)))
  (cur (caar lines))
  (transitions (subseq lines 1 (- (length lines) 1))))
    (if (or (loop for c across (caar (last lines))
      do (format t "~a ~a" cur c)
        when (not (loop for tr in transitions
       when (and (equal cur (car tr))
          (equal c (char (cadr tr) 0)))
       return (progn (format t " -> ~a~%"
        (setq cur (caddr tr)))
       t)
         ))
        return t)
     (lower-case-p (char cur 0)))
 (format t "~%REJECT~%")
 (format t "ACCEPT~%"))))

没有真正尝试最小化代码 - Common Lisp在所需的输入处理中付出了沉重的代价,因此我认为此解决方案获胜的可能性不大:-)

答案 12 :(得分:2)

Rexx 205个字符

(这个答案经过了一些编辑,因为我最初发布的一些代码是为了普遍感兴趣,然后决定实际发布一个真正的解决方案)

这是一个Rexx版本,让人们领略那种鲜为人知的语言。 Rexx http://en.wikipedia.org/wiki/REXX是IBM的VM / CMS大型机操作系统中使用的解释语言,后来又在IBM OS / 2中使用(我相信有一个Amiga变体)。它是一种非常富有表现力的语言,是一种令人惊叹的通用/“脚本”语言。

Parse pull i .
d.='~'
Do until l='';Parse pull o l d.o.l;End
Do j=1 to LENGTH(o)
t=SUBSTR(o,j,1);p=i t;i=d.i.t
If i=d. then Do;Say p;Leave;End
Say p '->' i
End
Say WORD('ACCEPT REJECT',c2d(left(i,1))%32-1)

这可以使用Regina Rexx解释器运行。

使用其唯一输出处理不正确的转换方案并且还测试大写有点贵。

对于对Rexx语法感兴趣的人,下面的一些旧编辑的代码,那些不是100%符合输出要求但功能正常(此答案中的所有代码都适用于我粘贴在下面的示例,但上面的代码处理其他必要的角落):

较旧的简短版本:

Parse pull i .
Do until l = ""; Parse pull o l d; t.o.l = d; End
Do j=1 to LENGTH(o); t=substr(o,j,1); Say i t "->" t.i.t; i=t.i.t; End
If LEFT(i,1)='S' then Say 'ACCEPT'; else say 'REJECT'

更长的版本:

Parse pull initial . /* Rexx has a powerful built in string parser, this takes the first word into initial */

Do until letter = "" /* This style of do loops is a bit unusual, note how it doesn't matter that letter isn't defined yet */
  Parse pull origin letter destination /* Here we parse the inpt line into three words */
  transition.origin.letter = destination /* Rexx has a very powerful notion of associative containers/dictionaries, many years pre-Python */
End

/* Now we take the last line and iterate over the transitions */
Do i = 1 to LENGTH(origin) 
  t = substr(origin, i, 1) /* This is the actual letter using Rexx's string functions */
  Say initial t "->" transition.initial.t /* Say is like print */
  initial = transition.initial.t /* Perform the transition */
End

/* check for uppercase in the current state */
if left(initial, 1) = 'S' then Say 'ACCEPT'; else say 'REJECT'

样品进/出:

S1 s2
S1 0 s2
0
S1 0 -> s2
REJECT

S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
1001010
S1 1 -> S1
S1 0 -> s2
s2 0 -> S1
S1 1 -> S1
S1 0 -> s2
s2 1 -> s2
s2 0 -> S1
ACCEPT

答案 13 :(得分:2)

Ruby - 183

h={}
r=$<.read
t=s=r.split[0]
i=r[-1]=="
"?"":r.split[-1]
r.scan(/(\S+) (.) (.+)/){|a,b,c|h[[a,b]]=c}
i.chars{|c|puts s+" #{c} -> #{s=h[[s,c]]}"}
puts s&&s[/^[A-Z]/]?"ACCEPT":"REJECT"

真的,奇怪的输出规格。我的作品如何:http://ideone.com/cxweL

答案 14 :(得分:2)

Lua,356

为状态采用任何非空格字符,为过渡字母采用任何非空格字符。虽然看起来不是最短的,但我会以任何方式发布。 可以保存25个字符打印标签而不是空格。

可读版本:

i=io.read
p=print
S={}
i():gsub("(%S+)",function (a) f=f or a S[a]={} end )
l=i"*a"
for a,t,d in l:gmatch"(%S+) (%S) (%S+)"do
    S[a][t]=d
end
I=l:match"(%S+)%s$"or"" -- fixes empty input
function F(a,i)
    t=I:sub(i,i)
    if t==""then
        p"ACCEPT"
    elseif S[a][t] then
        p(("%s %s -> %s"):format(a,t, S[a][t]))
        return F( S[a][t],i+1)
    else
        if t~=""then p(a.." "..t)end p'REJECT'
    end
end
F(f,1)

高尔夫版+输出。

i=io.read p=print S={}i():gsub('(%S+)',function(a)f=f or a S[a]={}end)l=i'*a'for a,t,d in l:gmatch"(%S+) (%S) (%S+)"do S[a][t]=d end I=l:match'(%S+)%s$'or''function F(a,i)t=I:sub(i,i)if t==""and a:match'^%u'then p'ACCEPT'elseif S[a][t]then p(('%s %s -> %s'):format(a,t,S[a][t]))return F(S[a][t],i+1)else if t~=''then p(a.." "..t)end p'REJECT'end end F(f,1)
-- input --
A B C   
A B B
A C C
A A A
B A A 
B B B
B C C
C A A 
C B B
C C C
AABCCBCBAX
-- output --

A A -> A
A A -> A
A B -> B
B C -> C
C C -> C
C B -> B
B C -> C
C B -> B
B A -> A
REJECT

答案 15 :(得分:2)

bash - 186 185 184 chars

declare -A a
read s x
while read f m t&&[ $m ];do a[$f $m]=$t;done
for((i=0;i-${#f};i++))do b="$s ${f:i:1}";s=${a[$b]};echo $b -\> $s;done
[ "$s" = "${s,}" ]&&echo REJECT||echo ACCEPT

请注意,这实际上需要bash - POSIX sh没有关联数组或C语言的语法(并且可能没有使用所有参数扩展,虽然我没有检查过)。

编辑:或者,对于完全相同的长度,

declare -A a
read s x
while read f m t&&[ $m ];do a[$f $m]=$t;done
while [ $f ];do b="$s ${f:i:1}";f=${f:1};s=${a[$b]};echo $b -\> $s;done
[ "$s" = "${s,}" ]&&echo REJECT||echo ACCEPT

答案 16 :(得分:0)

Lua - 248 227

r=...
p=print
M={}
s=r:match('(%a%d)')
for i,n,o in r:gmatch('(%a%d)%s(%d)%s(%a%d)')do
M[i]=M[i]or{}
M[i][n]=o
end
for c in r:match('%d%d+'):gmatch('(%d)')do
z=s
s=M[z][c]
p(z,c,'->',s)
end
p(s==s:upper()and'ACCEPT'or'REJECT')

检查codepad old version

上的正在运行的版本

答案 17 :(得分:0)

C# - 453 375 353 345个字符

这不会赢(不是任何人都应该期待的),但无论如何写它很有趣。我保留了可读性的主要空间和换行符:

using System;
class P
{
  static void Main()
  {
    string c,k="";
    var t=new string[99999][];
    int p=-1,n;
    while((c=Console.ReadLine())!="")
      t[++p]=c.Split(' ');

    c=t[0][0];
    foreach(var d in t[p][0]){
      k+=c+' '+d;
      for(n=1;n<p;n++)
        if(c==t[n][0]&&d==t[n][1][0])
      {
        c=t[n][2];
        k+=" -> "+c;
        break;
      }
      k+="\n";
      if(n==p){
        c="~";
        break;
      }
    }
    Console.Write(k+(c[0]>'Z'?"REJECT":"ACCEPT"));
  }
}

在我的上一次更新中,通过假设输入行数(即99,999)的实际限制,我能够保存22个字符。在最坏的情况下,你需要将其增加到最大值为2,147,483,647的Int32,这将增加5个字符。虽然我的机器不喜欢阵列的想法......

执行的一个例子:

>FSM.exe
S1 s2
S1 0 s2
S1 1 S1
s2 0 S1
s2 1 s2
1001010

S1 1 -> S1
S1 0 -> s2
s2 0 -> S1
S1 1 -> S1
S1 0 -> s2
s2 1 -> s2
s2 0 -> S1
ACCEPT

答案 18 :(得分:0)

F#420

我认为对于不变的高尔夫来说并不坏。我今天在课程上做得不是很好。

open System
let f,p,a=Array.fold,printf,Map.add
let l=Console.In.ReadToEnd().Split '\n'
let e,s=l.Length,l.[0].Split ' '
let t,w=Map.ofList[for q in s->q,Map.empty],[|"ACCEPT";"REJECT"|]
let m=f(fun t (r:String)->let s=r.Split ' 'in a s.[0](t.[s.[0]]|>a s.[1].[0]s.[2])t)t l.[1..e-2]
try let r=l.[e-1].ToCharArray()|>f(fun s c->p"%s %c "s c;let n=m.[s].[c]in p"-> %s\n"n;n)s.[0]in p"%s"w.[int r.[0]/97]with|_->p"%s"w.[1]

未打高尔夫的F#33行。在我打完高尔夫球之后,我会再次更新。

open System

let input = Console.In.ReadToEnd()
//let input = "S1 s2\nS1 0 s2\nS1 1 S1\ns2 0 S1\ns2 1 s2\n1001010"
let lines = input.Split '\n'
let length = lines.Length
let states = lines.[0].Split ' '

let stateMap = Map.ofList [for state in states -> (state, Map.empty)]

let folder stateMap (line:String) =
    let s = line.Split ' '
    stateMap |> Map.add s.[0] (stateMap.[s.[0]] |> Map.add s.[1].[0] s.[2])

let machine = Array.fold folder stateMap lines.[1 .. (length-2)]

let stateMachine state char =
    printf "%s %c " state char
    let newState = machine.[state].[char]
    printfn "-> %s" newState
    newState

try
    let result = 
        lines.[length-1].ToCharArray()
        |> Array.fold stateMachine states.[0]

    if Char.IsUpper result.[0] then
        printf "ACCEPT"
    else
        printf "REJECT"
with
    | _ -> printf "REJECT"

答案 19 :(得分:0)

Python(2.6)~269个字符。

可能还有改进的余地,暗示欢迎。 处理我认为的规格。

import sys;a=sys.stdin.readlines();b=a[0].split()
f=b[0];d=dict((x,{})for x in b);s=''
for x,y,z in map(str.split,a[1:-1]):d[x][y]=z
for g in a[-1]:
 try:s+=f+' '+g;f=d[f][g];s+=' -> '+f+'\n'
 except:s+='\n';break
print s+("REJECT","ACCEPT")[ord(f[0])<90 and g in d[f]]