乐高齿轮火车


13

灵感来自Keith Randall 的Lego传动比挑战。

我也计划建造一个大型的乐高机器人,该机器人最终将能够在前所未有的竞争中摧毁其他机器人。*在构建机器人的过程中,我将使用大量齿轮系来连接机器人的不同部分。我想让您编写最短的程序,这将帮助我构建完成如此复杂的任务所需的复杂齿轮系。当然,我只会使用半径为1、2、3和5的任意乐高单位的齿轮。

齿轮系中的每个齿轮在2D网格上都有特定的整数坐标。第一个齿轮位于(0,0),最后一个齿轮位于非负坐标。第一个和最后一个齿轮的位置和尺寸将作为输入提供,您的程序必须告诉哪些齿轮去哪里填补了空白。

此外,您的程序必须在齿轮系中使用尽可能少的齿轮。更少的齿轮/火车=更多的火车** =更大更好的销毁机器人。

输入将包含一行:

X,Y,B,A

X和Y是最终齿轮的坐标。一档始终位于(0,0)。B和A分别是最终齿轮和初始齿轮的半径。为了增加一些难度,您需要确保输出齿轮以正确的方向旋转。如果A和B具有相同的符号,则输出齿轮需要沿相同方向旋转,并且必须使用奇数个齿轮。如果它们的符号相反,则需要使用偶数个齿轮。

输出应为每个附加齿轮的X位置,Y位置和半径的列表,每行一个齿轮。如果有多个最小齿轮解决方案,则仅打印您选择的一种。输出中的齿轮顺序无关紧要。

示例(可能有更多等效的解决方案):

in
4,0,1,1
out
2,0,1

in
7,7,-2,-2
out
4,3,3
OR
0,7,5
OR
the above reflected over y=x line

in
7,8,-1,2
out
7,0,5
7,6,1
OR
7,0,5
1,8,5

in
7,7,2,-2
out
4,-3,3
7,1,2
12,1,3
12,7,3
OR
any permutation of the above, or reflected over y=x line
Now you're thinking with gear trains!

这是上述示例的解决方案,可视化:

在此处输入图片说明

据我所知,除非两个输入齿轮重叠或直接连接,否则没有问题是不可能的。您无需处理。

这是代码高尔夫,最短答案胜出。


*未来的KOTH,有人吗?

** CHOO CHOO !!


我希望它的初始半径和最终半径都可以为负。
wizzwizz4 '16

9
欢迎参加Phi的乐高齿轮火车挑战赛。在沙盒中工作了4年之后,希望它值得。
意大利面条

@ wizzwizz4进行了更改。
PhiNotPi

这真的在沙箱中存在了4年吗?
Rɪᴋᴇʀ

@RikerW更像是3 1/3。
PhiNotPi

Answers:


1

C#,660字节

