创建一个FizzBu​​zz编译器


17

欢迎来到编译器高尔夫的世界。您的任务是编写一个程序,该程序会生成另一个程序,以按规范播放FizzBu​​zz的变体。

您的编译器

编写一个编译器,以生成符合规范的FizzBu​​zz程序。此变体的规范以整数/字符串对数组的形式表示。

  • 输入可以采用任何方便您的语言的形式。(我的示例使用n:xxxx,但这只是出于说明目的。)
  • 每次调用编译器时,每个整数输入只能使用一次。
  • 每对的整数将具有至少一个值。
  • 每对字符串仅由四个ASCII字母组成。
  • 输出必须是符合以下规则的单个完整程序。
  • 输出可以是任何方便的形式,只要它是文本程序即可。(因此,没有返回的lambda表达式。)

对于不符合上述规则的输入,行为未定义。

您生成的FizzBu​​zz程序

编译器生成的程序将使用单个整数n作为输入。它将输出一个从1到n的数字序列,并在需要时用FizzBu​​zz字符串替换数字。

  • 生成的程序必须使用与编译器相同的语言。
  • 输入n可以采用适合您的语言的任何形式。
  • n的值至少为1。
  • 输入编译器的至少一个整数的倍数的数字必须替换为所有与这些整数结合在一起的字符串。
  • 不能用FizzBu​​zz字符串替换的数字必须以十进制ASCII输出。

例如;

> GenFizzBuzz 3:Fizz 5:Buzz
> a.out 5
1
2
Fizz
4
Buzz

计分

您的条目将根据编译器生成的程序的长度加上编译器的长度进行评分。使用以下每个参数多次运行编译器,然后将生成的程序的长度与编译器的长度相加,以得出分数。

  1. 只是计数。(无输入-生成的程序将在没有替换的情况下从1到n计数。)
  2. 只是高尔夫。(1:Golf-生成的程序将输出n次“ Golf” 。)
  3. 经典FizzBu​​zz。(3:嘶嘶声,5:嗡嗡声)

(请注意,编译器需要为任何有效输入生成代码,而不仅仅是列出的这些。)


没有得分的编译器的长度?
Sparr

我们可以假设整数是个位数吗?字符串中没有空格?
Sparr 2014年

@Sparr(两位整数)会有所作为吗?请记住,只有生成的代码才能使您得分。
billpg 2014年

好吧,fizzbuzz是互联网上其他地方已经非常彻底的高尔夫问题。我不知道是否可以尝试阅读解决方案。
Sparr

1
最终,高尔夫挑战赛在AWK中真正有意义。
shadowtalker 2014年

Answers:


8

Python的3 - 168 162 230 + = 392

哦,Python,您会尽力而为,但是将import sys;sys.argv内容乘以4确实很痛!

import sys;a=eval(sys.argv[1])
print("import sys\nfor i in range(1,int(sys.argv[1])+1):print("+"+".join('"%s"*(i%%%d==0)'%t for t in a)+(a and"or str(i))"or"i)"))

输出程序:

import sys
for i in range(1,int(sys.argv[1])+1):print(i)
import sys
for i in range(1,int(sys.argv[1])+1):print("Golf"*(i%1==0)or str(i))
import sys
for i in range(1,int(sys.argv[1])+1):print("Fizz"*(i%3==0)+"Buzz"*(i%5==0)or str(i))
  • 主程序的预期输入是可评估的Python元组序列或'()'无输入。(你说过“方便”。)例输入:'()''("Golf",1),''("Fizz",3),("Buzz",5)'注意报价为外壳和一个输入尾随逗号。

  • 通过将dict(未定义顺序!)更改为元组来修复1am错误。

  • 其他程序的预期输入就是数字


