Напишіть програму, яка виводить її рівень дзеркала


31

Є 95 символів для друку ASCII :

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

У шрифті Consolas (за замовчуванням блоку коду Stack Exchange) деякі символи мають дзеркала навколо вертикальної осі симетрії:

  • Ці пари символів є дзеркалами один одного: () [] {} <> /\
  • Ці символи є дзеркалами самі по собі: ! "'*+-.8:=AHIMOTUVWXY^_ovwx|(Зверніть увагу, що простір - це одне.)
  • У них немає дзеркал: #$%&,012345679;?@BCDEFGJKLNPQRSZ`abcdefghijklmnpqrstuyz~

( i, l, 0, #, І , можливо , інші персонажі є їх власні дзеркала в деяких шрифтах , але ми будемо дотримуватися форми Consolas.)

Кажеться, що струна є дзеркалом сама по собі, якщо вона зроблена лише з 39 дзеркальними символами , розташованими таким чином, що струна має центральну вертикальну лінію симетрії. Так ](A--A)[само є дзеркалом, але ](A--A(]це не так.

Напишіть однорядну програму рівної довжини, яка є дзеркалом самого себе. Коли до нього заздалегідь приготовлено N примірників лівої половини, а до нього додано N примірників правої половини, він повинен вивести N + 1. N - невід'ємне ціле число.

Наприклад, якщо програма була ](A--A)[(ліва половина:, ](A-права половина -A)[:), то:

  • Біг ](A--A)[повинен вивести 1. (N = 0)
  • Біг ](A-](A--A)[-A)[повинен вивести 2. (N = 1)
  • Біг ](A-](A-](A--A)[-A)[-A)[повинен вивести 3. (N = 2)
  • Біг ](A-](A-](A-](A--A)[-A)[-A)[-A)[повинен вивести 4. (N = 3)
  • . . .
  • Біг ](A-](A-](A-](A-](A-](A-](A-](A-](A-](A--A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[повинен вивести 10. (N = 9)
  • тощо.

Правила

  • Вихід у stdout або найближча альтернатива вашої мови. Можливо, необов'язковий кінцевий новий рядок. Не слід брати жодної інформації.
  • Процес теоретично повинен працювати для N до 2 15 -1 або більше, маючи достатню кількість пам'яті та обчислювальної потужності.
  • Потрібна повна програма, а не лише команда REPL .

Виграє найкоротша початкова програма (N = 0 випадків) у байтах.


У деяких шрифтах також #є його власне відбиття, але, ви маєте рацію, не в консолях.
SuperJedi224

1
Чи дозволено використання repls? Іншими словами: чи слід написати повну дійсну програму чи достатньо вирази? Я думаю про запис Haskell, який би працював під час роботи в ghci, але не є дійсною повною програмою.
Бакуріу

@Bakuriu Потрібна повна програма. Відповідь Haskell недійсна.
Захоплення Кальвіна

4
Чому не є дзеркалами 'b' та 'd' для інших? Це робить мій план неможливим: P
Thijs ter Haar

1
@ThijsterHaar Я насправді цього не вважав, але, схоже, їх консольні форми просто трохи відрізняються, вибачте: P
Хобі Кальвіна

Відповіді:


20

Піп, 12 8 4 байти

Тепер на 66% менше байтів!

x++x
  • xє змінною, попередньо ініціалізованою до "". У числовому контексті це стає 0.
  • Перша половина, не фінал +, робить вираз форми x+x+...+x. Це дійсна заява, яка нічого не робить.
  • Друга половина, включаючи заключну +з першого тайму, виражає форму ++x+x+...+x. ++xприріст xдо 1, а решта додає його собі N разів. Оскільки вираження оцінюються зліва направо в Pip, приріст гарантовано відбудеться спочатку, а результат дорівнює кількості рівнів дзеркала.
  • Наприкінці значення цього виразу автоматично друкується.

На жаль, Pip не дуже добре обробляє величезні вирази: це рішення викликає maximum recursion depth exceededпомилку для N вище 500 або близько того. Ось попереднє рішення, яке не відповідає 8 байтам :

x++oo++x

Детальніше про Pip


Гаразд, якщо хтось не опублікує 2-байтну відповідь, схоже, що ви отримали цю в сумці. До речі, я не знаю, чи ви працюєте з N = 32767 , але фактичний вихід є Fatal error: maximum recursion depth exceeded while calling a Python object.
Денніс

@Dennis Так, я натрапив на це насправді - він починається досить рано, близько 600, якщо не раніше. Причина полягає в тому, що вирази оцінюються шляхом рекурсивної оцінки спочатку всіх підекспресій, тому x+x+...+xгенерується O (N) глибина рекурсії. Можливо, це не відповідає цій відповіді. Я додам записку.
DLosc

Межа рекурсії легко регулюється в Python, чи не так?
Денніс

@Dennis Так, хоча є серйозні попередження про те, що це зробить для вашої системи, якщо ви встановите її занадто високо, тому я ніколи не пробував цього. ;) Крім того, налаштувати її неможливо зсередини Pip , тому мені здається, що це начебто моє обман. Якщо ви хочете спробувати, мені було б цікаво почути результати.
DLosc

Я намагався. На моїй машині, збільшивши межу рекурсії до 20000 вже зрізних значень. Але оскільки відповідь має працювати лише при достатній кількості пам'яті та обчислювальної потужності , це не повинно бути проблемою.
Денніс

34

GolfScript, 10 байт

!:{)::(}:!

Спробуйте в Інтернеті за допомогою Web Golfscript: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Web GolfScript має обмеження 1024 символів, але перекладач Ruby чудово справляється з N = 32767 :

$ curl -Ss http://www.golfscript.com/golfscript/golfscript.rb > golfscript.rb
$ echo '"!:{):"32768*":(}:!"32768*' | ruby golfscript.rb > mirror-level-32767.gs
$ ruby golfscript.rb mirror-level-32767.gs
32768

Як це працює

Без будь-якого введення GolfScript спочатку має порожній рядок у стеці.

У першій лівій половині відбувається таке:

  • !застосовується логічно НЕ до порожнього рядка. Це штовхає 1.

  • :{зберігає ціле число на стеку у змінній {.

    Так, це дійсний ідентифікатор, хоча неможливо отримати збережене значення.

  • ) збільшує ціле число на стеку.

  • : - неповна інструкція.

Наступні ліві половинки, трапляються наступне:

  • :!(де :залишок раніше) зберігає ціле число на стеку в змінній !.

    Так, це також дійсний ідентифікатор. Це порушує !команду, але ми її більше не використовуємо.

  • :{, )і :працювати як раніше.

У першій правій половині відбувається таке:

  • ::(де :залишок раніше) зберігає ціле число на стеку в змінній :.

    Так, навіть це дійсний ідентифікатор. Як і у випадку {, немає способу отримати збережене значення.

  • ( зменшує ціле число на стеку, отримуючи кількість лівих половинок.

  • }, оскільки він є неперевершеним і негайно припиняє виконання.

    Це недокументована особливість. Я називаю їх суперкомментантами .

Решта код просто ігнорується.


Дуже дивно здається, що }у 2-й половині вашого коду не дорівнюють за дзеркальною конкуренцією.
ballesta25

Це поширений трюк у варіантах паліндром. У "\""/", четверта подвійна цитата буде не збігатися, так як друга втеча була уникнута.
Денніс

27

Код машини Z80, 8 6 байт *

<8ww8> * Передбачає певні умови, ввівши з Amstrad BASIC

<   INC A         // A=A+1
8w  JR C, #77     ## C is unset unless A has overflowed, does nothing

w   LD (HL), A    // Saves A to memory location in HL (randomly initialised)
8>  JR C, #3E     ## C is still unset, does nothing

Aпочатково 0, коли вводиться з BASIC. Він збільшується A n разів, потім записує його n разів у те саме місце пам’яті (яке встановлюється злегка випадковим розташуванням BASIC)! Операція JRJump Relative ніколи нічого не робить, оскільки Cпрапор завжди не встановлений, тому використовується для "коментування" наступного байта! Ця версія трохи обманює, якщо передбачити певні умови в'їзду, а саме вхід із гарантій BASIC, який Aзавжди дорівнює 0. Місцезнаходження (HL)не гарантується як безпечне, і насправді це, мабуть, небезпечне місце. Наведений нижче код набагато надійніший, тому він настільки довший.

Код машини Z80, 30 байт

Як ASCII: o!.ww.!>A=o>{))((}<o=A<!.ww.!o

В основному, перша половина гарантує створення нульового значення, а друга половина збільшує його і записує його в пам'ять. У розгорнутій версії нижче ##позначається код, який не виконує жодної мети на своїй половині дзеркала.

o   LD L, A       ## 
!.w LD HL, #772E  // Load specific address to not corrupt random memory!
w   LD (HL), A    ## Save random contents of A to memory
.!  LD L, #21     ## 
>A  LD A, #41     // A=#41
=   DEC A         // A=#40
o   LD L, A       // L=#40
>{  LD A, #7B     ## 
)   ADD HL, HL    // HL=#EE80
)   ADD HL, HL    // HL=#DD00. L=#00 at this point

((  JR Z, #28     ## 
}   LD A, L       // A=L
<   INC A         // A=L+1
o   LD L, A       // L=L+1
=   DEC A         // A=L
A   LD B, C       ## 
<   INC A         // A=L+1
!.w LD HL, #772E  // Load address back into HL
w   LD (HL), A    // Save contents of A to memory
.!  LD L, #21     ## 
o   LD L, A       // L=A

Розбивка дозволених інструкцій:

n   op    description
--  ----  -----------
28  LD    LoaD 8-bit or 16-bit register
3   DEC   DECrement 8-bit or 16-bit register
1   INC   INCrement 8-bit or 16-bit register
1   ADD   ADD 8-bit or 16-bit register

Available but useless instructions:
3   JR    Jump Relative to signed 8-bit offset
1   DAA   Decimal Adjust Accumulator (treats the A register as two decimal digits
          instead of two hexadecimal digits and adjusts it if necessary)
1   CPL   1s ComPLement A
1   HALT  HALT the CPU until an interrupt is received

З 39 дозволених інструкцій, 28 - це операції з завантаження (блок від 0x40 до 0x7F - це всі однобайтові LDінструкції), більшість з яких тут не допомагають! Єдине завантаження в пам'ять інструкції все ще дозволено, це LD (HL), Aозначає, що я повинен зберігати значення в A. Оскільки Aєдиний реєстр, що залишився з дозволеною INCінструкцією, це насправді досить зручно!

Я не можу завантажити Aз 0x00 для початку, тому що ASCII 0x00 не є дозволеним символом! Усі доступні значення далекі від 0, а всі математичні та логічні вказівки заборонені! За винятком ... Я ще можу зробити ADD HL, HL, додати 16-бітний HLдо себе! Крім прямого завантаження значень (тут немає ніякого використання!), Збільшення Aта декрементація A, Lабо HLце єдиний спосіб змінити значення регістра! Насправді є одна спеціалізована інструкція, яка може бути корисною у першій половині, але болісно обійтися у другій половині, і інструкція з доповненням, яка тут майже марна і просто займе місце.

Отже, я знайшов найближче значення до 0, яке я міг: 0x41. Наскільки це близько до 0? У двійковій вона 0x01000001. Тож я його декрементую, завантажую Lі роблю ADD HL, HLдвічі! Lтепер дорівнює нулю, на який я завантажую назад A! На жаль, код ASCII для ADD HL, HL, )тому мені тепер потрібно використовувати (два рази. На щастя, (є JR Z, e, де eнаступний байт. Тож він піднімає другий байт, і мені просто потрібно переконатися, що він нічого не робить, обережно ставившись до Zпрапора! Остання інструкція вплинути на Zпрапор була DEC A(протиінтуїтивно, ADD HL, HLне змінює його), і оскільки я знаю, що Aв цей момент було 0x40, гарантовано, що Zце не встановлено.

Перша інструкція у другій половині JR Z, #28нічого не зробить перші 255 разів, оскільки прапор Z може бути встановлений лише у тому випадку, якщо A переповнений з 255 до 0. Після цього вихід буде помилковим, однак, так як він так само зберігає лише 8-бітові значення не має значення. Код не слід розширювати більше 255 разів.

Код повинен бути виконаний як фрагмент, оскільки всі доступні способи чистого повернення були заборонені. Всі вказівки щодо повернення вище 0x80, і кілька дозволених операцій стрибків можуть переходити лише до позитивного зміщення, тому що всі 8-бітові негативні значення також заборонені!


6
ЩО. ЩО ЦЕ.
cloudfeet

4
Тепер я бачив цю відповідь, використовуючи GolfScript / J / тощо. просто здається, що обман. : p
cloudfeet

Чи є процесори, сумісні з Z80, з 16-бітовим A-регістром? Я запитую, оскільки питання вимагає, щоб код працював для N = 32767 .
Денніс

1
@Dennis Щоб програма працювала на N = 32767, вона повинна мати принаймні 2 x 32767 або 65534 байт. Z80 може адресувати лише 65536 байт пам'яті, що робить це неможливим завданням, оскільки я не вірю, що я можу зробити програму меншою за 6 байт! У Aрегістрі завжди 8 біт, інакше процесор не був би сумісний із Z80. Я б сказав, що з урахуванням достатньої кількості пам'яті та обчислювальної потужності тут було закрито!
CJ Dennis

1
@Dennis Ви розумієте, чому жоден процесор, сумісний із Z80, не матиме Aреєстру нічого, крім 8 біт? Якщо змінити його на 16-біт, це може порушити код, покладаючись, наприклад, на 255 + 1 = 0. Вам слід було б винайти процесор, дозволить назвати його Z160, який використовує 16-розрядний регістр за замовчуванням, але все ще використовує ту саму 8-бітну інструкцію, встановлену з Z80. Дивно!
CJ Dennis

19

J, 16 14 байт

(_=_)]++[(_=_)

Використання:

   (_=_)]++[(_=_)
1
   (_=_)]+(_=_)]++[(_=_)+[(_=_)
2
   (_=_)]+(_=_)]+(_=_)]++[(_=_)+[(_=_)+[(_=_)
3

Пояснення:

  • J оцінює справа наліво.

  • (_=_)це inf equals infщо вірно, має значення 1, так що вираз стає 1+]...[+1. ( (8=8)також буде працювати, але це виглядає крутіше. :))

  • [і ]повернути їх лівий і правий аргументи відповідно, якщо вони мають 2 аргументи. Якщо вони отримують лише 1, вони повертають це.

  • +додає 2 аргументи. Якщо він отримує лише 1, він повертає це.

Тепер давайте оцінимо вираз 3 рівня (йде справа наліво):

(_=_)]+(_=_)]++[(_=_)+[(_=_)  NB. (_=_) is 1

1]+1]+1]++[1+[1+[1  NB. unary [, binary +

1]+1]+1]++[1+[2  NB. unary [, binary +

1]+1]+1]++[3  NB. unary [, unary +

1]+1]+1]+3  NB. unary +, binary ]

