代码高尔夫:有限状态机!

发布于 2024-10-11 15:40:26 字数 6001 浏览 5 评论 0原文

有限状态机

确定性有限状态机是一种简单的计算模型,在计算机科学基础课程中广泛用作自动机理论的介绍。它是一个简单的模型,相当于正则表达式,它确定某个输入字符串是接受还是拒绝抛开一些形式,有限状态机的运行由以下部分组成:

  1. 字母表,一组字符。
  2. 状态,通常显示为圆圈。其中一个状态必须是开始状态。有些状态可能接受,通常显示为双圆圈。
  3. 转换通常被可视化为状态之间的有向拱门,是与字母相关的状态之间的有向链接。
  4. 输入字符串字母字符列表。

机器上的运行从启动状态开始。读取输入字符串的每个字母;如果当前状态和与该字母对应的另一个状态之间存在转换,则当前状态更改为新状态。读完最后一个字母后,如果当前状态为接受状态,则接受输入字符串。如果最后一个状态不是接受状态,或者字母在运行期间没有对应的状态,则输入字符串将被拒绝。

注意:这个简短的解释远不是 FSM 的完整、正式的定义; 维基百科的优秀文章对该主题进行了精彩的介绍。

示例

例如,以下机器判断从左到右读取的二进制数是否有偶数个 0

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. 输入字符串是任何二进制数,包括空字符串。

规则:

用您选择的语言实现 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 的运行,写为 <信> ->,后跟最终状态。示例输入的输出为:

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 行(显示第一个state) 可能会被省略,并且以下输出也是可以接受的:

ACCEPT

For 101:

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

For '10X':

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

奖品

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

参考实现

参考 Python 实现可在此处获取。请注意,对于空字符串输入,输出要求已放宽。

附录

输出格式

根据流行的需求,对于空输入字符串,以下输出也是可以接受的:

ACCEPT

REJECT

没有在前一行中写入第一个状态。

状态名称

有效的状态名称是一个英文字母,后跟任意数量的字母、_ 和数字,非常类似于变量名称,例如 State1state0STATE_0

输入格式

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

答案摘要:

sed 137 解决方案是最短的,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

所以除非有澄清,否则赏金将归于 ruby​​ 解决方案。

Finite state machine

A deterministic finite state machine is a simple computation model, widely used as an introduction to automata theory in basic CS courses. It is a simple model, equivalent to regular expression, which determines of a certain input string is Accepted or Rejected. Leaving some formalities aside, A run of a finite state machine is composed of:

  1. alphabet, a set of characters.
  2. states, usually visualized as circles. One of the states must be the start state. Some of the states might be accepting, usually visualized as double circles.
  3. transitions, usually visualized as directed arches between states, are directed links between states associated with an alphabet letter.
  4. input string, a list of alphabet characters.

A run on the machine begins at the starting state. Each letter of the input string is read; If there is a transition between the current state and another state which corresponds to the letter, the current state is changed to the new state. After the last letter was read, if the current state is an accepting state, the input string is accepted. If the last state was not an accepting state, or a letter had no corresponding arch from a state during the run, the input string is rejected.

Note: This short descruption is far from being a full, formal definition of a FSM; Wikipedia's fine article is a great introduction to the subject.

Example

For example, the following machine tells if a binary number, read from left to right, has an even number of 0s:

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

  1. The alphabet is the set {0,1}.
  2. The states are S1 and S2.
  3. The transitions are (S1, 0) -> S2, (S1, 1) -> S1, (S2, 0) -> S1 and (S2, 1) -> S2.
  4. The input string is any binary number, including an empty string.

The rules:

Implement a FSM in a language of your choice.

Input

The FSM should accept the following input:

<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.

For example, the aforementioned machine with 1001010 as an input string, would be written as:

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

Output

The FSM's run, written as <State> <letter> -> <state>, followed by the final state. The output for the example input would be:

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

For the empty input '':

S1
ACCEPT

Note: Following your comments, the S1 line (showing the first state) might be omitted, and the following output is also acceptable:

ACCEPT

For 101:

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

For '10X':

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

Prize

A 250 rep bounty will be given to the shortest solution.

Reference implementation

A reference Python implementation is available here. Note that output requirements have been relaxed for empty-string input.

Addendum

Output format

Following popular demand, the following output is also acceptable for empty input string:

ACCEPT

or

REJECT

Without the first state written in the previous line.

State names

Valid state names are an English letter followed by any number of letters, _ and digits, much like variable names, e.g. State1, state0, STATE_0.

Input format

Like most code golfs, you can assume your input is correct.

Summary of answers:

The sed 137 solution is the shortest, ruby 145 is #2. Currently, I can't get the sed solution to work:

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

both gave me:

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

so unless It there are clarifications the bounty goes to the ruby solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

箜明 2024-10-18 15:40:26

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

PS。问题得到缓解后(不需要在空输入上输出状态行),这里是明显更短的新代码。如果您使用的是 <2.7 版本,则没有字典理解,因此应使用 {c+o:s for o,c,s in i[1:-1]}< /code> 尝试 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]

在有人因此打我之前,我想道歉:代码行为与原始规范略有不同 - 每个问题评论讨论。这是我为讨论而做的例证。

附言。虽然我喜欢决议接受/拒绝与最终状态在同一行,但它可以通过添加 让我转移到孤独(例如想象结果将由只关心最后一行被接受或拒绝的愚蠢脚本解析) '\n'+(5 个字符)到最后一个打印,价格为 +5 个字符。

输出示例:

# for empty input
S1  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
S1  ACCEPT

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

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

# for input 'X10'
S1 X REJECT

Python 2.7+, 201 192 187 181 179 175 171 chars

PS. After the problem was relaxed (no need to output state line on empty input), here is new code that's notably shorter. If you are on version <2.7, there is no dict comprehension, so instead of {c+o:s for o,c,s in i[1:-1]} try dict((c+o,s)for o,c,s in i[1:-1]) for the price of +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]

And its test output:

# 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

Previous entry (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]

I want to apologize before someone slaps me for it: the code behavior is slightly different from the original spec - per question-comments discussion. This is my illustration for the discussion.

PS. while i like the resolution ACCEPT/REJECT on the same line with the final state, it can me moved to solitude (e.g. imagine results are to be parsed by stupid script that only cares about last line being accept or reject) by adding '\n'+ (5 chars) to the last print for the price of +5 chars.

Example output:

# for empty input
S1  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
S1  ACCEPT

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

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

# for input 'X10'
S1 X REJECT
幸福还没到 2024-10-18 15:40:26

今天我感觉很复古,我为这项任务选择的语言是 IBM Enterprise Cobol - 字符计数 2462 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.    

I'm feeling retro today, my language of choice for this task is IBM Enterprise Cobol - char count 2462 4078 (Sorry, pasted from a screen oriented device, trailing spaces are a tragic side effect):

 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.    
落在眉间の轻吻 2024-10-18 15:40:26

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

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

sed -- 118 137 characters

This is using the -r flag (+3), for a total of 134+3=137 characters.

$!{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

This should handle inputs without transitions correctly... hopefully it fully complies with the spec now...

迷爱 2024-10-18 15:40:26

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

h={}
o=s=p
lt;.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

Ruby 1.9.2 - 178 190 182 177 153 161 158 154 145 characters

h={}
o=s=p
lt;.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

Testing Script

[
  "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

Outputs

All input starts with:

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
妄司 2024-10-18 15:40:26

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"

Adam provided a reference implementation. I didn't see it before I made mine, but the logic is similar:

Edit: This is Python 2.6 code. I did not try to minimize length; I just tried to make it conceptually simple.

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"
魂ガ小子 2024-10-18 15:40:26

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()]

Python, 218 characters

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()]
浊酒尽余欢 2024-10-18 15:40:26

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

一个很好的谜题是为什么在 Golf'd 版本中不需要 init!除此之外,休息都是标准的哈斯克尔高尔夫技巧。

Haskell - 252 216 204 197 192 characters

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

Conforms to output specification.

Ungolf'd version:

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

A good puzzle is why init isn't needed in the golf'd version! Other than that, rest are all standard Haskell golf techniques.

長街聽風 2024-10-18 15:40:26

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 解决方案的启发,但并非源自该解决方案。通过将 (?:...) 转换为 (...) 并根据需要重新编号,可以将其缩短 2 个字符。

$/="";$_=<>;
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"

Perl — 184 characters

(Count excluding all newlines, which are optional.)

