Передаточні коефіцієнти Lego


23

Я будую гігантського робота-лего, і мені потрібно створити певні передаточні коефіцієнти, використовуючи набір передач. У мене багато передач із загальними розмірами зубчастих коліс: 8, 16, 24 або 40 зубів. Написати програму, яку я можу використовувати, коли я ввожу передавальне співвідношення, і програма підказує мені, яку комбінацію передач я повинен використовувати, щоб отримати потрібне співвідношення.

Коефіцієнт введення визначається на стандартному вході (або еквіваленті вашої мови) з двома цілими числами, розділеними двокрапкою. Співвідношення a:bозначає, що вихідний вал повинен обертатися в a/bрази швидше, ніж вхідний вал.

Вихід до стандартного виходу повинен представляти собою один рядок, що містить розділений пробілом список передавальних передач, у вигляді x:yде xрозмір шестірні на вхідному валу і yрозмір шестірні на вихідному валу. Потрібно використовувати мінімально можливу кількість передач для даного співвідношення. Кожен xі yповинен бути одним із 8,16,24,40.

приклади:

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

Якщо потрібне передавальне число неможливе, надрукуйте "НЕМОЖЛИВО". Якщо передачі не потрібні, надрукуйте порожній рядок.

Це кодовий гольф, виграє найкоротша відповідь.


Чи не співвідношення зубів обернено пропорційне кутовій швидкості? Так, наприклад, якщо бажана швидкість входу на виході дорівнює 1: 5, чи не повинно співвідношення бути 40: 8 замість 8:40? Або співвідношення лівої руки - ефективне співвідношення зубців зубчастого колеса до фактичного зубця передач, яке ви хочете?
DavidC

Цікаве питання ... 1:5 -> 8:40і 10:1 -> 40:8має сенс, але інших не так вже й багато.
Роб

@DavidCarraher: Я думаю, ви можете визначити це будь-яким способом. Я намагався бути внутрішньо послідовним. 1:5означає, що вихідний вал обертається в 5 разів повільніше, і 8 зубчастих передач на вході та 40 зубчастих передач на виході робить це.
Кіт Рендалл

@MikeDtrick: ну, 10:1 -> 40:8 16:8не те, що ти сказав. Що з іншими вас бентежить? 9:4реалізується, роблячи 3:2двічі. 3:2реалізується за допомогою 24:16.
Кіт Рендалл

2
@MikeDtrick: Так, на ваше перше запитання. Щоб отримати 10: 1, ви можете зробити 5: 1 (використовуючи 40 зубів / 8 зубів), а потім 2: 1 (використовуючи 16 зубів / 8 зубів). 7:7це те саме, що 1:1, тому для його здійснення не потрібно передач.
Кіт Рендалл

Відповіді:


4

Пітон - 204

Гаразд, я піду першим:

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]
редагувати:

Щоб "оптимізувати" вихід, це можна додати до printзаяви,

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

доведення загальної кількості до 266 символів , я вважаю.


1
<1може замінити ==0. Також if b:a=...return aможе бути return b and...or a.
угорен

Чи не працює, наприклад, 23:12.
Кіт Рендалл

Добре помічений. Він проходить через 12 ділення. Додавання elif i!=1:return[]до оригіналу вирішує проблему, але вводить іншу. $ python gears.py <<< 21:28=> 24:16.. Я розберуся. Здається, проблема не була такою простою: DI Думаю, що код повинен бути ще довшим, або мені потрібен інший підхід.
daniero

Ось так; Я думаю, що цей працює як очікувалося. Навіть зробив її меншою :)
daniero

Виглядає досить добре, але це не оптимально. 6:15можна зробити, 16:40але ваш код повертається 24:40 16:24.
Кіт Рендалл

4

Perl - 310 306 294 288 272

Я трохи іржавий з perl і ніколи не робив код-гольф ... але ніяких виправдань. Підрахунок знаків без перерв ліній. Використання 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"

Я з нетерпінням чекаю критики та підказки. Знайти поради та рекомендації щодо коду-гольфу (в перл) не так просто.


Ви можете зберегти 9 символів, видаливши $1:$2 -> , це не потрібно у висновку.
DaveRandom

О, я неправильно прочитав специфікацію. Спасибі.
Патрік Б.

Ви можете зменшити заяви як $a[$_]=8 if!$a[$_];на$a[$_]||=8;
ardnew

Нові рядки вважаються одним символом.
Timtech

Перший рядок можна скоротити до ($v,$n)=split/:|\s/,<>;(неперевіреного).
msh210

2

swi-prolog, 324 250 248 204 байт

Prolog досить добре вирішує подібну проблему.

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.

Введення передається як параметр терміна для предикату m. Вихід записується в stdout. Вибачте за останню 'правду'; ось лише спосіб перекладача повідомити мені, що все було добре.

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

?- m(7:7).
true.

?- m(7:1).
IMPOSSIBLE
true.

2

C, 246 216 213 байт

У (марній) спробі перемогти власний розчин Prolog я повністю переписав рішення 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);}

Моє оригінальне рішення C (246 байт):

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

Це було приємною вправою довести, що це можна зробити без складання списків.


2

Pyth, 101 байт

(Майже напевно не змагається в конкурсі, оскільки використовує мову, новішу за сеп / 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\ 

Реалізація відповіді python @daniero, але напів оптимізована для 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

Спробуйте тут

Або перевірити кожен випадок


0

ES6, 230 байт

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` `)

Один з моїх найдовших гольфів, тож, мабуть, я зробив щось не так ... Ungolfed:

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(" ");
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.