1]+1]+3  NB. unary +, binary ]

1]+3  NB. unary +, binary ]

3

Як ми бачимо, 1додається права половина 's, а ліва частина 1' s опускається, що призводить до бажаного цілого числа N, рівня дзеркала.

Спробуйте його онлайн тут.


12

Хаскелл, 42 байти

(8-8)-(-(8-8)^(8-8))--((8-8)^(8-8)-)-(8-8)

На щастя, лінійний коментар у Haskell (-> --) є дзеркальним, і половина (-> -) є дійсною функцією. Решта - це математика для отримання чисел 0і 1. В основному ми маємо (0)-(-1)коментар для N=0та додаємося (0)-(-1)-до кожного кроку.

Якщо для виводу дозволені числа з плаваючою комою, ми можемо побудувати 1з 8/8та отримати з допомогою 26 байт:

Haskell, 26 байт

(8-8)-(-8/8)--(8\8-)-(8-8)

Виходи 1.0, 2.0і т.д.


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

@ Calvin'sHobbies: я бачу. Чи маємо консенсус щодо мінімальних вимог до повної програми? Я шукав мета, але знайшов лише обговорення функцій, а не програм. Залежно від визначення повної програми, можливо, я зможу виправити своє рішення.
німі

Я б назвав це повноцінною програмою, якщо ви можете зберегти її у файлі, program.hsа потім запустити $ runhaskell program.hsз командного рядка і побачити вихід. Я не знаю Haskell, тому я не можу точно сказати, що потрібно змінити.
Захоплення Кальвіна

