Relaciones de engranajes de Lego

23

Estoy construyendo un robot lego gigante y necesito generar algunas relaciones de engranaje particulares usando un conjunto de engranajes. Tengo muchos engranajes con los tamaños de engranajes de lego comunes: 8, 16, 24 o 40 dientes. Escriba un programa que pueda usar donde ingrese una relación de engranaje y el programa me dice qué combinación de engranajes debo usar para obtener la relación solicitada.

La relación de entrada se especificará en la entrada estándar (o el equivalente de su idioma) con dos enteros separados por dos puntos. Una relación de a:bsignifica que el eje de salida debe girar a/bveces más rápido que el eje de entrada.

La salida a la salida estándar debe ser una sola línea que contenga una lista de relaciones de engranajes separadas por espacios, en forma de x:ydónde xestá el tamaño del engranaje en el eje de entrada y yel tamaño del engranaje en el eje de salida. Debe usar el mínimo número posible de engranajes para la relación dada. Cada uno xy ydebe ser uno de 8,16,24,40.

ejemplos:

1:5 -> 8:40
10:1 -> 40:8 16:8
9:4 -> 24:16 24:16
7:1 -> IMPOSSIBLE
7:7 ->
6:15 -> 16:40

Si la relación de transmisión deseada es imposible, imprima "IMPOSIBLE". Si no se requieren engranajes, imprima la cadena vacía.

Este es el código de golf, gana la respuesta más corta.

Keith Randall
fuente
¿No es la proporción de dientes inversamente proporcional a la velocidad angular? Entonces, por ejemplo, si la velocidad de entrada y salida deseada es 1: 5, ¿no debería ser la relación 40: 8 en lugar de 8:40? ¿O es la relación de la mano izquierda la relación efectiva entre dientes y engranajes que desea?
DavidC
Pregunta interesante ... 1:5 -> 8:40y 10:1 -> 40:8tiene sentido pero los demás no tanto.
Rob
@DavidCarraher: Creo que puedes definirlo de cualquier manera. Intenté ser internamente consistente. 1:5significa que el eje de salida gira 5 veces más lento, y un engranaje de 8 dientes en la entrada y un engranaje de 40 dientes en la salida hacen que eso suceda.
Keith Randall
@ MikeDtrick: bueno, 10:1 -> 40:8 16:8no es lo que dijiste. ¿Qué hay de los demás que te confunde? 9:4Se implementa haciendo 3:2dos veces. 3:2se implementa usando 24:16.
Keith Randall
2
@ MikeDtrick: Sí a tu primera pregunta. Para obtener 10: 1 puedes hacer 5: 1 (usando 40 dientes / 8 dientes) y luego 2: 1 (usando 16 dientes / 8 dientes). 7:7es lo mismo que 1:1, por lo que no requiere engranajes para implementar.
Keith Randall

Respuestas:

4

Python - 204

Ok, iré primero:

def p(n,a=[1]*9):
 n=int(n)
 for i in(2,3,5):
    while n%i<1:n/=i;a=[i]+a
 return a,n
(x,i),(y,j)=map(p,raw_input().split(':'))
print[' '.join(`a*8`+':'+`b*8`for a,b in zip(x,y)if a!=b),'IMPOSSIBLE'][i!=j]
editar:

Para 'optimizar' la salida, esto se puede agregar antes de la printdeclaración,

for e in x:
 if e in y:x.remove(e);y.remove(e)

trayendo el total hasta 266 caracteres , creo.

daniero
fuente
1
<1puede reemplazar ==0. Además, if b:a=...return apuede ser return b and...or a.
ugoren
No funciona para, por ejemplo, 23:12.
Keith Randall
Bien descrito. Sucede ya que 12 es divisible. Agregar elif i!=1:return[]al original resuelve el problema pero presenta otro. $ python gears.py <<< 21:28=> 24:16.. Voy a investigarlo. Parece que el problema no fue tan simple después de todo: DI Creo que el código tiene que ser aún más largo, o necesito otro enfoque.
daniero
Ahí tienes Creo que este funciona como se esperaba. Incluso lo hizo más pequeño :)
daniero
Se ve bastante bien, pero no es óptimo. 6:15puede hacerse con 16:40pero su código vuelve 24:40 16:24.
Keith Randall
4

Perl - 310 306 294 288 272

Estoy un poco oxidado con Perl y nunca hice un código de golf ... pero no tengo excusas. El recuento de caracteres no tiene saltos de línea. Usando perl v5.14.2.