在您的示例命令行参数中,我必须用双引号括起来,并对'Fizz'和'Buzz'使用单引号-就像`“ {{3:'Fizz',5:'Buzz'}”这样,但是程序仍然给我丢一个错误。
詹姆斯·威廉姆斯

有什么错误?
2014年

@JasonS-嗨。我对您对此挑战的经历很感兴趣。meta.codegolf.stackexchange.com/questions/5050/…–
billpg

6

perl6 376 340 84 + 115 = 199

更新:从perl5切换到perl6以获得sayuse feature

更新:三个测试用例,而不是五个

FizzBu​​zz已有数百种解决方案,许多比赛都以相同的结果结束,所以我从这里开始。我的编译器只是生成该解决方案的定制版本。插入了一些额外的字符以说明“ just count”的变化。

编译器,需要这样的参数:“ Fizz 3”“ Buzz 5”

print'say(('.(join'.',map{'('.(join')[$_%',split).']'}@ARGV).')||$_)for 1..$ARGV[0]'

编译的程序,期望这样的参数:100

say(()||$_)for 1..$ARGV[0]
say(((Golf)[$_%1])||$_)for 1..$ARGV[0]
say(((Fizz)[$_%3].(Buzz)[$_%5])||$_)for 1..$ARGV[0]

旧测试用例的已编译程序:

say(((Twoo)[$_%2].(Four)[$_%4].(Eiht)[$_%8])||$_)for 1..$ARGV[0]
say(((Twoo)[$_%2].(Thre)[$_%3].(Five)[$_%5].(Sevn)[$_%7])||$_)for 1..$ARGV[0]

我已经更改了问题评论中讨论的规则。您将需要重新计算分数。
billpg 2014年

@billpg完成,并进行了改进:)
Sparr

嗨,您好。我对您对此挑战的经历很感兴趣。meta.codegolf.stackexchange.com/questions/5050/…–
billpg

3

Pyth-51 +(38 + 43 + 50)= 182字节

大概可以编译几个字节。所有这些链接都是在线解释器的永久链接。

编译器 -51个字节

%"K[%s)=dc\"%s\"dFGr1hQJkFNKI!%%GN~J@dxKN))?JJG",zw

使用输入元组进行字符串格式化也是如此。接受像这样的输入:

3 5
Fizz Buzz

-38个字节

K[)=dc""dFGr1hQJkFNKI!%GN~J@dxKN))?JJG

Just Golf -43个字节

K[1)=dc"Golf"dFGr1hQJkFNKI!%GN~J@dxKN))?JJG

经典Fizz Buzz -50个字节

K[3 5)=dc"Fizz Buzz"dFGr1hQJkFNKI!%GN~J@dxKN))?JJG

2

C ++ 11〜486 +(234 + 244 + 255)= 1219

第一次参加此挑战并不是最困难的挑战,因此我想尝试一下。尽管使用C ++,甚至使用C ++ 11,它仍然是一种非常冗长的语言,但是我敢肯定还有改进的余地。

编译器(486):

#include<sstream>
#include<iostream>
using namespace std;main(int c,char**v){stringstream t;int i;string s,o;o="#include <iostream>\n#include <map>\nusing namespace std;main(int c,char**v){int i,n=stoi(v[1]);map<int,string> f{";int z=2;for(int j=1;j<c;++j){t.str(v[j]);t.clear();t >> i; t >> s;o+="{"+to_string(i)+",\""+s+"\"}"+(z++==c?"":",");}o+= R"(};bool p;for(i=1;i<n;++i){p=true;for(auto e:f){if(i%e.first==0){cout<<e.second;p=false;}}cout<<(p?to_string(i):"")+"\n";}})";cout<<o;}

它假定参数为3Fizz 5Buzzetc 形式。

数(234):

#include <iostream>
#include <map>
using namespace std;main(int c,char**v){int i,n=stoi(v[1]);map<int,string> f{};bool p;for(i=1;i<n;++i){p=true;for(auto e:f){if(i%e.first==0){cout<<e.second;p=false;}}cout<<(p?to_string(i):"")+"\n";}}

高尔夫(244):

#include <iostream>
#include <map>
using namespace std;main(int c,char**v){int i,n=stoi(v[1]);map<int,string> f{{1,"Golf"}};bool p;for(i=1;i<n;++i){p=true;for(auto e:f){if(i%e.first==0){cout<<e.second;p=false;}}cout<<(p?to_string(i):"")+"\n";}}

FizzBu​​zz(255):

#include <iostream>
#include <map>
using namespace std;main(int c,char**v){int i,n=stoi(v[1]);map<int,string> f{{3,"Fizz"},{5,"Buzz"}};bool p;for(i=1;i<n;++i){p=true;for(auto e:f){if(i%e.first==0){cout<<e.second;p=false;}}cout<<(p?to_string(i):"")+"\n";}}

附加信息

经过GCC 4.8.1测试,没有编译器作弊。

这是一个小的makefile,用于自动生成测试用例并运行它们(使用make run):

run:
    g++ main.cpp --std=c++11 -o fbc

    ./fbc > count.cpp
    g++ count.cpp --std=c++11
    echo "======= Count ========"
    ./a.out 15

    ./fbc 1Golf > golf.cpp
    g++ golf.cpp --std=c++11
    echo "======= Golf ========"
    ./a.out 15

    ./fbc 3Fizz 5Buzz > fizzbuzz.cpp
    g++ fizzbuzz.cpp --std=c++11
    echo "======= FizzBuzz ========"
    ./a.out 15

嗨,您好。我对您对此挑战的经历很感兴趣。meta.codegolf.stackexchange.com/questions/5050/…–
billpg

map<int,string> f可能是map<int,string>f。您可以j=1同时使用进行初始化z
Yytsi

2

红宝石99 +(86 + 94 + 103)= 382

puts"(1..ARGV[0].to_i).each{|i|x=[];#{ARGV[0]}.each{|k,v|x<<v if i%k==0};puts x.size>0?x.join():i}"

用法:

wc -c main.rb # 99 chars
ruby main.rb "{}" | ruby - 100 # 1..2..3..
ruby main.rb "{}" | wc -c # 86 chars
ruby main.rb "{1=>:Golf}" | ruby - 100 # Golf..Golf..Golf..
ruby main.rb "{1=>:Golf}" | wc -c # 94 chars
ruby main.rb "{3=>:Fizz,5=>:Buzz}" | ruby - 100 # 1..2..Fizz..4..Buzz..
ruby main.rb "{3=>:Fizz,5=>:Buzz}" | wc -c # 103 chars

2

萨克斯,23 + 5 + 17 + 29 = 74

╥╟.└ç╘SJ∞CF╔v=▌╝Σ@∞ìé«g

运行并调试

迄今为止最短的答案毫不奇怪地被果冻击败了。Stax中提供的字符串模板确实很整洁,并提供类似于printf的功能。由编译器生成的程序几乎总是与不使用打包即可通过手动代码高尔夫实现的最佳程序一样短。

编译器本身为23 个字节长。

ASCII等效项是:

{H34|S_h"_`c%z`n?+"m"mz`cc_?

