Равлик у криниці


47

Фон

Існує загальна загадка, яка йде приблизно так:

Равлик знаходиться на дні 30-футового колодязя. Щодня равлик здатний підніматися на 3 фути. Вночі, коли вони сплять, вони ковзають назад на 2 фути. Скільки днів потрібно, щоб равлик вийшов із криниці?

Інтуїтивно зрозуміла відповідь

30 днів, оскільки равлик піднімається 1 футом на день протягом 30 днів, щоб досягти вершини,

але насправді відповідь така

28 днів, оскільки колись равлик на 27 футів у повітрі (через 27 днів), вони просто піднімуться на 3 дні на вершину 3 фути на вершину.

Виклик

Цей виклик узагальнює цю загадку. Враховуючи три цілі натуральні числа, що представляють загальну висоту, висоту підйому та висоту падіння, поверніть кількість днів, які знадобляться, щоб піднятися зі свердловини.

Якщо равлик не може вилізти з криниці, ви можете повернути 0, повернути помилкове значення або викинути виняток. Ви також можете написати код, який зупиниться, якщо і лише тоді, коли існує рішення.

За бажанням ви можете взяти висоту падіння як від’ємне ціле число.

Випробування

(30, 3, 2) -> 28
(84, 17, 15) -> 35
(79, 15, 9) -> 12
(29, 17, 4) -> 2
(13, 18, 8) -> 1
(5, 5, 10) -> 1
(7, 7, 7) -> 1
(69, 3, 8) -> Немає
(81, 14, 14) -> Немає

Оцінка балів

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



8
Я, мабуть, нагороду отримаю, якщо хтось відповість у "Сірому равлику" Сторінка Esolangs - це лише порожня заглушка, але є певна інформація та доступний онлайн-компілятор , а також зразок програми для проблеми з 99 пляшками пива .
musicman523

4
Я думав, що це буде просто проста формула, але справа в справах напрочуд цікава.
xnor

У вас ще є "скільки годин ....". Відповідь - 27 * 24 + 12 (припускаючи 12-годинний «день»).
Френсіс Деві

2
@WheatWizard Я присуджую нагороду за найкоротший відповідь Сірої равлики
musicman523

Відповіді:


21

Сірий равлик , 1206 байт для числового вводу / виводу, 149 байт для одинарного вводу / виводу

Задля розваги. Склад першої програми:

  • 451 байт, перетворюючи число в крапки
  • 121 байт, основна функція (окрема версія написана нижче)
  • 634 байти, перетворюючи крапки в число

Візьміть числовий вхід і вихід. Вхід A, B, Cвідповідно. Порівняно з іншими (близькими) O(1)відповідями, код має складність O(n). Але для великої кількості це може спочатку з'їсти вашу пам’ять.

Повісьте, якщо не знайдено рішення.

INPUT p
POP Z r .!
f
POP Z o .
q
POP Z p [p]
GOTO [Z]
0
POP Z n .
GOTO w
1
POP Z n ..
GOTO w
2
POP Z n ...
GOTO w
3
POP Z n ....
GOTO w
4
POP Z n .....
GOTO w
5
POP Z n ......
GOTO w
6
POP Z n .......
GOTO w
7
POP Z n ........
GOTO w
8
POP Z n .........
GOTO w
9
POP Z n ..........
GOTO w
w
POP Z o .[o][o][o][o][o][o][o][o][o][o][n]
GOTO [r] [p] 
GOTO q
!
POP Z A .[o]
INPUT p
POP Z r .@
GOTO f
@
POP Z B .[o]
INPUT p
POP Z r .#
GOTO f
#
POP Z C .[o]
POP H N .[B]
U
POP Z A [A]
POP Z B [B]
GOTO D [A] 
GOTO $ [B] 
GOTO U
$
POP Z A .[A][C]
POP Z H ..[H]
POP Z B .[N]
GOTO U
D
POP Z r .
POP Z M .
POP Z N ...........
POP Z z .[N]
POP Z V .[H]
+
GOTO l[V] [H] 
POP Z H [H]
POP Z z [z]
GOTO ( [z] 
GOTO +
(
GOTO ) [H] 
POP Z z .[N]
POP Z M ..[M]
POP Z V .[H]
GOTO +
)
POP Z r .0[r]
POP Z M ..[M]
POP Z H .[M]
POP Z M .
POP Z V .[H]
POP Z z .[N]
GOTO +
l
POP Z r .0[r]
GOTO -
l.
POP Z r .1[r]
GOTO -
l..
POP Z r .2[r]
GOTO -
l...
POP Z r .3[r]
GOTO -
l....
POP Z r .4[r]
GOTO -
l.....
POP Z r .5[r]
GOTO -
l......
POP Z r .6[r]
GOTO -
l.......
POP Z r .7[r]
GOTO -
l........
POP Z r .8[r]
GOTO -
l.........
POP Z r .9[r]
GOTO -
-
GOTO / [M] 
POP Z H .[M]
POP Z M .
POP Z V .[H]
POP Z z .[N]
GOTO +
/
OUTPUT [r]

