Trem da engrenagem de Lego

13

Inspirado pelo desafio das relações de marchas da Lego por Keith Randall.

Também planejo construir um robô lego gigante que acabará destruindo os outros robôs na competição nunca mencionada. * No processo de construção do robô, usarei muitos trens de engrenagem para conectar diferentes partes do robô. Quero que você me escreva o programa mais curto que me ajudará a construir os complexos trens de engrenagem necessários para uma tarefa tão complexa. Obviamente, usarei apenas engrenagens com raios 1, 2, 3 e 5 unidades lego arbitrárias.

Cada engrenagem no trem de engrenagens tem uma coordenada inteira específica em uma grade 2D. A primeira marcha está localizada em (0,0) e a marcha final será localizada em coordenadas não-negativas. O local e o tamanho da primeira e da última marcha serão fornecidos como entrada. Seu programa deve informar quais marchas serão para onde preencher as lacunas.

Além disso, seu programa deve usar o número mínimo possível de marchas no trem de engrenagens. Menos engrenagens / trem = mais trens ** = maior e melhor robô de destruição.

A entrada consistirá em uma linha:

X,Y,B,A

X e Y são as coordenadas da marcha final. A primeira marcha está sempre localizada em (0,0). B e A são os raios das marchas final e inicial, respectivamente. Para adicionar alguma dificuldade, você precisa garantir que a engrenagem de saída gire na direção correta.Se A e B tiverem o mesmo sinal, a engrenagem de saída precisará girar na mesma direção, e um número ímpar de marchas deverá ser usado. Se eles tiverem sinais opostos, será necessário usar um número par de marchas.

A saída deve ser uma lista da localização X, localização Y e raios de cada marcha adicional, uma marcha por linha. Se houver várias soluções de engrenagem mínima, imprima apenas uma de sua escolha. A ordem das marchas na saída não importa.

Exemplos (soluções mais equivalentes podem ser possíveis):

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!

Aqui estão as soluções para os exemplos acima, visualizadas:

insira a descrição da imagem aqui

Até onde eu sei, nenhum problema é impossível, a menos que as duas engrenagens de entrada se sobreponham ou se conectem diretamente. Você não terá que lidar com isso.

Este é o código de golfe, a resposta mais curta vence.


* Um futuro KOTH, alguém?

** CHOO CHOO !!

PhiNotPi
fonte
Eu gostaria que o raio inicial e o raio final fossem negativos.
Wizzwizz4
9
Bem-vindo ao Lego Gear Train Challenge, da Phi. Depois de 4 anos na Sandbox, espero que valha a pena.
a spaghetto
@ wizzwizz4 Fez a mudança.
PhiNotPi 6/01/16
Isso foi realmente na caixa de areia por 4 anos?
Rɪᴋᴇʀ
@RikerW Mais como 3 1/3.
PhiNotPi 6/01/16

Respostas:

1

C #, 660 bytes

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

Experimente Online

Isso foi muito divertido !! Programa completo, aceita entrada de STDIN, saída para STDOUT. A saída é a engrenagem na ordem do fim ao início. Uso:

Executa uma simples pesquisa de largura em primeiro lugar, que resolve um problema de quatro marchas em menos de um segundo. O fator de ramificação não é realmente tão grande, então é bom para consideravelmente mais (não o testou realmente). Infelizmente, ele usa o Linq.

A Qstring é uma tabela de todas as conexões de engrenagem permitidas (ou seja, an r=3e se conectam a um r=1if dx=4e dy=0) em um quadrante, que é rotacionado para encontrar as outras. Cada conjunto de 3 bytes é o dx, dye informações raio de um vínculo jurídico. A escolha de (como deslocamento foi muito deliberada: foi divertido, pela primeira vez, escolher um caractere ASCII para propriedades agradáveis, em vez de tentar desesperadamente encontrar propriedades agradáveis ​​para caracteres ASCII impostos.

Provavelmente, posso fazer um trabalho melhor lendo a entrada, mas ainda não tive sorte, até porque o Linq é pago pela necessidade de uma lista. Também estou muito decepcionado com o código de rotação, sinto que isso poderia ser feito em consideravelmente menos bytes.

Código formatado e comentado com Qgerador:

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
                        }));
        }
    }
}
VisualMelon
fonte