2
@ Calvin'sHobbies: runhaskellце сценарій оболонки, який створює певне середовище і, нарешті, викликає ghc, компілятор Haskell. Ви можете запустити свій код безпосередньо ghc: ghc -e "(8-8)-(-8/8)--(8\8-)-(8-8)". Це запускає, ghcщо оцінює код, наданий як аргумент, друкує результат та виходить. Ні відмови, ні взаємодії. Звичайно, це додасть +1 до кількості байтів -e.
німі

@nimi: -eне сприяє оцінці в цьому випадку. Ми не рахуємо байтів для того perl -Eчи gcc -std=c99іншого.
Денніс

11

CJam, 14 байт

]X+:+OooO+:+X[

Спробуйте в Інтернеті в інтерпретаторі CJam: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

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

Як це працює

У лівій половинці відбувається таке:

  • ] загортає весь стек у масив.

  • Xдодає 1до цього масиву.

  • :+ обчислює суму всіх елементів масиву.

  • Oo друкує вміст порожнього масиву (тобто нічого).

У першій правій половині відбувається таке:

  • o друкує ціле число на стеці, яке є бажаним результатом.

  • O+ намагається додати порожній масив до найвищого елемента стека.

    Однак стек був порожній перед натисканням O. Це виходить з ладу і припиняє виконання програми.

Решта код просто ігнорується.

1 Відповідно до мета опитування Чи слід дозволити виходу із запитом помилки? , це дозволено.


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

Такі завдання, як ця, на CJam дивно важкі, враховуючи, що це мова для гольфу. Навіть помилка синтаксису (наприклад, невизначений оператор) у невиконаному блоці запобіжить виконанню всієї програми. Я все ще намагаюся позбутися помилки.
Денніс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.