f- це (можливо) рекурсивна функція для перетворення цілих чисел у крапки. Аргумент зберігається [p]і виводиться в [o].

Uце тестування функцій S1>=S2, зберігаючи параметр у B, A, зберігаючи A-Bв A.

Код, починаючи з D- це заглушка, що перетворює крапки в цифри.

Принцип, що лежить в основі, збігається з моєю відповіддю С (зірвавши помилковий вихід за неможливі рішення).

Автономна версія, 149 156 157 167 170 230 байти, підтримуються лише одинарні введення / виведення

Введення має бути крапками, наприклад ..........для 10.

INPUT A
INPUT B
INPUT C
POP N H .
GOTO U
$
POP N A .[A][C]
POP Z H ..[H]
U
POP Z A [A]
POP Z N ..[N]
GOTO D [A] 
GOTO $ .[B] [N]
GOTO U
D
OUTPUT .[H]

Uобчислює A=A-Bі стрибає до того, Dколи A<=0. В іншому випадку $призначається A+Cдля Aі виклику U.

Повісьте, якщо не знайдено рішення.

Прийоми: зловживати здатністю "компілятора" інтерпретувати порожній рядок. Ви можете зірвати умови в GOTOоператорі, щоб зробити безумовні стрибки, і для того ж працює трюк POP.

Зауваження: я можу переграти його більше на 3 байти, але, роблячи це, моя відповідь і відповідь WheatWizard матимуть таку ж логіку. Результат, мабуть, є найкоротшим рішенням GraySnail, і я намагаюся це довести.


Ви зробили це першим
Евгений Новиков

Гей, я просто думав, що я дам вам знати, що я знову зробив мою коротшою, ніж ваша. Його лише байт коротший, і він черпає певне натхнення з вашого останнього гольфу.
Пшеничний майстер

@WheatWizard У мене є 155-байтне рішення на основі вашої старої відповіді. Але щодо спортивної майстерності я не сприйматиму це як свою відповідь.
Кейу Ган

@KeyuGan Ні, продовжуй. Мене не хвилює реп. Я щасливий, що мене побили. Якщо мій код можна пограти в гольф, я винен, що не бачив його. :)
Пшеничний майстер

@WheatWizard Мене ні. Я впевнений, що це найкращий час, який я коли-небудь проводив на PPCG.
Кейу Ган

20

Зауважте: підрахунок байтів ставить під сумнів Мартін Ендер у коментарях. Здається, немає чіткого консенсусу щодо того, що робити з названими рекурсивними лямбда-виразами у відповідях на C #. Тому я поставив питання в Meta про це.

C # (.NET Core) , 32 31 байт

f=(a,b,c)=>a>b?1+f(a-b+c,b,c):1

Спробуйте в Інтернеті!

Рекурсивний підхід. Якщо равлик не може втекти, це закінчується таким повідомленням:Process is terminating due to StackOverflowException.

  • 1 байт збережено завдяки LiefdeWen!

1
Ви можете зберегти байт байт зміни a<=bв a>bі заміни наступних частин
LiefdeWen

3
Таже код працює в ES6f=(a,b,c)=>a<=b?1:1+f(a-b+c,b,c)
Tushar

