代码高尔夫:Fractran

49

挑战

编写一个程序,作为Fractran解释器。以字符计数最少的方式实现,无论是哪种语言,都是获胜者。您的程序必须接收两个输入:要执行的fractran程序和输入整数n。程序可以采用任何方便您的程序的形式 - 例如,2元组列表或平面列表。输出必须是单个整数,即执行结束时寄存器的值。

Fractran

Fractran是由John Conway发明的一种微不足道的语言。一个fractran程序由一系列正分数和一个初始状态n组成。解释器维护一个程序计数器,最初指向列表中的第一个分数。Fractran程序按以下方式执行:

  1. 检查当前状态和程序计数器下的当前分数的乘积是否为整数。如果是,则将当前状态乘以当前分数,并将程序计数器重置为列表开头。
  2. 推进程序计数器。如果到达列表末尾,则停止,否则返回步骤1。

有关Fractran的工作原理和原因的详细信息,请参见esolang entry和good math/bad math上的this entry

测试向量

程序:[(3, 2)]
输入:72(2332
输出:243(35

程序:[(3, 2)]
输入:1296(2434
输出:6561(38

程序:[(455, 33), (11, 13), (1, 11), (3, 7), (11, 2), (1, 3)]
输入:72(2332
输出:15625(56

奖励测试向量:

如果您能正确执行最后一个程序,则不需要提交此答案。但是,如果可以,那就太棒了!

程序: [(455, 33), (11, 13), (1, 11), (3, 7), (11, 2), (1, 3)]
输入: 60466176 (210310)
输出: 7888609052210118054117285652827862296732064351090230047702789306640625 (5100)

提交与评分

程序将按照字符长度严格排名,最短的为最佳。可以同时提交美观且有文档的代码和“minified”版本的代码,以便人们了解情况。

不接受“J”语言。这是因为在链接页面中已经有一个众所周知的J解决方案。 如果您是J粉丝,很抱歉!

额外奖励,任何能够提供一个自托管的fractran解释器的人将获得500声望点奖励。如果存在多个自托管解释器,则具有最少分数的解释器将获得赏金。

获胜者

官方获胜者是Jesse Beder's solution,他提交了一个由1779个分数构成的自托管fractran解决方案。但实际上,该解决方案的执行速度太慢,甚至无法执行1+1。

令人难以置信的是,这已经被另一个分数解决方案Amadaeus's solution打败了,只用了84个分数!当在我的参考Python解决方案上运行时,它能够在几秒钟内执行前两个测试用例。它使用了一种新颖的分数编码方法,值得仔细研究。

荣誉提名:

  • Stephen Canon's solution,使用165个字符的x86汇编语言(28个字节的机器代码)
  • Jordan's solution,使用52个字符的ruby - 可处理长整数
  • Useless's solution,使用87个字符的Python,虽然不是最短的Python解决方案之一,但是它是少数不是递归的解决方案之一,因此可以轻松处理更难的程序。它也非常易读。

20
对于不可避免的关门派: 在 Stack Overflow 上有超过100个标记为代码高尔夫的问题。这是一个合法的帖子,并且会得到有趣而富有启发性的回答。此外,它是一个社区 Wiki,因此没有人会通过它来攫取声誉。 - Nick Johnson
8
@R. Pate:在我之前可以先去和其他 104 个代码高尔夫的人争论一下,或者在 Meta 上提出来,社区共识通常是支持的。@mmyers:谢谢,我会更新问题。 - Nick Johnson
9
目前的共识看起来相当强大(超过20个人支持“可以,如果你不喜欢就忽略它”):http://meta.stackexchange.com/questions/20912/so-weekly-code-golf。当然,你(和其他关心此事的人)应该投票,并且如果你的观点没有被覆盖,也应该说明你的观点。 - ire_and_curses
5
我并非预先发表评论,而是在别人投票关闭之后才进行了评论。 - Nick Johnson
6
我只是发表个人意见:这是一个很棒的问题,一方面因为我喜欢代码高尔夫,另一方面更重要的是因为它让我了解了一个非常有趣的东西(以前从没听说过这种“语言”,但它太棒了!)。 - Edan Maor
显示剩余8条评论
25个回答

1

有点晚了... dc 84 字符

只是为了好玩,这是一个 dc 解决方案(OpenBSD)

[ss1sp]s1[Rlp1+sp]s2?l1xz2/sz[z2/ds_:bl_:az0<L]dsLx
1[;als*lp;b~0=1e2lpdlz!<L]dsLxlsp

它处理所有情况:

$ dc fractran.dc  
455 33 11 13 1 11 3 7 11 2 1 3 60466176
7888609052210118054117285652827862296732064351090230047702789306640625

1

Haskell,142个字符

不使用任何额外的库和完整的I/O。

t n f=case f of{(a,b):f'->if mod n b == 0then(\r->r:(t r f))$a*n`div`b else t n f';_->[]}
main=readLn>>=(\f->readLn>>=(\n->print$last$t n f))

1

Java, 200 192 179个字符

我想每个人都知道Java不会有最短的实现,但我想看看它与其他语言相比如何。它可以解决一些简单的例子,但无法解决奖励问题。

这是最小化的版本:

class F{public static void main(String[]a){long p=new Long(a[0]);for(int i=1;i<a.length;){long n=p*new Long(a[i++]),d=new Long(a[i++]);if(n%d<1){p=n/d;i=1;}}System.out.print(p);}}

java -cp . F 108 455 33 11 13 1 11 3 7 11 2 1 3

Java -cp . F 108 455 33 11 13 1 11 3 7 11 2 1 3

15625

java -cp . F 1296 3 2

6561

这是经过清理的版本:

public class Fractran {

    public static void main(String[] args) {
        long product = new Long(args[0]);

        for (int index = 1; index < args.length;) {
            long numerator = product * new Long(args[index++]);
            long denominator = new Long(args[index++]);

            if (numerator % denominator < 1) {
                product = numerator / denominator;
                index = 1;
            } // if
        } // for

        System.out.print(product);
    }
}

你可以通过使用 new Long 而不是 Long.decode 来节省更多字符。 - Michael Myers
谢谢你的建议-已经实现了!利用代码技巧来节省字符确实是一个挑战,这些技巧通常不会被使用。 - shadit

1

Scheme 73个字符

我第一次尝试使用完全标准的R5RS Scheme,结果为104个字符:

(define(f p n)(let l((q p)(n n))(if(null? q)n(let((a(* n(car q))))(if(integer?
a)(l p a)(l(cdr q)n))))))

针对测试向量中的几个项目运行:

> (f '(3/2) 1296)
6561
> (f '(455/33 11/13 1/11 3/7 11/2 1/3) 60466176)
7888609052210118054117285652827862296732064351090230047702789306640625

假设λ被绑定到lambda并且let/cc被定义(在PLT Scheme中已定义;如果在不定义这些的Schemes中运行,下面会提供定义),那么我可以将Jordan的第二个Ruby解决方案改编为Scheme,这样就得到了73个字符(请注意参数顺序与我的第一个解决方案相反,但与Jordan's相同;在这个版本中,这可以节省一个字符)。:

(define(f n p)(let/cc r(map(λ(i)(if(integer?(* n i))(r(f(* n i)p))))p)n))

如果我没有预定义的λlet/cc,则这个函数会有111个字符(如果常见的call/cc缩写被定义,则只有88个字符):

(define(f n p)(call-with-current-continuation(lambda(r)(map(lambda(i)(if(integer?(*
n i))(r(f(* n i)p))))p)n)))

λlet/cc的定义:

(define-syntax λ (syntax-rules () ((_ . body) (lambda . body)))
(define-syntax let/cc (syntax-rules () ((_ var . body) (call-with-current-continuation (lambda (var) . body)))))

0

我还不能留下评论,但这是RCIX的C#版本的“稍微”缩短版(我相信它比原版少了7个字符)

using System;namespace T{static class P{static void Main(string[] a){int i=1;Func<string,decimal> d=Convert.ToDecimal;var c=d(a[0]);while(i+1<=a.Length){var f=d(a[i])/d(a[++i]);if((f*c)%1==0){i=1;c*=f;}else i++;}Console.Write(c);}}}

它使用

Func<string,decimal> d=Convert.ToDecimal

并调用d();而不是

using b=Convert;

并且反复调用 b.ToDecimal();

我还删除了不必要的 else 语句周围的一对花括号以节省 1 个字符:)。

我还将 a[i+1] 替换为 a[++i],在接下来的 else 块中,我将 i+=2 替换为 i++,以获得另一个字符 :P


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接