($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"

Also, this 155-character program does not implement the intermediate outputs, but executes the machine entirely as a repeated substitution on the whole FSM definition (changing the start state and input string). It was inspired by, but not derived from, the sed solution. It could be shortened by 2 characters by converting the (?:...) into a (...) and renumbering as needed.

$/="";$_=<>;
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"
澜川若宁 2024-10-18 15:40:26

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<'_'])

Python 3, Chars: 203

The output format seems a bit hard to fit.

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<'_'])
若无相欠,怎会相见 2024-10-18 15:40:26

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

神化 Knuth!

MIXAL 898 characters

    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!

最后的乘客 2024-10-18 15:40:26

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 情况均由相同的失败处理。

Haskell - 189 characters

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"}

EDIT: Does not correctly implement the output for no-transition rejection.

Line-broken version and variable guide:

-- 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"}

I got the s<"[" technique from MtnViewMark's solution; the rest is my own design. Notable characteristics:

  • The input is left as junk in the transition table. This is OK as long as the input does not contain two spaces; but note that the transition rule format is arguably unfriendly to transitioning on the space character anyway.
  • Stepping through the input string and searching the transition table are the same function.
  • Both REJECT cases are handled by the same fallthrough.
街角卖回忆 2024-10-18 15:40:26

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 在所需的输入处理中付出了沉重的代价,所以我认为这个解决方案获胜的机会不大:-)

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~%"))))

No real attempt to minimize the code -- Common Lisp pays a heavy penalty in the required input processing, so I don't think there's much chance of this solution winning :-)

生死何惧 2024-10-18 15:40:26

Ruby — 183

h={}
r=
lt;.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

Ruby — 183

h={}
r=
lt;.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"

Really, strange output specification. Here how my works: http://ideone.com/cxweL

幻想少年梦 2024-10-18 15:40:26

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

Rexx 205 characters

(This answer went through few edits as I initially just posted some code for general interest and then decided to actually post a real solution)

Here's a Rexx version to give people a taste for that less known lanugage. Rexx http://en.wikipedia.org/wiki/REXX is an interpreted language used in IBM's VM/CMS mainframe operating system and later in IBM OS/2 (and I believe there was an Amiga variant). It's a very expressive language and an amazing general purpose/"scripting" language.

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)

This can be run with the Regina Rexx interpreter.

Handling the incorrect transition scenario with its unique output and also testing for uppercase is a bit expensive.

Code from some older edits below for people interested in the Rexx syntax, those aren't 100% compliant with the output requirements but are functional (all code in this answer works with the samples I pasted below but the code above handles the other required corners):

Older short version:

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'

Longer version:

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'

Sample in/out:

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
孤云独去闲 2024-10-18 15:40:26

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

Lua, 356

Takes any nonspace characters for states, and any non-space one characters for transition letters. Though it seems not shortest, I'll post it any way.
Could save 25 chars printing tabs instead of spaces.

Readable version:

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)

Golfed version + in- an output.

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
执妄 2024-10-18 15:40:26

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

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

Note that this does actually require bash - POSIX sh doesn't have associative arrays or the C-style for syntax (and probably doesn't have all the parameter expansions used either, although I haven't checked).

Edit: alternatively, for the exact same length,

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
此岸叶落 2024-10-18 15:40:26

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]]

Python (2.6) ~ 269 characters.

Probably still room for improvement, hints welcome.
Handles specifications I think.

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]]
萤火眠眠 2024-10-18 15:40:26

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')

检查 键盘 上的运行版本 旧版本

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')

check running version on codepad old version

触ぅ动初心 2024-10-18 15:40:26

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"

F# 420

Not bad for immutable golf I think. I didn't do very good on the course today though.

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]

33 lines for un-golfed F#. I'll update again in a bit after I've golfed.

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"
避讳 2024-10-18 15:40:26

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 个字符。在最坏的情况下,您需要将其增加到 Int32 最大值 2,147,483,647,这将添加 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

C# - 453 375 353 345 characters

This doesn't win (not that anyone should have expected it to), but it was fun to write anyway. I kept the leading spaces and newlines for legibility:

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"));
  }
}

In my last update I was able to save 22 characters by assuming a practical limit to the number of input rows (namely 99,999). In the worst case, you'd need to up that to the Int32 max of 2,147,483,647 which would add 5 chars. My machine doesn't like the idea of an array that long though...

An example of the execution:

>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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文