Вам доведеться порахувати код, який призначає функцію імені, якщо ви покладаєтесь на це ім'я fдля рекурсивного виклику.
Мартін Ендер

4
Я не займаюся гольфом на C #, тому я не зовсім впевнений, що таке консенсус, але я б очікував, що для цього потрібна повна заява з декларацією fта крапкою з комою, якщо вона названа. Перше, що я знайшов, це це, але тут немає чіткого консенсусу.
Мартін Ендер

2
@MartinEnder Я, як правило, так само, як це зробив Карлос, оскільки декларація лише f=...я не впевнений у тому, чи слід додати напівколонку до кінця, хоча.
TheLethalCoder

13

GREY SNAIL, 219 206 169 167 159 156 146 байт (одинарний IO)

INPUT a
INPUT u
INPUT d
POP U c 
GOTO 1
3
POP f a [a][d]
POP U c ..[c]
1
GOTO 2 [a] 
GOTO 3 [U] [u]
POP f U ..[U]
POP f a [a]
GOTO 1
2
OUTPUT [c].

Я думаю, що я можу трохи пограти в гольф.


Вітаємо!
Кейу Ган

11

JavaScript (ES6), 31 28 27 байт

Збережено кілька байт завдяки @Arnauld

Я не розумів, що ми можемо зазнати невдачі за винятком. Досить впевнений, що це оптимально:

u=>d=>g=h=>h>u?1+g(h-u+d):1

Призначте змінну з, наприклад f=, тоді дзвоніть як f(climb)(fall)(height). Кидає, InternalError: too much recursionякщо піднятися неможливо.


JavaScript (ES6), 38 байт

f=(h,u,d=0)=>h>u?u>0?1+f(h-u,u-d):+f:1

Рекурсивна функція, яка повертає кількість днів, або NaNніколи.

Тестові справи


2
Це очевидно: якщо равлик робить занадто багато рекурсії , то піднятися неможливо. :)
Тушар

1
Можливо 27 із синтаксисом зворотного каррі? d=>u=>g=h=>h>u?1+g(h-u+d):1
Арнольд

@Arnauld Дякую, що працює напрочуд добре ...
ETHproductions

Я переплутав повторно число байтів - в одну змінна функція присвоєна t включена, в іншу ні?
Відображувати ім’я

@Orangesandlemons у верхній версії, у вас є g=посередині, оскільки ця змінна зберігає проміжну функцію, необхідну для рекурсивного виклику. Більш довга відповідь виконує рекурсивний дзвінок f, який вимагає включення імені до числа байтів.
musicman523

10

Excel, 51 46 байт

-1 байт завдяки @ Scarabee .

-4, тому що INT (x) = ПОЛЬ (x, 1)

=IF(B1<A1,IF(C1<B1,-INT((B1-A1)/(B1-C1)-1)),1)

Введення взято з клітин А1, В1 і С1 відповідно. Повернення FALSEдля недійсних сценаріїв.


ceiling(x)завжди дорівнює -floor(-x), тому я думаю, що ви можете зберегти 1 байт, замінивши CEILING((A1-B1)/(B1-C1)+1,1)на -FLOOR((B1-A1)/(B1-C1)+1,1).
Скарабей

7

C (gcc), 39 43 44 46 47 58 60 байт

Тільки на 32-розрядному GCC і всі оптимізайтони відключені.

f(a,b,c){a=a>b?b>c?1+f(a-b+c,b,c):0:1;}

Повертайте 0, коли рішення неможливо. Модифікована версія оригінального рекурсивного рішення.

Натхненний рішеннями @Jonah J та рішенням @CarlosAlejo C #.

Я оновлю розширену версію пізніше (після того, як закінчу відповідь "Сірий равлик").


Хороший! Ви можете, будь-ласка, включити аналітичне (нестиснене) рішення?
koita_pisw_sou

1
@koita_pisw_sou Звичайно.
Кейу Ган

Це взагалі нічого не "повертає". Ви призначаєте локальний параметр, значення якого випаровується після повернення функції. Равлик застряг у вічній кінцівці.
Коді Грей

