Puzzle 代码:自动机

Puzzle 代码:自动机,puzzle,code-golf,rosetta-stone,automata,Puzzle,Code Golf,Rosetta Stone,Automata,我用这些规则创造了终极的笑声发生器。你能用你最喜欢的语言巧妙地实现它吗 规则: 在每次迭代中,都会发生以下转换 H -> AH A -> HA AA -> HA HH -> AH AAH -> HA HAA -> AH 这是一个非常简单的C++版本: #include <iostream> #include <sstream> using namespace std; #define LINES 10 #define

我用这些规则创造了终极的笑声发生器。你能用你最喜欢的语言巧妙地实现它吗

规则: 在每次迭代中,都会发生以下转换

H   -> AH
A   -> HA
AA  -> HA
HH  -> AH
AAH -> HA
HAA -> AH


这是一个非常简单的C++版本:

#include <iostream>
#include <sstream>
using namespace std;

#define LINES 10

#define put(t) s << t; cout << t

#define r1(o,a,c0) \
    if(c[0]==c0) {put(o); s.unget(); s.unget(); a; continue;}
#define r2(o,a,c0,c1) \
    if(c[0]==c0 && c[1]==c1) {put(o); s.unget(); a; continue;}
#define r3(o,a,c0,c1,c2) \
    if(c[0]==c0 && c[1]==c1 && c[2]==c2) {put(o); a; continue;}

int main() {
    char c[3];
    stringstream s;
    put("H\n\n");
    for(int i=2;i<LINES*2;) {
        s.read(c,3);
        r3("AH",,'H','A','A');
        r3("HA",,'A','A','H');
        r2("AH",,'H','H');
        r2("HA",,'A','A');
        r1("HA",,'A');
        r1("AH",,'H');
        r1("\n",i++,'\n');
    }
}

Haskell的简单翻译:

grammar = iterate step
    where
        step ('H':'A':'A':xs) = 'A':'H':step xs
        step ('A':'A':'H':xs) = 'H':'A':step xs
        step ('A':'A':xs) = 'H':'A':step xs
        step ('H':'H':xs) = 'A':'H':step xs
        step ('H':xs) = 'A':'H':step xs
        step ('A':xs) = 'H':'A':step xs
        step [] = []
以及一个较短的版本(122个字符,优化为三个派生规则+基本情况):

和C++的转换(182字符,只需一次迭代,在命令行中调用初始状态):

#包括
#定义putchar
int main(int,char**v){char*p=v[1];while(*p){p[1]==65&&~*p&p[2]?o(p[2]),o(*p),p+=3:*p==p[1]?o(137-*p++),o(*p++),p:(o(137-*p),o(*p++),p);}返回0;}
MATLAB(v7.8.0): 73个字符(不包括用于使其看起来可读的格式化字符)

此脚本(“haha.m”)假设您已经定义了变量n

s = 'H';
for i = 1:n,
  s = regexprep(s,'(H)(H|AA)?|(A)(AH)?','${[137-$1 $1]}');
end
…以下是一行版本:

s='H';for i=1:n,s = regexprep(s,'(H)(H|AA)?|(A)(AH)?','${[137-$1 $1]}');end
#include <stdio.h>
#include <string.h>
char s[99] = "H", t[99] = {0};
int main()
{
    for(int n = 0; n < 10; n++)
      {
        int i = 0, j = strlen(s);
        printf("n = %u |  %s\n", n, s);
        strcpy(t, s);
        s[0] = 0;
        /*
         * This was originally just a while() loop.
         * I tried to make it shorter by making it a for() loop.
         * I failed.
         * I kept the for() loop because it looked uglier than a while() loop.
         * This is code golf.
         */
        for(;i<j;)
          {
            if(t[i++] == 'H' )
              {
                // t[i] == 'H' ? i++ : t[i+1] == 'A' ? i+=2 : 1;
                // Oh, ternary ?:, how do I love thee?
                if(t[i] == 'H')
                    i++;
                else if(t[i+1] == 'A')
                    i+= 2;
                strcat(s, "AH");
              }
            else
              {
                // t[i] == 'A' ? i += 1 + (t[i + 1] == 'H') : 1;
                if(t[i] == 'A')
                    if(t[++i] == 'H')
                        i++;
                strcat(s, "HA");
              }
          }
      }
    return 0;
}
测试:

>> for n=0:10, haha; disp([num2str(n) ': ' s]); end
0: H
1: AH
2: HAAH
3: AHAH
4: HAAHHAAH
5: AHAHHA
6: HAAHHAAHHA
7: AHAHHAAHHA
8: HAAHHAAHHAAHHA
9: AHAHHAAHAHHA
10: HAAHHAAHHAHAAHHA
Perl
168个字符。 (不包括不必要的换行)