($v,$n)=<>=~/(.+):(.+)/;
($x,$y)=($v,$n);($x,$y)=($y,$x%$y)while$y;
sub f{$p=shift;$p/=$x;for(5,3,2){
while(!($p%$_)){$p/=$_;push@_,$_*8}}
$o="IMPOSSIBLE"if$p!=1;
@_}
@a=f($v);@b=f($n);
if(!$o){for(0..($#b>$#a?$#b:$#a)){
$a[$_]||=8;
$b[$_]||=8;
push@_,"$a[$_]:$b[$_]"}}
print"$o@_\n"

Espero con interés las críticas y sugerencias. No es tan fácil encontrar consejos y trucos para code-golf (en perl).

Patrick B.
fuente
Puede guardar 9 caracteres eliminando $1:$2 -> , no es necesario en la salida.
DaveRandom
Oh, leí mal las especificaciones. Gracias.
Patrick B.
Puede reducir declaraciones como $a[$_]=8 if!$a[$_];a$a[$_]||=8;
ardnew
Las líneas nuevas cuentan como un personaje.
Timtech
La primera línea se puede abreviar a ($v,$n)=split/:|\s/,<>;(sin probar).
msh210
2

swi-prolog, 324 250 248 204 bytes

Prolog hace bastante bien en resolver un problema como este.

m(P):-(g(P,L),!;L='IMPOSSIBLE'),write(L).
g(A:A,''):-!.
g(A:B,L):-A/C/X,C>1,B/C/Y,!,g(X:Y,L);A/C/X,!,B/D/Y,C*D>1,g(X:Y,T),format(atom(L),'~D:~D ~a',[C*8,D*8,T]).
X/Y/Z:-(Y=5;Y=3;Y=2;Y=1),Z is X//Y,Y*Z>=X.

La entrada se pasa como un parámetro de término para predicar m. La salida se escribe en stdout. Perdón por el "verdadero" final; esa es solo la forma en que el intérprete me hizo saber que todo estaba bien.

?- m(54:20).
24:40 24:16 24:8 
true.

?- m(7:7).
true.

?- m(7:1).
IMPOSSIBLE
true.
Ruud Helderman
fuente
2

C, 246 216 213 bytes

En un intento (inútil) de superar mi propia solución Prolog, reescribí completamente la solución C.

b,c,d;f(a,b,p){while(c=a%5?a%3?a%2?1:2:3:5,d=b%5?b%3?b%2?1:2:3:5,c*d>1)c<2|b%c?d<2|a%d?p&&printf("%d:%d ",8*c,8*d):(c=d):(d=c),a/=c,b/=d;c=a-b;}main(a){scanf("%d:%d",&a,&b);f(a,b,0);c?puts("IMPOSSIBLE"):f(a,b,1);}

Mi solución C original (246 bytes):

#define f(c,d) for(;a%d<1;a/=d)c++;for(;b%d<1;b/=d)c--;
b,x,y,z;main(a){scanf("%d:%d",&a,&b);f(x,2)f(y,3)f(z,5)if(a-b)puts("IMPOSSIBLE");else
while((a=x>0?--x,2:y>0?--y,3:z>0?--z,5:1)-(b=x<0?++x,2:y<0?++y,3:z<0?++z,5:1))printf("%d:%d ",a*8,b*8);}

Fue un buen ejercicio demostrar que se puede hacer sin crear listas.

Ruud Helderman
fuente
2

Pyth, 101 bytes

(Es casi seguro que no compite en el concurso ya que usa un idioma más reciente que septiembre / 2012)

D'HJH=Y[)VP30W!%JN=/JN=Y+NY))R,YJ;IneKhm'vdcz\:J"IMPOSSIBLE").?V.t,.-Y.-hK=J.-hKYJ1In.*Npj\:m*8d_Np\ 

Una implementación de @daniero 'python answer pero semi-optimizada para Pyth.

D'H                               - Define a function (') which takes an argument, H.
   JH                             - J = H (H can't be changed in the function)
     =Y[)                         - Y = []
         V                        - For N in ...
          P30                     - Prime factors of 30 (2,3,5)
             W!%JN                - While not J%N
                  =/JN            - J /= N
                      =Y+NY       - Y = N + Y
                           ))R,YJ - To start of function, return [Y,J]

ENDFUNCTION

If 
         cz\:  - Split the input by the ':'
     m'vd      - ['(eval(d)) for d in ^]
   Kh          - Set K to the first element of the map (before the :)
  e            - The second returned value
             J - The second returned value after the : (The variables are globals)
 n             - Are not equal

Then 
"IMPOSSIBLE" - Print "IMPOSSIBLE"

Else
V                                      - For N in
 .t                1                   - transpose, padded with 1's
             .-hKY                     - 1st function first return - 2nd function first return
           =J                          - Set this to J
       .-hK                            - 1st function first return - ^
    .-Y                                - 2nd function first return - ^
   ,              J                    - [^, J]
                                         (Effectively XOR the 2 lists with each other)
                    I                  - If
                     n.*N              - __ne__(*N) (if n[0]!=n[1])
                         pj\:m*8d_N    - print ":".join([`d*8` for d in reversed(N)])
                                   p\  - print a space seperator

Pruébalo aquí

O prueba cada caso

Azul
fuente
0

ES6, 230 bytes

x=>([a,b]=x.split`:`,f=(x,y)=>y?f(y,x%y):x,g=f(a,b),d=[],a/=g,f=x=>{while(!(a%x))a/=x,d.push(x*8)},[5,3,2].map(f),c=d,d=[],a*=b/g,[5,3,2].map(f),a>1?'IMPOSSIBLE':(c.length<d.length?d:c).map((_,i)=>(c[i]||8)+':'+(d[i]||8)).join` `)

Uno de mis campos de golf más largos, así que debo haber hecho algo mal ...

x => {
    [a, b] = x.split(":");
    f = (x, y) => y ? f(y, x % y) : x; // GCD
    g = f(a, b);
    f = x => {
        r = [];
        while (!(x % 5)) { x /= 5; r.push(5); }
        while (!(x % 3)) { x /= 3; r.push(3); }
        while (!(x % 2)) { x /= 2; r.push(2); }
        if (x > 1) throw "IMPOSSIBLE!";
        return r;
    }
    c = f(a);
    d = f(b);
    r = [];
    for (i = 0; c[i] || d[i]; i++) {
        if (!c[i]) c[i] = 8;
        if (!d[i]) d[i] = 8;
        r[i] = c[i] + ":" + d[i];
    }
    return r.join(" ");
}
Neil
fuente