@CodyGray використовує стабільну, але невизначену поведінку в GCC. Я можу показати вам посилання пізніше.
Кейу Ган


7

Java (OpenJDK 8) , 35 байт

(a,b,c)->b<a?c<b?(a+~c)/(b-c)+1:0:1

Спробуйте в Інтернеті!

Математика перемагає!

Кредити


1
Минув час, але a-c-1a+~c.
Кевін Круїссен

1
Дякую @KevinCruijssen Минув час, але гольф - це гольф, незалежно від того, коли це станеться :-)
Олів'є Грегоар,

Мої думки точно. Декілька разів, коли я переглянув деякі мої перші відповіді, я взяв участь у гольфі приблизно вдвічі. ;)
Кевін Круїссен

5

Python 2 , 37 байт

f=lambda x,y,z:x-y<1or 1+f(x-y+z,y,z)

Спробуйте в Інтернеті!

Нарешті я отримав мою рекурсивну версію нижче мого стандартного розрахунку (я передавав підрахунок до своєї функції замість того, щоб додати її, перш ніж викликати її).

Пітон 2 , 4346 байт

#43 bytes
lambda x,y,z:y/x>0 or[1-(x-y)/(z-y),0][z/y]
#46 bytes
lambda x,y,z:y/x and 1or[1-(x-y)/(z-y),0][z/y]

Спробуйте в Інтернеті!

Поголив 3 байти, торгуючи "__ та 1" за "__> 0".

Використовуючи булеву хитрість, по суті виконує:

if floor(y/x) > 0:
    return True # == 1
elif floor(z/y) == 1:
    return 0
elif floor(z/y) == 0:
    return 1-floor((x-y)/(z-y))
    # Python 2 implicitly treats integer division as floor division
    # equivalent: 1 + math.ceil((y-x)/(z-y))
    # because: -floor(-x) == ceil(x)

2
Ви повинні поставити f=перед своїм кодом (перше рішення), і кількість байтів стає 37, оскільки він є рекурсивним, тому ви не можете залишити його анонімним. f=можна відкинути на лямбда лише тоді, коли вона не викликає рецидивів.
Містер Xcoder

Помічено та адресовано. Дякую, що повідомив.
Coty Johnathan Saxman

4

R, 43 байти

Запозичення з інших відповідей:

g=function(a,b,c)`if`(b<a,1+g(a-b+c,b,c),1)

Помилка, якщо немає рішення.


Гарна відповідь. Ласкаво просимо до PPCG!
musicman523

3

J, 25 байт

По-перше, приємне рішення, яке є обманом, оскільки передбачає, що "нічого, крім позитивного цілого результату", дорівнює "Немає":

>.>:%/2-/\

пояснення

  • 2-/\використовуйте вікна довжиною 2 на вході 3 пункту, розміщуючи знак мінус між кожним, який для введення 30 3 2, наприклад, повертає27 1
  • %/ помістіть символ поділу між кожним елементом списку, у нашому випадку у списку є лише два пункти, тому це означає "розділити 27 на 1"
  • >: приріст на 1
  • >. візьміть стелю

офіційне рішення

Ось офіційне рішення, яке перетворює негативи та нескінченність у 0, частина яких я не змогла знайти задовільно коротке рішення для:

0:`[@.(>&0*<&_)>.>:%/2-/\

ТІО


If the snail cannot climb out of the well, you may return 0, return a falsy value, or throw an exception.Для написання тестових випадків я просто вирішив Noneвказати, що відповіді немає. Чи могли б ви також додати пояснення та спробувати посилання Інтернет?
musicman523

@ musicman523 виправлено і виконано.
Джона



2

Математика, 47 40 39 байт

If[#==#2,1,⌈(#-#3)/(#2-#3)⌉~Max~0]&

-7 байт від @KeyuGan


Вам потрібно мати справу з введенням як 69, 3, 8і вважається 3 байтами, наскільки я думаю.
Кейу Ган

все виправлено! спробуйте зараз
J42161217

ви можете використовувати Maxдля заміни Ifоператора. If[#<=#2,1,Max[⌈(#-#3)/(#2-#3)⌉,0]]&
Кейу Ган


2

Пакет, 66 байт

@set/an=%4+1,a=%1-%2+%3
@if %1 gtr %2 %0 %a% %2 %3 %n%
@echo %n%

Другий тестовий випадок нічого не надрукував, а останній тестовий випадок справді розбився CMD.EXE...


2

05AB1E , 19 байт

0[¼²+D¹<›i¾q}³-D1‹#

Пояснення:

0                   Initialise stack with 0
 [                  while(true)
  ¼                   increment the counter variable
   ²+                 add the second input to the top of the stack
     D¹<›i            if it is greater than or equal to the first input
          ¾             push the counter variable
           q            terminate the program
             }        end if
              ³-      subtract the third input from the top of the stack
                D     duplicate top of stack
                 1‹   if it is less than 1
                   #  break the loop

Для недійсних значень це може повернути будь-яке значення менше 1. Однак у 05AB1E лише 1 є правдоподібним, тому це відповідає вимозі, що вихідне значення для недійсного значення має бути хибним.

Спробуйте в Інтернеті!


2

PHP, 60 байт

[,$h,$v,$d]=$argv;echo$h>$v?$v>$d?ceil(($h-$d)/($v-$d)):N:1;

відбитки Nдля None. Бігайте з -r.



2

Japt , 12 байт

@UµV-W §W}aÄ

Перевірте це в Інтернеті!

Виходи undefinedніколи, після можливого заморожування браузера на деякий час, тому будь ласка, будьте обережні.

Я не впевнений, що це оптимально. oWV-W lпрацює над усіма, крім останніх трьох випадків ...


З цим придумали 11 байт, змінивши порядок входів.
Кудлатий

2

Haskell , 30 29 байт

(b!c)a=1+sum[(b!c)$a+c-b|a>b]

Спробуйте в Інтернеті!

Коротше, ніж існуюча відповідь Haskell. Можливо, хтось інший може побити мене.

Для цього використовується рекурсивний підхід до вирішення проблеми. Кожна рекурсія - це по суті день руху для равлики. Якщо відстань, що залишилася до кінця, менша за необхідну відстань, ми припиняємо свою рекурсію.


Зберегти 1 байт з інфіксной записи: (b#c)a=1+sum[(b#c)$a+c-b|a>b].
Лайконі

@Laikoni Не знав, що можна зробити. Дякую за пораду.
Пшеничний майстер

Ви можете опустити паролі навколо b!cв розумінні списку.
Згарб

2

QBIC , 31 23 байт

Щойно помітили, що вимоги змінилися. Ця версія не перевіряє, чи равлик коли-небудь досягне вершини криниці.

≈:-:>0|q=q+1┘a=a-b+:]?q

Пояснення, наведене нижче, для оригінальної версії, яка перевіряє наявність рішення, охоплює і всі відповідні частини цього коду.


Оригінал, 31 байт відповідь:

~:>:|≈:-a>0|q=q+1┘c=c-a+b]?q\?0

Пояснення

~           IF
 :          cmd line arg 'a'  (the increment of our snail)
  >         is greater than
   :        cmd line arg 'b'  (the decrement, or daily drop)
    |       THEN
≈           WHILE
 :          cmd line arg 'c'  (the height of the well)
  -a        minus the increment (we count down the hieght-to-go)
    >0|     is greater than 0 (ie while we haven't reached the top yet)
q=q+1       Add a day to q (day counter, starts at 1)
┘           (syntactic linebreak)
c=c-a+b     Do the raise-and-drop on the height-to-go
]           WEND
?q          PRINT q (the number of days)
\?0         ELSE (incrementer <= decrementer) print 0 (no solution)

Спробуйте в Інтернеті! (Гаразд, не дуже: це переклад QBIC на код QBasic, запущений у repl.it (дещо бракує) оточення QBasic)


2

Excel VBA, 47 байт

Анонімна функція негайного вікна VBE, яка приймає вхід з діапазону [A1:C1]від ActiveSheetоб'єктних виходів до безпосереднього вікна VBE

Це, насамперед, рішення на основі формули Excel, здається, менше, ніж будь-яке суто рішення VBA, яке я можу придумати :(

?[If(B1>C1,-Int((B1-A1)/(B1-C1)-1),Int(A1=B1))]

1

Haskell, 47 55 байт (48, якщо потрібен кортеж)

f d c s|d<=c=1|c<s= -1|d>c||c<s=1+(f(d-c+s)c s)

варіація кортежу

f(d,c,s)|d<=c=1|c<s= -1|d>c||c<s=1+(f(d-c+s)c s)

Пояснення

f d c s       function that does all the heavy lifting =)
              d - depth
              c - climb per day
              s - slide per night

 |d<=c=1             recursion terminator. 1 day of climbing 
 |c<s= -1            possibility check. top can't be reached
 |otherwise=1+(f(d-c+s)c s)  1 day plus the rest of the distance

1
1. Ви можете замінити d>c||c<sпросто на 0<1, як ви вже неявно це робите у своєму поясненні, оскільки otherwiseце лише синонім True. 2. Рекурсивний виклик у вашій кортежній версії все ще залишається викритим. 3. Ви можете визначити свою функцію, (d#c)sзамість того f d c sщоб зберегти більше двох байтів.
Лайконі

1
Вам також потрібно c<=sзамість c<s.
Лайконі

1
Впорядкування та використання 0замість -1дозволених ОП дає 38 байт: Спробуйте в Інтернеті!
Лайконі

1
Чи можете ви використовувати ідентифікатор інфіксації для збереження будь-яких байтів?
musicman523

Я не знаю, чи варто публікувати відредагований ансер, оскільки це відповідь esentialy @ Laikoni
Сергій Мартиненко-молодший



1

C # (.NET Core) , 37 байт

(h,c,f)=>h>c?f<c?1+(h-f-1)/(c-f):0:1;

Нерекурсивна лямбда. Тут знайдено формулу використання . Можна скоротити на 6 байт, якщо "будь-який негативний результат" є дійсним способом повернення відмови; наразі повертає 0 замість цього.


Минув час, але h-f-1може бути h+~f.
Kevin Cruijssen

1

Python v2 & v3, 44 байт

f=lambda x,y,z:1+f(x-(y-z),y,z)if x>y else 1

^ Нескінченна рекурсія (помилка) для жодного випадку.


Можна використовувати лямбда. Крім того , це , здається , схожий на мій (Java) відповідь , щоб дозволити мені запропонувати поліпшення в формулі (x-z-1)//(y-z)+1. Я мало займаюся Python, тому можу помилитися ...
Олів'є Грегоар

Ви можете усунути f=кількість байтів, видалити пробіли навколо ifs та elses та перейти на Python 2, де ціле поділ є єдиним/
musicman523

Дякуємо @ musicman523. Я зрештою взяв усі ваші поради.
veganaiZe

1
Я зрозумів, що мій "чистий" (без нескінченної рекурсії) код мав безліч проблем, пов'язаних із кутом справи, коли використовувався з іншими входами (тобто 4, 3, 8). @ musicman523 Я думаю, я починаю бачити "докази", про які ви говорите.
veganaiZe

1

Програмований калькулятор HP-15C, 26 байт

Три числа завантажуються в стек для того, щоб запустити програму. Висота падіння вводиться як від’ємне число. Якщо равлик не може вилізти зі свердловини, результатом є або негативне число, або помилка № 0 (нульова помилка поділу).

Коди Op у шістнадцятковій формі:

C5 C1 B4 C5 FB 74 1A C4 FA B4 C5 FD C1 C1 A3 70 C6 F0 B4 FA EB F1 FA B2 0A F1

Значення інструкцій:

x↔y 
ENTER
g R⬆
x↔y 
− 
g TEST x≤0 
GTO A
R⬇
+ 
g R⬆
x↔y 
÷ 
ENTER
ENTER
f FRAC
TEST x≠0 
EEX 
0 
g R⬆
+ 
g INT 
1 
+ 
g RTN 
f LBL A
1

Ви можете спробувати програму за допомогою цього симулятора HP-15C .


Це круто! Ласкаво просимо до PPCG :)
musicman523


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.