消除混淆:
Perl
150个字符。 (不包括不必要的换行)

消除模糊 Lex/Flex 69个字符。在这里的文本中,我将制表符改为8个空格,这样看起来就对了,但是所有这些连续的空格都应该是制表符,制表符很重要,所以总共有69个字符

        #include <stdio.h>
%%
HAA|HH|H        printf("AH");
AAH|AA|A        printf("HA");
这会进行多次迭代(与上一次不同,上一次只进行了一次迭代,每次都必须手动设定种子,但会产生正确的结果),并且具有非常可怕的代码的优势。我使用一个函数宏、字符串化操作符和两个全局变量。如果您想要一个更混乱的版本,它甚至不检查
malloc()
失败,它看起来像这样(282个字符):

我的首选是最有效的(即第一个可以迭代直到内存耗尽并检查其错误的),但这是代码高尔夫

要编译第一个,请键入:

flex golf.l
gcc -ll lex.yy.c
(如果您使用的是
lex
而不是
flex
,只需将
flex
更改为
lex
。它们应该是兼容的。)

要编译其他文件,请键入:

flex golf.l
gcc -std=c99 lex.yy.c
否则,GCC将抱怨C99模式之外使用的循环初始声明和其他废话

下面是纯C答案。

Javascript: 120剥离空白,我现在就不管它了

function f(n,s){s='H';while(n--){s=s.replace(/HAA|AAH|HH?|AA?/g,function(a){return a.match(/^H/)?'AH':'HA'});};return s}
扩大:

function f(n,s)
{
    s = 'H';
    while (n--)
    {
        s = s.replace(/HAA|AAH|HH?|AA?/g, function(a) { return a.match(/^H/) ? 'AH' : 'HA' } );
    };
    return s
}
那个替代品很贵

ANSI C99 以306个字符的速度出现:

        char*c,*t;
        #define s(a) t=c?realloc(c,strlen(c)+3):calloc(3,1);if(t)c=t,strcat(c,#a);
%%
        free(c);c=NULL;
HAA|HH|H        s(AH)
AAH|AA|A        s(HA)
%%
int main(void){c=calloc(2,1);if(!c)return 1;*c='H';for(int n=0;n<10;n++)printf("n = %d |  %s\n",n,c),yy_scan_string(c),yylex();return 0;}int yywrap(){return 1;}
        char*c,*t;
        #define s(a) t=c?realloc(c,strlen(c)+3):calloc(3,1);c=t;strcat(c,#a);
%%
        free(c);c=NULL;