提供的输入[],生成一个(5字节)

mzc_?

运行并调试

提供的输入[[1,"Golf"]],生成此输入(17个字节)

mz_1%z"Golf"?+c_?

运行并调试

提供的输入[[3,"Fizz"],[5,"Buzz"]],生成一个(29字节)

mz_3%z"Fizz"?+_5%z"Buzz"?+c_?

运行并调试


1

普通Lisp 636 577

(ql:quickload'cl-ppcre)(lambda(z)(princ(subseq(ppcre:regex-replace-all" *([(')]) *"(with-output-to-string(@)(print`(lambda(n)(dotimes(i n)(loop for(m s)in ',z if(=(mod(1+ i)m)0)do(princ s))(do()((fresh-line))(princ (1+ i)))))@))"\\1")1)))

我添加了其他答案,并在添加输入参数的同时将其包裹在了准引用中。我将结果表单打印为单行,并删除不必要的空格字符。编译器比以前的版本长一点,但是结果得分降低了。

得分了

(let ((*standard-output* (make-broadcast-stream)))
  (loop
     for form in '(215                      ; Compiler
                   ()                       ; Count
                   ((1 "Golf"))             ; Golf
                   ((3 "Fizz")(5 "Buzz")))  ; FizzBuzz
     for length = (if (numberp form) form
                      (length (funcall *fun* form)))
     collect length into lengths
     sum length into sum
     finally (return (values sum lengths))))

返回值:

574
(215 111 119 129)

漂亮

