Lego Gear Train

13

Inspiré des rapports de démultiplication Lego défi des de Keith Randall.

Moi aussi, je prévois de construire un robot lego géant qui sera éventuellement en mesure de détruire les autres robots dans la compétition sans précédent. * Dans le processus de construction du robot, j'utiliserai beaucoup de trains d'engrenages pour me connecter différentes parties du robot. Je veux que vous m'écriviez le programme le plus court qui m'aidera à construire les trains d'engrenages complexes qui sont nécessaires pour une tâche aussi complexe. Bien sûr, je n'utiliserai que des engrenages avec des rayons 1, 2, 3 et 5 unités lego arbitraires.

Chaque engrenage du train d'engrenages a une coordonnée entière spécifique sur une grille 2D. Le premier engrenage est situé à (0,0) et l'engrenage final sera situé à des coordonnées non négatives. L'emplacement et la taille des premier et dernier engrenages seront fournis en entrée, votre programme doit indiquer quels engrenages vont où combler les lacunes.

De plus, votre programme doit utiliser le nombre minimum de vitesses possible dans le train d'engrenages. Moins de vitesses / train = plus de trains ** = robot de destruction plus grand et meilleur.

L'entrée consistera en une ligne:

X,Y,B,A

X et Y sont les coordonnées de l'engrenage final. La première vitesse est toujours située à (0,0). B et A sont respectivement les rayons des vitesses finale et initiale. Pour ajouter une certaine difficulté, vous devez vous assurer que le pignon de sortie tourne dans le bon sens.Si A et B ont le même signe, alors le pignon de sortie doit tourner dans le même sens, et un nombre impair de vitesses doit être utilisé. S'ils ont des signes opposés, alors un nombre pair de vitesses doit être utilisé.

La sortie doit être une liste de l'emplacement X, de l'emplacement Y et des rayons de chaque engrenage supplémentaire, un engrenage par ligne. S'il existe plusieurs solutions à vitesse minimale, n'imprimez qu'une seule de votre choix. L'ordre des vitesses dans la sortie n'a pas d'importance.

Exemples (des solutions plus équivalentes peuvent être possibles):

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!

Voici les solutions aux exemples ci-dessus, visualisées:

entrez la description de l'image ici

Pour autant que je sache, aucun problème n'est impossible à moins que les deux vitesses d'entrée se chevauchent ou se connectent directement. Vous n'aurez pas à vous en occuper.

C'est le golf de code, la réponse la plus courte l'emporte.


* Un futur KOTH, quelqu'un?

** CHOO CHOO !!

PhiNotPi
la source
Je voudrais que les rayons initial et final puissent être négatifs.
wizzwizz4
9
Bienvenue au Phi's Lego Gear Train Challenge. Après 4 ans dans le Sandbox, j'espère que cela en aura valu le poids.
un spaghetto du
@ wizzwizz4 Apporté le changement.
PhiNotPi
Était-ce vraiment dans le bac à sable pendant 4 ans?
Rɪᴋᴇʀ
@RikerW Plus comme 3 1/3.
PhiNotPi

Réponses:

1

C #, 660 octets

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

Essayez-le en ligne

C'était très amusant !! Programme complet, accepte les entrées de STDIN, les sorties vers STDOUT. La sortie est les engrenages dans l'ordre de la fin au début. Usage:

Effectue une simple recherche de largeur, qui résout un problème à 4 vitesses en moins d'une seconde. Le facteur de branchement n'est pas vraiment grand, donc il devrait être bon pour beaucoup plus (pas vraiment testé). Malheureusement, il utilise Linq.

La Qchaîne est un tableau de toutes les connexions d'engrenages autorisées (c'est-à-dire un r=3et se connecter à un r=1si dx=4et dy=0) dans un quadrant, qui est ensuite tourné pour trouver les autres. Chaque ensemble de 3 octets est dx, dyet de l' information de rayon pour un lien juridique. Le choix d' (un décalage était très délibéré: c'était amusant pour une fois de choisir un caractère ASCII pour de belles propriétés, plutôt que d'essayer désespérément de trouver de belles propriétés pour des caractères ASCII imposés.

Je peux probablement faire un meilleur travail de lecture de l'entrée, mais je n'ai pas encore eu de chance, notamment parce que le Linq est payé par le besoin d'une liste. Je suis également très déçu par le code de rotation, j'ai l'impression que cela pourrait être fait en beaucoup moins d'octets.

Code formaté et commenté avec Qgénérateur:

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
la source