HAA|HH|H        s(AH)
AAH|AA|A        s(HA)
%%
int main(void){c=calloc(2,1);*c='H';for(int n=0;n<10;n++)printf("n = %d |  %s\n",n,c),yy_scan_string(c),yylex();return 0;}int yywrap(){return 1;}
#include <stdio.h>
#include <string.h>
char s[99]="H",t[99]={0};int main(){for(int n=0;n<10;n++){int i=0,j=strlen(s);printf("n = %u |  %s\n",n,s);strcpy(t,s);s[0]=0;for(;i<j;){if(t[i++]=='H'){t[i]=='H'?i++:t[i+1]=='A'?i+=2:1;strcat(s,"AH");}else{t[i]=='A'?i+=1+(t[i+1]=='H'):1;strcat(s,"HA");}}}return 0;}
return new Regex("HAA|AAH|HH|AA|A|H").Replace(i,m =>(String)new Hashtable{{"H","AH"},{"A","HA"},{"AA","HA"},{"HH","AH"},{"AAH","HA"},{"HAA","AH"}}[m.Value]);
a='h';n.times{puts a.gsub!(/(h(h|aa)?)|(a(ah?)?)/){$1.nil?? "ha":"ah"}}
#包括
#包括
字符s[99]=“H”,t[99]=“0};int main(){for(int n=0;n这里有一个C#示例,如果我将每个项之间的空格减少到一个空格,则会得到321字节

编辑:作为对评论的回应,我从解决方案中删除了泛型以寻找更多的字节

编辑:另一个更改,删除了所有临时变量

public static String E(String i)
{
    return new Regex("HAA|AAH|HH|AA|A|H").Replace(i, 
        m => (String)new Hashtable {
            { "H", "AH" },
            { "A", "HA" },
            { "AA", "HA" },
            { "HH", "AH" },
            { "AAH", "HA" },
            { "HAA", "AH" }
        }[m.Value]);
}
重写后的解决方案的空白更少,但仍然可以编译,其长度为158个字符:

        char*c,*t;
        #define s(a) t=c?realloc(c,strlen(c)+3):calloc(3,1);if(t)c=t,strcat(c,#a);
%%
        free(c);c=NULL;
HAA|HH|H        s(AH)
AAH|AA|A        s(HA)
%%
int main(void){c=calloc(2,1);if(!c)return 1;*c='H';for(int n=0;n<10;n++)printf("n = %d |  %s\n",n,c),yy_scan_string(c),yylex();return 0;}int yywrap(){return 1;}
        char*c,*t;
        #define s(a) t=c?realloc(c,strlen(c)+3):calloc(3,1);c=t;strcat(c,#a);
%%
        free(c);c=NULL;
HAA|HH|H        s(AH)
AAH|AA|A        s(HA)
%%
int main(void){c=calloc(2,1);*c='H';for(int n=0;n<10;n++)printf("n = %d |  %s\n",n,c),yy_scan_string(c),yylex();return 0;}int yywrap(){return 1;}
#include <stdio.h>
#include <string.h>
char s[99]="H",t[99]={0};int main(){for(int n=0;n<10;n++){int i=0,j=strlen(s);printf("n = %u |  %s\n",n,s);strcpy(t,s);s[0]=0;for(;i<j;){if(t[i++]=='H'){t[i]=='H'?i++:t[i+1]=='A'?i+=2:1;strcat(s,"AH");}else{t[i]=='A'?i+=1+(t[i+1]=='H'):1;strcat(s,"HA");}}}return 0;}
return new Regex("HAA|AAH|HH|AA|A|H").Replace(i,m =>(String)new Hashtable{{"H","AH"},{"A","HA"},{"AA","HA"},{"HH","AH"},{"AAH","HA"},{"HAA","AH"}}[m.Value]);
a='h';n.times{puts a.gsub!(/(h(h|aa)?)|(a(ah?)?)/){$1.nil?? "ha":"ah"}}
对于VisualStudio2008的完整源代码解决方案,下面提供了包含必要代码(包括单元测试)的subversion存储库

,用户名和密码都是“guest”,没有引号。

在python中:

def l(s):
 H=['HAA','HH','H','AAH','AA','A']
 L=['AH']*3+['HA']*3
 for i in [3,2,1]:
  if s[:i] in H: return L[H.index(s[:i])]+l(s[i:])
 return s

def a(n,s='H'):
 return s*(n<1)or a(n-1,l(s))

for i in xrange(0,10):
 print '%d: %s'%(i,a(i))
def l(s):
H=['HAA','HH','H','AAH','AA','A']
L=['AH']*3+['HA']*3
对于[3,2,1]中的i:
如果H中的s[:i]:返回L[H.索引(s[:i])]+L(s[i:]
返回s
定义a(n,s='H'):
返回s*(nRuby
这段代码并没有很好地指定——我假设返回第n个迭代字符串的函数是解决它的最佳方法。它有80个字符

def f n
a='h'
n.times{a.gsub!(/(h(h|aa)?)|(a(ah?)?)/){$1.nil?? "ha":"ah"}}
a
end
打印出n个前字符串(71个字符)的代码:


Erlang

241字节,准备运行:

> erl -noshell -s g i -s init stop
AHAHHAAHAHHA

-module(g).
-export([i/0]).
c("HAA"++T)->"AH"++c(T);
c("AAH"++T)->"HA"++c(T);
c("HH"++T)->"AH"++c(T);
c("AA"++T)->"HA"++c(T);
c("A"++T)->"HA"++c(T);
c("H"++T)->"AH"++c(T);
c([])->[].
i(0,L)->L;
i(N,L)->i(N-1,c(L)).
i()->io:format(i(9,"H"))
可能会有所改进。

Python(150字节) 输出 n=0 | H n=1 |啊 n=2 |哈 n=3 |啊哈 n=4 |哈哈哈 n=5 | ahaha n=6 |哈哈哈 n=7 |啊哈啊哈 n=8 |哈哈哈哈哈 n=9 |哈哈哈哈哈
REBOL,150个字符。不幸的是,REBOL不是一种有助于编码高尔夫的语言,但正如亚当·桑德勒所说,150个字符并不太寒酸

这假设已经定义了循环变量
m

s: "H" r: "" z:[some[["HAA"|"HH"|"H"](append r "AH")|["AAH"|"AA"|"A"](append r "HA")]to end]repeat n m[clear r parse s z print["n =" n "|" s: copy r]] s:“H”r:“z:[一些[“HAA”|“HH”|“H”](附加r“AH”)|[“AAH”|“AA”|“A”](附加r“HA”)]结束]重复n m[清除r解析s z打印[“n=”n“|”s:复制r]] 这里有更好的布局:

s: "H" r: "" z: [ some [ [ "HAA" | "HH" | "H" ] (append r "AH") | [ "AAH" | "AA" | "A" ] (append r "HA") ] to end ] repeat n m [ clear r parse s z print ["n =" n "|" s: copy r] ] s:“H” r:“” z:[ 一些[ [“HAA”|“HH”|“H”](附加r“AH”) |[“啊”|“AA”|“A”](附加r“HA”) ] 结束 ] 重复n-m[ 清除r 解析sz 打印[“n=”n“|”s:copy r] ] F#:184个字符

似乎很清楚地映射到F#:

以下是fsi中的运行:

> [for a in 0 .. 9 -> a, laugh(a, [H])] |> Seq.iter (fun (a, b) -> printfn "n = %i: %A" a b);;
n = 0: [H]
n = 1: [A; H]
n = 2: [H; A; A; H]
n = 3: [A; H; A; H]
n = 4: [H; A; A; H; H; A; A; H]
n = 5: [A; H; A; H; H; A]
n = 6: [H; A; A; H; H; A; A; H; H; A]
n = 7: [A; H; A; H; H; A; A; H; H; A]
n = 8: [H; A; A; H; H; A; A; H; H; A; A; H; H; A]
n = 9: [A; H; A; H; H; A; A; H; A; H; H; A]

我不知道,但我很惊讶它竟然被关闭了,因为有一大堆相同的“代码高尔夫”一个。我不知道,但为什么这些没有关闭?@Zifre,我个人很想看看这是如何在几种语言中以紧凑的方式完成的。我正在使用lex想出一个奇怪的解决方案。我真的希望在我完成它之前不会关闭它。+1这很有趣,我很高兴boredI打算用lex/C以类似的方式来完成它(我认为这更容易),但实际上这在C++中是非常简单的,有几个宏。我的目标是最小化最小值:)我必须承认我不熟悉Lex,所以我想知道)你的代码是如何通过初始化字符串到“H”和B来开始的。如何让它停止在给定的n?我很懒-代码只进行一次迭代。我很快会想出如何编写更好的版本,但现在你输入“H”,它会吐出“AH”,然后你输入“AH”,它会吐出“HAAH”,等等。我会在某个时候用合适的解决方案进行编辑,这非常复杂。无论如何,要编译这段代码,键入“flex file.l”,它将生成文件“lex.yy.c”。用c编译器编译它,并链接到lex库(很可能是libl.a)这似乎是到目前为止我接受的最短的一个。我从来不知道matlab代码可以如此浓缩。我投票给了所有有过它的人
> erl -noshell -s g i -s init stop
AHAHHAAHAHHA

-module(g).
-export([i/0]).
c("HAA"++T)->"AH"++c(T);
c("AAH"++T)->"HA"++c(T);
c("HH"++T)->"AH"++c(T);
c("AA"++T)->"HA"++c(T);
c("A"++T)->"HA"++c(T);
c("H"++T)->"AH"++c(T);
c([])->[].
i(0,L)->L;
i(N,L)->i(N-1,c(L)).
i()->io:format(i(9,"H"))
import re
N = 10
s = "H"
for n in range(N):
    print "n = %d |"% n, s
    s = re.sub("(HAA|HH|H)|AAH|AA|A", lambda m: m.group(1) and "AH" or "HA",s)
n = 0 | H n = 1 | AH n = 2 | HAAH n = 3 | AHAH n = 4 | HAAHHAAH n = 5 | AHAHHA n = 6 | HAAHHAAHHA n = 7 | AHAHHAAHHA n = 8 | HAAHHAAHHAAHHA n = 9 | AHAHHAAHAHHA s: "H" r: "" z:[some[["HAA"|"HH"|"H"](append r "AH")|["AAH"|"AA"|"A"](append r "HA")]to end]repeat n m[clear r parse s z print["n =" n "|" s: copy r]] s: "H" r: "" z: [ some [ [ "HAA" | "HH" | "H" ] (append r "AH") | [ "AAH" | "AA" | "A" ] (append r "HA") ] to end ] repeat n m [ clear r parse s z print ["n =" n "|" s: copy r] ]
type grammar = H | A
let rec laugh = function
    | 0,l -> l
    | n,l ->
        let rec loop = function
            |H::A::A::x|H::H::x|H::x->A::H::loop x
            |A::A::H::x|A::A::x|A::x->H::A::loop x
            |x->x
        laugh(n-1,loop l)
> [for a in 0 .. 9 -> a, laugh(a, [H])] |> Seq.iter (fun (a, b) -> printfn "n = %i: %A" a b);;
n = 0: [H]
n = 1: [A; H]
n = 2: [H; A; A; H]
n = 3: [A; H; A; H]
n = 4: [H; A; A; H; H; A; A; H]
n = 5: [A; H; A; H; H; A]
n = 6: [H; A; A; H; H; A; A; H; H; A]
n = 7: [A; H; A; H; H; A; A; H; H; A]
n = 8: [H; A; A; H; H; A; A; H; H; A; A; H; H; A]
n = 9: [A; H; A; H; H; A; A; H; A; H; H; A]