(defun fizz-buzz-compiler (z)
  (princ (subseq
          (cl-ppcre:regex-replace-all
           " *([(')]) *"
           (with-output-to-string (stream)
             (print
              `(lambda (n)
                 (dotimes(i n)
                   (loop for (m s) in ',z
                      if (=(mod(1+ i)m)0)
                      do (princ s))
                   (do () ((fresh-line))
                     (princ (1+ i))))) stream))
             "\\1") 1)))

输入格式为(number string)夫妇列表。例如:

(fizz-buzz-compiler '((3 "Fizz")(5 "Buzz")))

...打印到标准输出:

(LAMBDA(N)(DOTIMES(I N)(LOOP FOR(M S)IN'((3 "Fizz")(5 "Buzz"))IF(=(MOD(1+ I)M)0)DO(PRINC S))(DO NIL((FRESH-LINE))(PRINC(1+ I)))))

...漂亮印刷的是:

(lambda (n)
  (dotimes (i n)
    (loop for (m s) in '((3 "Fizz") (5 "Buzz"))
          if (= (mod (1+ i) m) 0)
          do (princ s))
    (do () ((fresh-line)) (princ (1+ i)))))

测试结果函数:

CL-USER> ((lambda (n)
  (dotimes (i n)
    (loop for (m s) in '((3 "Fizz") (5 "Buzz"))
          if (= (mod (1+ i) m) 0)
          do (princ s))
    (do () ((fresh-line)) (princ (1+ i))))) 20)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz



0

C,总共1080个字节

编译器[369字节]

#include<stdlib.h>
r,t,f=3,b=5,n;char*F="FIzz",*B="buZZ";main(int c,char **v){if(f)for(c=atoi(v[1]),n=1;c>=n;)r=f?n%f:0,r?(t=b?n%b:0)?printf("%i\n",n):puts(B):r?printf("%s%s\n",F,B):puts(F),++n;else for(c=0;c<atoi(v[1]);)printf("%i\n",++c);}

嘶嘶声[241]

#include<stdlib.h>
r,t,f=3,b=5,n;char*F="FIzz",*B="buZZ";main(int c,char **v){if(f)for(c=atoi(v[1]),n=1;c>=n;)r=f?n%f:0,r?(t=b?n%b:0)?printf("%i\n",n):puts(B):r?printf("%s%s\n",F,B):puts(F),++n;else for(c=0;c<atoi(v[1]);)printf("%i\n",++c);}

高尔夫[237]

#include<stdlib.h>
r,t,f=1,b=0,n;char*F="golf",*B="";main(int c,char **v){if(f)for(c=atoi(v[1]),n=1;c>=n;)r=f?n%f:0,r?(t=b?n%b:0)?printf("%i\n",n):puts(B):r?printf("%s%s\n",F,B):puts(F),++n;else for(c=0;c<atoi(v[1]);)printf("%i\n",++c);}

计数[233字节]

#include<stdlib.h>
r,t,f=0,b=1,n;char*F="",*B="";main(int c,char **v){if(f)for(c=atoi(v[1]),n=1;c>=n;)r=f?n%f:0,r?(t=b?n%b:0)?printf("%i\n",n):puts(B):r?printf("%s%s\n",F,B):puts(F),++n;else for(c=0;c<atoi(v[1]);)printf("%i\n",++c);}

0

直流电,434字节

[:a]sa[91Pn93Pznlanps_znlanz0<R]sR[[[lj1-;aP1sb]sB0sj[dljd2+sj;a%0=Bljlz>F]sF[p2Q]sP]P]sI[[[]sF[pq]sP]nq]sN[z0=Nzn[sz]PlRxlIx]x[sn0dsb[1+0sjlFx[lb0=PAP]x0sbdln>M]dsMx]P

在线尝试!

编译器的输入(168字节)应以整数,字符串,整数,字符串等形式放在堆栈上(3 [Fizz] 5 [Buzz])。应该以希望打印他们的嘶嘶声和嗡嗡声的顺序给出,这可能有点作弊(dc以前已经实现了气泡排序,我相信这会花掉我大约1​​00个字节),但是它还允许用户,例如,仍然将'Fizz'运行在3上,将'Buzz'运行在5,但是将15生成'BuzzFizz'。

我相信这可以打更多些。最终程序(M)中的主宏依赖于两个宏(FP),这些没有输入的情况下是不必要的。现在,编译器会检查这些宏的输入和输出(如果没有)的不同(小得多)版本,但是我不确定整个设置是否是最佳的。

编译器本身非常简单,它只是检查堆栈上是否有“规则”,如果是,它将打印将堆栈深度存储在中的代码,将堆栈z存储在0索引数组中a,然后打印广义的FizzBu​​zz代码。如果堆栈上没有任何内容,它实际上只会打印FizzBu​​zz代码的修改版本。测试用例:

无输入(46字节):

[]sF[pq]sPsn0dsb[1+0sjlFx[lb0=PAP]x0sbdln>M]dsMx

3 [Fizz] 5 [Buzz](117字节):

4sz[Buzz]3:a5
2:a[Fizz]1:a3
0:a[lj1-;aP1sb]sB0sj[dljd2+sj;a%0=Bljlz>F]sF[p2Q]sPsn0dsb[1+0sjlFx[lb0=PAP]x0sbdln>M]dsMx

1 [高尔夫](103字节):

2sz[Golf]1:a1
0:a[lj1-;aP1sb]sB0sj[dljd2+sj;a%0=Bljlz>F]sF[p2Q]sPsn0dsb[1+0sjlFx[lb0=PAP]x0sbdln>M]dsMx

他们都希望堆栈上的n值存储在中n。具有“规则”的规则将它们放置在数组中a,字符串在奇数索引处,整数在偶数处。主宏M递增堆栈上的所有内容,运行宏F,该宏检查数组的值a,检查是否F将寄存器设置b为true,如果是则打印堆栈顶部,如果不是则打印换行符,重置b为falsy,然后保持如果n尚未达到目标,则自行运行。F给定规则的Macro 遍历整个数组以查找匹配项。因为我们的整数和字符串是通过数组编织的,所以它增加了两个,并且在匹配项中它称为宏B。巨集B只是检索字符串(数组中的当前位置减去一),然后打印它。它还设置b为真实。我们的编译器不会打扰不打印B任何输入,并且本质上会F进行nop。


0

vim,122(编译器)+ 73(空)+ 90(高尔夫球)+ 123(fizzbuzz)= 392字节

编译器

:%s/\v(.*):(.*)/qq\1jA\2<C-V><C-V><C-V><ESC>q=@qgg
VgggJAddGdd:%s/\v[0-9]*([^0-9])/\1
<C-V><ESC>:%@n
:w
:so! %
<ESC>ggii%s/=/<C-V><ESC><C-V><C-A>a/g<C-V><ESC>"ncc:%!seq 0 =
<ESC>

输入格式

3:Fizz
5:Buzz

为FizzBu​​zz案例生成的代码

i%s/=/<ESC><C-A>a/g<ESC>"ncc:%!seq 0 =
qq3jAFizz<C-V><ESC>q=@qggqq5jABuzz<C-V><ESC>q=@qggddGdd:%s/\v[0-9]*([^0-9])/\1
<ESC>:%@n
:w
:so! %

生成的代码,带注释

# replace the input number with a regex that replaces the placeholder (=) 
# with the real number + 1 (we'll need an extra line as a terminator later)
i%s/=/<ESC><C-A>a/g<ESC>

# pull the substitution command into register c and enter insert mode
"ncc

# create the numbers 0..N+1
:%!seq 0 =

# for each word, scan down k lines at a time and append the word to each
qq3jAFizz<C-V><ESC>q=@qgg
qq5jABuzz<C-V><ESC>q=@qgg

# delete the 0 and N+1 lines
ddGdd

# remove the numbers from any line with words
:%s/\v[0-9]*([^0-9])/\1
<ESC>

# Run the command we created at the beginning, replacing the placeholder 
# with the real number
:%@n

# The file now contains yet another program, with the constants defined.   
# Save and run.
:w
:so! %

# The file now contains a program that, when run on a buffer containing 
# a single line with a number, will produce the appropriate output

<C-V>是0x16。<ESC>是0x1b。<C-A>是0x01。

会话示例

$ cat code.txt
2:Foo
4:Bar
$ cat input.txt
8
$ { cat compile.vim; echo ':wq'; } | vim code.txt
# code.txt now contains the generated code
$ { cat code.txt; echo ':wq'; } | vim input.txt
$ cat input.txt
1
Foo
3
FooBar
5
Foo
7
FooBar

当我尝试从另一个宏中定义并运行一个宏时,发生了一些奇怪的事情。如果设法解决问题,我可能会在保存和源代码方法上节省一些字节。

-2

SlooSarksi .Lang,179岁

%%--43^jjk"/][][0[#!#111# h SD G ergDFGdfg[]9--99+==

10
我对这种语言不熟悉;您可以将我们链接到描述它的页面吗?
lirtosiast,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.