using System.Linq;using System;class P{int p=1,x,y,r;P l;static void Main(){var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V";var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();int i=0,t,s=7,u,v,w,p=I[3]*I[2];for(var D=new[]{new P{r=Math.Abs(I[3]),l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3}}}.ToList();i>=0;){P c=D[i++],l=c.l;for(;(l=l?.l)!=null&&(s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;);if(s==0&&l.p>2&p*c.p<0)for(i=-1;c.l.p<3;c=c.l)Console.WriteLine(c.x+","+c.y+","+c.r);for(t=0;s>0&t<66;t++)for(u=Q[t++]-36,v=Q[t++]-36,s=1;s++<5&Q[t]%9==c.r;w=u,u=v,v=-w,D.Add(new P{l=c,r=Q[t]/9-4,x=c.x+u,y=c.y+v,p=-c.p}));}}}

在线试用

这是一个很多的乐趣!完整的程序,接受来自STDIN的输入,输出到STDOUT。输出是从头到尾依次排列的齿轮。用法:

执行简单的广度优先搜索,从而在不到一秒钟的时间内解决了4齿轮问题。分支因子实际上并没有那么大,因此分支因子应该有更多的好处(没有经过实际测试)。可悲的是它使用了Linq。

Q字符串是一个象限中所有允许的齿轮连接的表(即,an r=3r=1if dx=4和相连dy=0),然后旋转该象限以查找其他象限。每个组的3个字节是dxdy对于一个合法的连接,和半径信息。选择(偏移量是非常有意的:曾经一次为良好的属性选择ASCII字符很有趣,而不是拼命尝试为施加的ASCII字符寻找良好的属性。

我可能可以更好地阅读输入内容,但是我还没有走运,尤其是因为Linq是由需要列表支付的。我对旋转代码也非常失望,我觉得可以用更少的字节数来完成。

Q生成器的格式化和注释代码:

using System.Linq; // seems to pay today
using System;

class P
{
    static void GenQ()
    {
        int t, k = 0, m = 0;
        Func<P, P, int> C = (P c, P l) => (t = c.x - l.x) * t + (t = c.y - l.y) * t - (t = c.r + l.r) * t; // ==0 -> touching, <0 -> not touching, >0 -> overlap

        string str = "";

        string T(int i) => "" + (char)('$' + i); // $ is zero, '$' == 36, so we can mod and div by 9, and greater than " so we don't have to escape it

        foreach (int r in new[] { 1, 2, 3, 5 }) // at 0,0 (current gear)
            foreach (int s in new[] { 1, 2, 3, 5 }) // gear to place
                for (int i = 0; i <= r + s; i++) // x
                    for (int j = 1; j <= r + s; j++, m++) // y
                        if (C(new P { r = r }, new P { r = s, x = i, y = j }) == 0) // 
                        {
                            str += T(i) + T(j) + T(r + s * 9);
                            k++;
                        }

        System.Console.WriteLine("K : " + k);
        System.Console.WriteLine("M : " + m);
        System.Console.WriteLine(str);
        System.Console.ReadKey(true);
        return;
    }

    int p=1, // parity
        x, // x
        y, // y
        r; // radias (TODO: store radias^2 ?)
    P l; // previous in search list

    static void Main()
    {
        //GenQ();

        // '$' == 36 (4*9)
        // 3char blocks: x,y,r+9*s
        var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V"; // quarter table

        // primative read ints
        var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();

        int i=0, // position in Due
            t, // check differential cache, position in Q
            s=7, // check cache, rotation counter (>0)
            u, // rotation x
            v, // rotation y
            w, // rotation x cache
            p=I[3]*I[2]; // parity (>0 -> same, even ; <0 -> different, odd)

        // due (not point using a queue, the search space grows exponentially)
        for(var D=new[]{
                new P{r=Math.Abs(I[3]), // start (p==1)
                    l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3} // terminal (detect with p==3)
                }}.ToList();
            i>=0;) // infinite number of configurations, no bounds, i is escape term
        {
            P c=D[i++], // current
                l=c.l; // check, initially the one before the previous (we know we are touching last already)

            // 'checks' c against l
            //Func<int>C=()=>(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t; // ==0 -> touching, >0 -> not touching, <0 -> overlap

            // check we arn't touching any before us (last thing we check is terminal)
            for(;(l=l?.l)!=null&& // for each before us (skipping the first one)
                (s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;); // check c against l and cache in s, ==0 -> touching, >0 -> not touching, <0 -> overlap

            if(s==0&& // touching last checked?
                l.p>2& // stopped on terminal?
                p*c.p<0) // correct parity? -> win
                for(i=-1; // escape
                    c.l.p<3;c=c.l) // for each that wasn't the first
                    Console.WriteLine(c.x+","+c.y+","+c.r);

            // enumerate possible additions, and queue them in due
            for(t=0;
                s>0& // not touching or overlapping anything (including terminal)
                t<66;t++) // 66 = Q.Length
                for(
                    u=Q[t++]-36, // '$'
                    v=Q[t++]-36,
                    s=1;s++<5& // rotate 4 times
                    Q[t]%9==c.r; // our raidus matches
                        w=u, // chache y value
                        u=v, // rotate
                        v=-w,
                        D.Add(new P // add
                        {
                            l=c,
                            r=Q[t]/9-4, // radius
                            x=c.x+u,
                            y=c.y+v,
                            p=-c.p // flip parity
                        }));
        }
    }
}
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.