Напечатайте фразу «И она сказала:« Но это его ».», Используя только алфавит

51

Напечатайте фразу, And she said, 'But that's his.'используя только следующие символы: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ Никаких знаков препинания или неалфавитных символов. Вы можете использовать любой язык программирования, который вы хотите. Пробелы полностью разрешены. Кратчайшая программа выигрывает.

Ястреб
источник
Как насчет пробелов в выводе? (ведущий / конечный?)
attinat
2
Черт, мой esolang не может завершить, потому что нет возможности производить только вывод a-zA-Z. Теоретически я мог бы использовать write и Eval для создания необходимых инструкций, но ни один из них не +-*,%'"может быть создан без использования (по крайней мере) одного из +-*,%'"0-9.
Draco18s
11
(programmer-of (language 'lisp))не любит это.
МэтьюРок
4
Должен признаться, сначала я не думал, что это будет особенно интересно, но сочетание повторяющихся и уникальных символов действительно сделало оптимизацию забавной (особенно на языке стека!). Очень хорошо.
brhfl
1
Можете ли вы уточнить, разрешены ли дополнительные пробелы в выводе ? Нравится дополнительный трейлинг-перевод строки? Или только пробел в источнике плюс буквенные символы. Есть ответ Befunge, который печатает с дополнительным завершающим переводом строки.
Питер Кордес

Ответы:

75

Пробелы , 417 414 349 265 байт

265 байтов благодаря Кевину Круйссену

  							
  				   
   		 	
   		
   	 
  		   		 
 	  		
 	  		 
   			 
  		 	
   	 
 	  	 
 	  		 
 	  	
   				
  		  	  
  							
 	  	  
  				 	 
  		 
   		
  		 	
   		 	
 	  	 	
  		
   	 
 	  		
 	  		
  		 
   	   
  		  	 	

  
   		  		 
	   	
  
 


Попробуйте онлайн!

Разъяснение:

[S S T  T   T   T   T   T   T   N
_Push_-63_'][S S T  T   T   T   S S S N
_Push_-53_.][S S S T    T   S T N
_Push_13_s][S S S T T   N
_Push_3_i][S S S T  S N
_Push_2_h][S S T    T   S S S T T   S N
_Push_-70_space][S T    S S T   T   N
_Copy_0-based_3rd_s][S T    S S T   T   S N
_Copy_0-based_6th_'][S S S T    T   T   S N
_Push_14_t][S S T   T   S T N
_Push_-5_a][S S S T S N
_Push_2_h][S T  S S T   S N
_Copy_0-based_2nd_t][S T    S S T   T   S N
_Copy_0-based_6th_space][S T    S S T   N
_Copy_0-based_1st_t][S S S T    T   T   T   N
_Push-15_u][S S T   T   S S T   S S N
_Push_-36_B][S S T  T   T   T   T   T   T   N
_Push_-63_'][S T    S S T   S S N
_Copy_0-based_4th_space][S S T  T   T   T   S T S N
_Push_-58_,][S S T  T   S N
_Push_-2_d][S S S T T   N
_Push_3_i][S S T    T   S T N
_Push_-5_a][S S S T T   S T N
_Push-13_s][S T S S T   S T N
_Copy_0-based_3rd_space][S S T  T   N
_Push_-1_e][S S S T S N
_Push_2_h][S T  S S T   T   N
_Copy_0-based_3rd_s][S T    S S T   T   N
_Copy_0-based_3rd_space][S S T  T   S N
_Push_-2_d][S S S T S S S N
_Push_8_n][S S T    T   S S T   S T N
_Push_-37_A][N
S S N
_Create_Label_LOOP][S S S T T   S S T   T   S N
_Push_102][T    S S S _Add][T   N
S S _Print_as_character][N
S N
N
_Jump_to_Label_LOOP]
каменная паукообразная
источник
101
Whitespace is completely allowed.Я вижу, вы поняли это буквально.
Бенджамин Уркхарт
3
Вы победили меня в этом .. Хотя некоторые вещи могут быть в гольф. :) Вы можете удалить трейлинг NNNдля выхода, так как он уже останавливается с ошибкой, когда вы выполняете добавление до print_char, поэтому он даже не будет следовать после Jump_to_Label. Кроме того, зачем хранить 63в начале и получить его в цикле? Вы можете просто нажать его перед добавлением. И почему ярлык-номер TTSSSSTN? Метка может даже быть пустой, поэтому достаточно просто NSSNсоздать метку и NSNNперейти к метке, когда вы используете только одну метку.
Кевин Круйссен
1
318 байт с изменениями, которые я предложил выше. Вот та же программа с добавленной подсветкой. А как вы вычитали постоянную величину 63? Я не уверен на 100%, что здесь самая короткая постоянная. Если это так, что-то не так с моей постоянной генерирующей программой, которую я написал для более ранней задачи. :)
Кевин Круйссен
1
Да, я был прав. Константа 102самая эффективная: 281 байт (или здесь с подсветкой ). (ПРИМЕЧАНИЕ: я также использовал одну копию, чтобы сохранить 4 байта для пробела между ними ehs dnA(скопировано из пробела между ними dias ehs).
Кевин Круйссен
3
Хорошо, теперь я закончил. :) 265 байт (или здесь с подсветкой ). Добавлены некоторые дополнительные копии. ( Вот соответствующий совет по
пробелам
63

Perl 5 , 133 102 95 байт

s qqAnd she saidZ ZBut thatZs hisZZGjGGfq x
s qZqchr oct oct oct ord chopqge x
y qGjfqqdx
print

Попробуйте онлайн!

Объяснение:

Регулярные выражения, print и chop все применяются к переменной $_по умолчанию.

s qqAnd she saidZ ZBut thatZs hisZZGjGGfq

Заменяет пустую строку на And she saidZ ZBut thatZs hisZZGjGGf.

s qZqchr oct oct oct ord chopqge

Заменяет каждый Zс результатом evaling chr oct oct oct ord chop. Это удаляет последний символ $_, берет его код ключа, интерпретирует его как восьмеричный трижды и преобразует его обратно в символ. Например, j→ 106 → 70 → 56 → 46 → ..

Из-за того, как работает замена, изменения, $_которые происходят при оценке замены, теряются, $_как и сейчас And she said, 'But that's his.'GjGGf.

y qGjfqqd

Удаляет все G, jи fв $_.

Grimmy
источник
27
Не зная Perl, похоже, что вы только что пытались напечатать предложение, но в процессе участвовали в нескольких боях с вашей кошкой
popctrl
2
Это может быть самый красивый фрагмент кода, который я когда-либо видел на этом сайте, и я говорю это как тот, кто знает Perl.
Сильвио Майоло
1
Связанные, но вы можете заменить printс sayна -2 символов. Текущий мета-консенсус говорит, что флаги командной строки -M5.010не учитываются в счетчиках байтов.
Сильвио Майоло
34

> <> , 916 915 903 байта

Сначала я думал, что решение в> <> невозможно, но потом я понял ... кому нужны условные выражения или логическое управление? : D

fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffloffffffffffffffffffffffffffffffffffffffffffffflopppgloppppppppppppppppppppppggloffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffflopppggloploppppppppppppppppppppppploffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffflopppppplofffffffflopggloppppppppppppppppppgglopppplofffffffloffffffffffffffffffffffffffflofffffffffffffffffffffffffffffffffffffffffffffffffffloglopppppppppppppppppppppppppppplofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffflopppploppgloffffffffffffffffffflopppppppppppppppppppppppppgglofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffflopppppppppppppppppppppppppppgglofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffflofloffffffffffloppppppppppppppppppppppploppgloio

Попробуйте онлайн

Я неоднократно помещаю числа (число 15) в стек, затем увеличиваю длину стека и печатаю символ с этим значением ASCII. Если мне нужно уменьшить длину стека, я уменьшаю в стеке три значения за раз, используя p, или одно за раз, используя, gесли я в пределах трех от цели. Программа заканчивается вызовом i(input), который нажимает a, -1так как нет ввода, а затем печатает его, чтобы вызвать ошибку.

Это программа на Python 3, которую я использовал для создания решения, когда подумал, как это сделать:

s = "And she said, 'But that's his.'"
L = [0]+[ord(c) for c in s]
#print(L)
M = L[1:]+[0]
D = [x[1]-x[0] for x in zip(L,M)]
#print(D)
while D:
	n=D.pop(0)
	if not D:print('io',end='');exit()
	if n>0:print('f'*n,end='lo')
	else:
		while n<-2:print('p',end='');n+=3
		print('g'*-n,end='lo')

Попробуйте онлайн

mbomb007
источник
5
Это правильный контрапункт к решению пробелов! Получите +1 от меня, я также ценю программу генерации ...
Франческо
Последний раздел может быть полностью удален с осторожным использованием p: создать 59 в стеке при движении вверх от пространства к sдюйму said, а затем поместить его в коде на пути вниз от dк ,. (Обратите внимание, что (15,15) имеет 15 к этому моменту.)
Nitrodon
На самом деле, вы можете злоупотреблять lи pпомещать несколько полезных символов в прямоугольник (10,10) - (15,15), а затем извлекать их gтам, где это более удобно.
Нитродон
Это действительно хорошая идея. Так трудно думать о> <> таким образом. Это как кодирование с BF
mbomb007
Я отправил свой собственный ответ: codegolf.stackexchange.com/a/186916/69059
Nitrodon
28

Сборка 8086 на IBM PC, 1463 845 664 байта

Пояснение: Фактическим источником ассемблера является запись, а не сгенерированный машинный код.

Сложность заключается в том, что большинство инструкций x86 (таких как ADD, SUB, JMP, условные переходы, доступ к памяти) имеют два аргумента и, следовательно, нуждаются в запятой или адресе памяти. Таким образом, мы не можем использовать сложение, вычитание, ifs или циклы!

Во время моей первой попытки я смог «построить» числа, используя комбинацию приращения, уменьшения, умножения, деления, байт-трюков и непонятных команд BCD (таких как AAA, DAS). После этого я понял, что эту идею можно использовать для создания самоинспектируемого и самоизменяющегося кода.

  • Попытка 1. (1463 байта)

    Использовали доступные инструкции для построения кодов ASCII и адреса 0xb800 экранного буфера. Расчет каждого персонажа в последовательности был сыгран вручную.

  • Попытка 2. (не завершена)

    Понял, что есть код операции для каждого целого числа в диапазоне 0x40-0x5f. Этот диапазон включает AZ. Так, например, INC CX соответствует 0x41 = 'A'. (Эта таблица кодов операций очень удобна.)

    Я попытался создать 3 строки «данных» и наложить их друг на друга. Первый «как есть» (в верхнем регистре), второй «смещен» в зону 0x60-0x7f (в нижнем регистре), а последний «сдвинут» в зону 0x20-0x3f (пунктуация).

    Самомодифицирующийся код создаст цикл или три для перебора данных.

  • Попытка 3. (845 байт)

    Как и в предыдущем подходе, но для сокращения данных строка будет закодирована только один раз, с «управляющими символами», смешанными для переключения наборов символов.

  • Попытка 4. (664 байта)

    Как избавиться от управляющих символов, которые требуют много исправленных инструкций, чтобы иметь дело с ветвлением? Учитывая, что используются только две заглавные буквы, я подумал, могу ли я «перевернуть» таблицу кодов операций для кодирования строчных букв, используя диапазон 0x40-0x4f и пунктуацию, используя диапазон 0x90-0x9f (вычитая из 0xc0). «А» и «В» могут быть вставлены отдельно.

    Однако только половина опкодов в диапазоне 0x90-0x9f пригодна для использования, и они не совпадают с необходимыми. Тогда я подумал, что, может быть, смогу перетасовать их, используя XOR, и нашел тот, который сработал. И вот оно.

Golfed:

REP LODSB
PUSH CX
PUSH CX
POP AX
INC CH
PUSH CX
POP DI
DEC AX
DEC AX
REPNE SCASB
REPNE SCASB
PUSH DI
REPNE SCASB
PUSH DI
REPNE SCASB
PUSH DI
POP SI
POP DI
DEC DI
LODSB
NOT AL
STOSB
POP CX
DEC CH
LODSB
NOT AL
STOSB
LODSB
AAA
STOSB
INC DI
LODSB
NEG AL
STOSB
LODSB
NOT AL
PUSH AX
PUSH AX
INC SP
POP ES
INC SP
POP DI
LODSB
NOT AL
PUSH AX
POP BX
NEG AL
STOSB
INC DI
LODSB
DEC AL
NEG AL
DIV BH
PUSH AX
POP DI
LODSB
STOSB
RET
DEC BL
PUSH CS
STOSB
PUSH DS
INC DI
INC AX
POP SI
PUSH SP
NOP
INC BP
POP AX
PUSH DI
NOP
INC BP
PUSH BX
POP BX
PUSH SP
PUSHF
NOP
CWD
PUSH DX
INC DI
INC SP
NOP
INC SP
POP AX
PUSH BX
INC SP
CWD
INC BP
NOP
POP AX
POP BX
INC BP
SAHF
CWD
SCASB
INC DX

Собрать с

nasm golf.asm -o golf.com

и запустите в DOSBOX (сначала запустите CLS). Выглядит так:

Образец вывода

комментарии:

; ASSUME DS = ES = CS
; ASSUME IP = 0x0100
; true for .COM file

; We treat 0xFE as a special marker that we scan for
; This marks our patch zone and the start of our data

; We also use it as a cheap trick to get a constant 0x1f
; into CX

; 0xFE is the first byte of INC or DEC instructions
; that operate on half-word registers (AL, BL, CH etc.)
; WATCH OUT! Adding these breaks the scan


; Can't assume any register contains zero
; so use this trick to zero out CX
REP LODSB

PUSH CX ; needed later

; zero AX
PUSH CX
POP AX

INC CH
PUSH CX
POP DI ; 0x100, where our code starts

DEC AX
DEC AX ; AL = 0xFE, our marker (AH = 0xFF)

REPNE SCASB ; skip the INC CH above
REPNE SCASB ; find the DEC CH located at 0x10E

; we will later need 0xF, the char count minus the 'A'
PUSH DI ; DI = 0x10F

REPNE SCASB ; find the patch position
PUSH DI

REPNE SCASB ; find the next 0xfe; our data section
PUSH DI
POP SI ; load data from here

POP DI ; store data to the patch position
DEC DI

; patch in XOR
; XOR is 0x34, start with 0xCB
; second byte of DEC BL is 0xCB
LODSB
NOT AL
STOSB

POP CX ; get 0x0f in CX for our strlen
DEC CH

; patch in our XOR arg
; it is 0xF1 (take 0x0E and NOT it)
LODSB ; 0x0E (PUSH CS)
NOT AL
STOSB

; ADD is 0x00 (take 0xAA, apply weird AAA behaviour)
; this also zeroes AH
LODSB ; 0xAA (STOSB)
AAA
STOSB

INC DI ; skip next instruction byte

; LOOP is 0xE2
LODSB ; 0x1E PUSH DS
NEG AL
STOSB


; get b800 in ES (address of screen buffer)
; first get 0x47 in AL (INC DI)
LODSB  ; get 0x47 (INC DI)
NOT AL ; NOT 0x47 = 0xb8
; AX = 0x00b8 (bytes backwards)

PUSH AX
PUSH AX
; stack contains 0xb8 0x00 0xb8 0x00
; stack off-by-1 trick
INC SP
; now POP gives you 0xb800
POP ES
INC SP ;and clean up after ourselves

; store 0 in DI ***** PUSHED AT START OF PROGRAM ***
POP DI


LODSB ; get our magic 0xC0 (0x40 INC AX)
NOT AL
PUSH AX
POP BX

NEG AL ; NOT and +1 to get 0x41 ("A")


; charloop:
STOSB
INC DI
LODSB
DEC AL ; XOR
NEG AL ; modify this into an ADD AL, BL
DIV BH ; modify this to LOOP back to charloop

; doesn't print the last character
; but the last character turns into the address where 'B'
; is supposed to go

PUSH AX
POP DI
LODSB ; "B"
STOSB

; graceful exit this time ;)
RET


; *** DATA SECTION ***

         ; PURPOSE

DEC BL   ; 0xFE marks data section, 0xCB for XOR
PUSH CS  ; for XOR arg
STOSB    ; for ADD
PUSH DS  ; for LOOP
INC DI   ; 0x47 -> for 0xb800

INC AX   ; for magic number but also "A"


POP     SI ;n
PUSH    SP ;d
NOP        ;
INC     BP ;s
POP     AX ;h 
PUSH    DI ;e
NOP        ;
INC     BP ;s
PUSH    BX ;a
POP     BX ;i
PUSH    SP ;d
PUSHF      ;,
NOP        ;
CWD        ;'
PUSH    DX ;B
INC     DI ;u
INC     SP ;t
NOP        ;
INC     SP ;t
POP     AX ;h
PUSH    BX ;a
INC     SP ;t
CWD        ;'
INC     BP ;s
NOP        ;
POP     AX ;h
POP     BX ;i
INC     BP ;s
SAHF       ;.
CWD        ;'

SCASB     ; treated as char but turns into screen address!
INC DX    ; "B"
Artelius
источник
Гектометр Я получаю разные файлы .COM из двух источников сборки, начиная со смещения 0x3e. Правка - Nvm обнаружил разницу: строка 117 в закомментированной версии есть, INC AXа без комментариев - INC AL.
гастропнер
1
Я хочу видеть полностью алфавитный двоичный файл вместо этого. :-)
Питер Ферри
1
Если вам удобно заблокировать NASM в качестве предпочтительного ассемблера, вы можете создавать метки, выполняя label1 dbотдельную строку. Это выдаст предупреждение, но без ошибки.
гастропнер
1
@gastropner хорошо, это просто сделало бы это слишком легким. : P Не знал об этом, спасибо! Может быть, я должен переименовать свой язык как «что-то, что вы можете добавить в DEBUG.COM». Который между прочим я использовал для отладки этого. xD
Артелий
1
@PeterCordes теперь этот самоизменяется!
Артелий
23

Perl 6 , 1299 1272 1220 1215 байт

Спасибо Грими за -27 байт.

-52 байта, потому что в первую очередь нам не нужны кроличьи уши.

Спасибо Джо Кингу за -5 байтов.

print chr flip chars i x chars i xx pi
and print lc chr chars NaN x chars cis pi
and print lc chr chars e x e x e
and print chr chars i x e x e x e
and print lc chr flip chars exp i
and print lc chr chars NaN x tau x e x e
and print chr chars chop NaN x e lcm chars e
and print chr chars i x e x e x e
and print lc chr flip chars exp i
and print lc chr flip chars i x chars i xx pi
and print chr chars False x pi x ceiling tau
and print lc chr chars e x e x e
and print chr chars i xx chars NaN x pi
and print chr chars i x e x e x e
and print chr chars chop False x e x e x e
and print chr chars chop NaN xx chars e
and print lc chr chars e x chars False
and print lc chr chars chop e x chars False
and print chr chars i x e x e x e
and print lc chr chars chop e x chars False
and print lc chr chars NaN x tau x e x e
and print lc chr flip chars i x chars i xx pi
and print lc chr chars chop e x chars False
and print chr chars chop False x e x e x e
and print lc chr flip chars exp i
and print chr chars i x e x e x e
and print lc chr chars NaN x tau x e x e
and print chr chars False x pi x ceiling tau
and print lc chr flip chars exp i
and print chr chars NaN xx tau x e
and say chr chars chop False x e x e x e

Попробуйте онлайн!

Выводит строку с завершающим переводом строки. Если вы не хотите этого, замените последний sayна print. Вы также можете заменить новые строки в источнике пробелами.

объяснение

Этот код печатает строку символ за символом. Каждый символ формируется путем подачи соответствующего кода символа в chrфункцию и, lcесли необходимо, в нижнем регистре .

В настоящее время все значения генерируются путем генерации строки с правильным количеством символов в ней; в некоторых случаях количество символов является обратным к целевому символьному коду. Теоретически должно быть возможно использовать математические функции, такие как logи expнепосредственно, но я не нашел, чтобы их было очень легко использовать.

Для использования в качестве чисел, мы имеем e, piи tau; в правой части xили xxони неявно перекрыты. Все они имеют 17 символов в своих строковых представлениях, поэтому мы используем eминимальное количество символов. У нас также есть i(4 символа), False(5 символов) и NaN(3 символа). Мы можем умножить длины строк на x; xxумножает один плюс длина строки на правую часть и добавляет один. chopудаляет один символ из строки в случае, если мы один от цели.

Операторы печати связаны друг с другом с использованием and, что имеет довольно низкий приоритет. Это почти чудо, оно существует; в противном случае нам пришлось бы использовать незаконные точки с запятой.

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

bb94
источник
1
1078 байт
Джо Кинг
Кстати, @JoKing, вы искали короткие выражения вручную или использовали программу, чтобы помочь?
BB94
1
Боюсь от руки. Алгоритмический путь, вероятно, не будет слишком сложным
Джо Кинг,
1
242 байта
Grimmy
@ Грими Умный, но, к сожалению, это возможно только потому, что используемое вами пространство нулевой ширины не является пробельным символом
Джо Кинг,
17

Ширина , 66 64 байт

QaaGmwmiimaGcwWiimawAGawmfciiiGaFmAmFiimFGcwAmFiGmaiiGcGamafFiGQ

Попробуйте онлайн!

Отпечатки для отладки. Для печати в stdout добавьте wwконец кода, который выскочит и выведет верхнюю часть стека.

объяснение

В ширине каждая буква соотносится с числом, исходя из того, насколько она широка, согласно этой таблице . Каждой букве присваивается число от 0 до 9. Затем эти цифры используются для фактического выполнения кода.

В частности, буква, отличная от совпадения 7, начнет строковый литерал. Он будет читать наборы из двух букв одновременно, пока не прочитает исходное письмо снова. Каждый набор из двух букв будет преобразован в их числа ширины, прочитанные как десятичное число от 0 до 99, и символ, которому они равны, будет их индексом в следующей строке:

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

Например, индекс !равен 1, поэтому 01будут правильные значения ширины. Таким образом, if, iI, jtи т.д. будет весь коррелят струнного литерала !.

В этом случае я перевел 31 символ требуемого вывода в соответствующие буквы, используя Qв качестве кавычек. Вершина стека печатается для отладки после завершения программы.

Стивен
источник
Это самый короткий пока. Я думаю, что вы могли бы победить!
Ястреб с синими крыльями
14

машинный код x86 (32-разрядный), 256 байт

Когда я печатаю свой код на консоли кодовой страницы 437, я вижу следующее:

j XI a I a I a jbZ      Q fiQ Gf a f    Q I a I a I a I a h hisZ        Q I a I a I a I a hBP  Z        Q iQ
y       Q  a I a I a I a h thaZ Q I a I a I a Ih ButZ   Q  a I a I a I a fhu fZf        Q iQ g  S       Q  a I a I a I a hsaidZ Q I a I a I a I a hshe Z        Q I a I a I a I a hAnd Z        Q TZBX b 

Он содержит некоторые пробельные символы, так что здесь один и тот же код, когда я заменяю все символы табуляции на и все неразрывные пробелы (с кодом 255) на *:

j XI a I a I a jbZ→Q fiQ Gf a f→Q I a I a I a I a h hisZ→Q I a I a I a I a hBP  Z→Q iQ →→y →Q  a I a I a I a h thaZ→Q I a I a I a Ih ButZ→Q  a I a I a I a fhu fZf→Q iQ g→S →Q  a I a I a I a hsaidZ→Q I a I a I a I a hshe Z→Q I a I a I a I a hAnd Z→Q TZBX*b*

HexDump:

6a 20 58 49 20 61 20 49 20 61 20 49 20 61 20 6a
62 5a 09 51 20 66 69 51 20 47 66 20 61 20 66 09
51 20 49 20 61 20 49 20 61 20 49 20 61 20 49 20
61 20 68 20 68 69 73 5a 09 51 20 49 20 61 20 49
20 61 20 49 20 61 20 49 20 61 20 68 42 50 20 20
5a 09 51 20 69 51 20 09 09 79 20 09 51 20 20 61
20 49 20 61 20 49 20 61 20 49 20 61 20 68 20 74
68 61 5a 09 51 20 49 20 61 20 49 20 61 20 49 20
61 20 49 68 20 42 75 74 5a 09 51 20 20 61 20 49
20 61 20 49 20 61 20 49 20 61 20 66 68 75 20 66
5a 66 09 51 20 69 51 20 67 09 53 20 09 51 20 20
61 20 49 20 61 20 49 20 61 20 49 20 61 20 68 73
61 69 64 5a 09 51 20 49 20 61 20 49 20 61 20 49
20 61 20 49 20 61 20 68 73 68 65 20 5a 09 51 20
49 20 61 20 49 20 61 20 49 20 61 20 49 20 61 20
68 41 6e 64 20 5a 09 51 20 54 5a 42 58 ff 62 ff

Некоторые пояснения о том, как это работает:

Полезные инструкции:

  • push imm8, push imm16а push imm32затем popгенерировать константы. Это также может генерировать ноль (in ah) при нажатии byte ( imm8).
  • and [ecx+32], ah- предполагая, что ах = 0, это устанавливает байт в ноль. Так уж получилось, что длина выходной строки равна 32, поэтому код заполняет буфер от конца до начала.
  • or [ecx+32], edx- при условии, что выходной байт установлен в ноль, это копирует edx(4 байта) для вывода. Я использую вариант с dxвместо edxконца буфера, потому что он не должен записывать за пределы выходного буфера. Ограничение на код делает невозможным запись отдельных байтов таким образом!
  • imul edx, [ecx+32], whatever- это основная идея борьбы. При достаточной энтропии [ecx+32]и любом количестве она может генерировать любой результат. Я использую его для генерации 2 или 3 байта необходимых значений. Некоторая сложность заключается в том, что при записи его в выходной файл он должен выполнять логические операции ORс тем, что уже есть. Это иногда приводило к необходимости обнуления памяти еще раз.
  • Вариант jmpинструкции используется для возврата. Я выбрал его, потому что это кодировка 0xff, которая соответствует неразрывному пробелу в кодовой странице 437. Немного натянуто по правилам, но в остальном я думаю, что задача невозможна ...

Исходный код сборки вместе с программой на C, которая его запускает (использует синтаксис Visual Studio):

#include <stdio.h>

__declspec(naked) void __fastcall doit(char* buf)
{
    __asm {
        push ' '
        pop eax

        dec ecx
        and [ecx+32], ah    // terminating 0 byte

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah

        push 98
        pop edx
        or [ecx+32], edx
        imul dx, [ecx+32], 26183
        and [ecx+32], ah
        or [ecx+32], dx    // two bytes: [.']

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push 'sih '
        pop edx
        or [ecx+32], edx    // 4 bytes: [ his]

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push 538988610
        pop edx
        or [ecx+32], edx
        imul edx, [ecx+32], 544803081
        or [ecx+32], edx // 1 junk byte and 3 good bytes: (t's)

        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push 'aht '
        pop edx
        or [ecx+32], edx    // 4 bytes: [ tha]

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        push 'tuB '
        pop edx
        or [ecx+32], edx    // 1 junk byte and 3 good bytes: [But]

        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push word ptr 8309
        pop dx
        or [ecx+32], dx
        imul edx, [ecx+32], 542312807
        or [ecx+32], edx    // 1 junk byte and 3 good bytes: [, ']

        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push 'dias'
        pop edx
        or [ecx+32], edx    // 4 bytes: [said]

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push ' ehs'
        pop edx
        or [ecx+32], edx    // 4 bytes: [she ]

        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        dec ecx
        and [ecx+32], ah
        push ' dnA'
        pop edx
        or [ecx+32], edx    // 4 bytes: [And ]

        push esp
        pop edx
        inc edx

        pop eax
        jmp dword ptr[edx-1]
    }
}

int main()
{
    char buf[100];
    doit(buf);
    puts(buf);
}
anatolyg
источник
Это не похоже на игру в гольф для меня. Конечно, вы бы сэкономили несколько байтов, используя циклы, а не повторяя серию идентичных инструкций. Все , что dec ecx+ and [ecx+32], ahматериал может быть вынесено.
Коди Грей
Вы можете попробовать. Это лучшее, что я мог сделать; Я был бы рад увидеть другой подход. Я решил отказаться от идеи циклов, когда увидел, что они требуют отрицательного смещения прыжка. Может быть, это ограничение можно решить творческим путем - я не знаю как.
Анатолий
1
@anatolyg Это может быть связано с позицией вашей тестовой среды на самоизменяющийся код. Или его мнения о выполнении кода, который вы создали в стеке.
гастропнер
Разве символ не 0xffнарушает "Никаких знаков препинания или неалфавитных символов вообще"?
Валь
13

PostScript, 889 874 837 835 байт

currentflat string dup rrand
count dup count count mul mul xor count count mul count dup mul exch count
count copy count copy count copy count copy count copy
add and sub put print
and sub add put print
sub sub add put print
mul or xor put print
idiv xor add put print
or xor add put print
mod idiv add put print
mul or xor put print
idiv xor add put print
sub and add put print
or and add put print
sub sub add put print
pop add sub put print
mul or xor dup copy put print
mod mul sub put print
add or xor put print
idiv add add put print
add or add put print
put print
add or add put print
or xor add put print
sub and add put print
add or add put print
mod mul sub put print
idiv xor add put print
mul or xor put print
or xor add put print
or and add put print
idiv xor add put print
xor add sub put print
mod mul sub put print
quit

Попробуйте онлайн!

Это использует 32 копии целых чисел 89 25 20 6. Все коды целевой строки могут быть получены с помощью операций с этими целыми числами в порядке стека: например, «A» (ASCII 65) равно 89 - (25 & (20 + 6)). Многие 4-целые кортежи имеют это свойство; этот был выбран, потому что их особенно легко генерировать.

currentflat string dup rrand

Flat по умолчанию равен 1, поэтому создается строка длиной 1 (инициализируется в \0). dupне глубокая копия: она создает вторую ссылку на ту же строку. rrand выталкивает случайное семя, которое по умолчанию равно 0. Стек теперь ["\0", "\0", 0].

count dup count count mul mul xor

count толкает количество элементов в стеке, так что это вычисляет 3 ^ (3 * (5 * 6)) = 89.

count count mul count dup mul exch count

4 * 5 = 20, 5 * 5 = 25, 6 = 6. Стек сейчас ["\0", "\0", 0, 89, 25, 20, 6].

count copy count copy count copy count copy count copy

Дублируйте весь стек пять раз. Таким образом, мы получаем 32 копии нашего начального стека из 7 элементов. Нам нужно всего лишь 31 копию, поскольку длина целевой строки составляет 31 символ, но дополнительная копия не помешает.

add and sub put print

Вычислите код из первых четырех целых чисел, запишите его в индекс 0 строки, затем напечатайте строку.

quit

Подавляет приглашение по умолчанию.

Grimmy
источник
11

Рубин , 420 354 338 байт

def P a
print String a
end
def Q a
p String a
end
class String
def inspect
putc sum size
q
end
end
def w
Q def hacked
end
rescue
end
P def And
end
w
P def she
end
w
P def said
end
Q def gadget
end rescue
w
def a
Q def afraid
end
rescue
end
a
P def But
end
w
P def that
end
a
putc String def s
end
w
P def his
end
Q def fierce
end rescue
a

Попробуйте онлайн!

В порядке возрастания рывков:

Слова, начинающиеся с заглавной буквы, можно распечатать, определив класс с таким именем и вызвав его displayв теле определения класса.

Другие слова можно отобразить, определив методы с этим именем, которое возвращает Symbol, а затем приведя его к String, чтобы удалить начальный двоеточие.

Другие символы могут быть отображены путем вызова putcих кода ASCII. Мы можем сгенерировать соответствующие числа, повторно используя String defтрюк, чтобы получить строку, а затем взяв сумму ее байтов, используя модуль, определяемый ее размером. К сожалению, у нас нет никакого способа вызвать методы объекта, кроме как из определения класса этого объекта, что затрудняет передачу аргументов. Таким образом, последний взлом заключается в переопределении String#inspect, которое вызывается неявно при передаче в pметод String , чтобы он вычислял и выводил соответствующий символ в качестве побочного эффекта, прежде чем выдавать ошибку, чтобы pфактически не завершить выполнение и напечатать новая линия. Тогда нам нужно спасти ошибку в основном коде.

Редактировать: Джордан сделал число байтов намного меньше, хм, высокий с некоторым умным управлением потоком управления, и я сократил еще несколько байтов, заменив raiseнесуществующим вызовом метода из одной буквы, который вызывает NameError.

Редактирование 2: заметил, что при print Stringизвлечении в метод дешевле использовать его с определением метода, чем использовать трюк с определением класса, поскольку методы допускаются в качестве заголовка.

histocrat
источник
Красиво .... Я не понимаю, как sum sizeполучается сумма по модулю ее размера, но все остальное проверяется!
Стоимость чернил
Я сказал это немного лениво, на самом деле размер строки передается как необязательный аргумент метода sum.
гистократ
11

> <> , 233 122 байта

cdacaabbglccgpcbfbbcaacdebbafbebbcebdbealbcpcdbcccdlcdpacbbalccpaalacpbcfafbaab









       g  sandBe
       o  Aviuth

Попробуйте онлайн!

Это началось с того, что я получил ответ mbomb , но я обнаружил фундаментальный сдвиг, который экономит огромное количество байтов, поэтому я публикую его как свой собственный ответ.

Генерирование не алфавитных символов для вывода выполняется путем многократного помещения значений в стек, а затем с lпомощью увеличения длины стека. Однако, это не должно pбыть выведено немедленно: используя , этот символ может быть помещен в любую ячейку, чьи координаты находятся между 10 и 15 включительно, чтобы быть найденными позже с g. Точно так же алфавитные символы могут быть помещены в исходный исходный код и читаться следующим образом: поскольку самый высокий код не алфавитного символа на входе равен 46 ( .), это означает, что стек не нужно помещать выше, чем 62, необходимые для хранения все 31 символов вывода.

Кроме того, vв коде в столбце 7 помещается символ a . Когда указатель команды оборачивается и попадает в него v, последовательность goповторяется для считывания из заданных координат и вывода соответствующих символов. В конце концов, стек становится пустым и gзавершает программу с ошибкой.

Первые 7 байтов кода используются повторно как переданные первые 7 и последние 7 координат. Размещение vв столбце 9 теоретически позволило бы сохранить еще два байта, но заставило бы символы Ainsvв квадрате 2x2 в коде, что невозможно. В более ранней версии использовался столбец 15, но это требовало дополнительной строки в исходном коде и заканчивалось на шесть байтов длиннее.

Nitrodon
источник
После дальнейших размышлений, я думаю, что смогу заставить колонку 9 работать, потратив один байт на rперемещение выравнивания куда я хочу. Тем не менее, игра в гольф от этой программы немного вредит моему мозгу.
Нитродон
8

CJam , 262 байта

  KAbScibCmhc  CZbsic          GmQYbsic
S CmfYmeibc    ImqmeKmhcel     AZbAbc
S CmfYmeibc    KAbScibCmhcel   ImqmeKmhAmhcel  GmQYbsic    KAZbYbbBbc
S CGmQbDbc     EYbTYtZbc       FYbGmQbcel      EYbGmQbcel
S EYbGmQbcel   ImqmeKmhcel     KAbScibCmhcel   EYbGmQbcel  CGmQbDbc    CmfYmeibc
S ImqmeKmhcel  ImqmeKmhAmhcel  CmfYmeibc       PYmhmeKmhc  CGmQbDbc

Попробуйте онлайн! Новые строки показаны здесь только для ясности; каждая строка представляет символ.

Вот это было весело. Ограничение себя алфавитными командами ставит некоторые интересные задачи:

  • Без {и }, практически нет возможности для потока управления (кроме того f, который я не нашел возможности использовать).
  • Без \, _, ;или $, у нас нет никаких средств для манипулирования стека.

Это означает, что основной целью будет получение соответствующих кодовых точек в стеке, а затем преобразование их в символы с помощью c.

Проблема в том, что нам также не хватает большинства основных арифметических команд, а также целочисленных литералов. Это хорошо, хотя, поскольку mпространство имен содержит множество сложных математических операций, и есть много переменных, предопределенных для полезных чисел.

В итоге я интенсивно использовал квадратные корни ( mQи mq), экспоненциальную функцию meи базовое преобразование ( b), которые также можно использовать для эмуляции умножения ( [X 0] Ybвычисляет X * Y). Кроме того, иногда проще создать заглавную кодовую точку, и в этом случае мы можем использовать el(преобразовать в нижний регистр) результирующий символ.

Я все еще не удовлетворен некоторыми из более длинных. Ну что ж.

объяснение

Это посимвольное объяснение вывода. Прежде чем я начну, вот несколько коротких способов сделать цифры:

  • 0, 1, 2, 3, содержатся в переменных T, X, Y, Zсоответственно.
  • Числа с 10 по 20 содержатся в переменных Aчерез K.
  • 32 можно сделать с помощью Sci( Sвыталкивает строку, содержащую пробел, cполучает первый символ этой строки и iпреобразует этот символ в его кодовую точку). Sтакже используется для пробелов.
  • 4 задается как GmQ(целочисленный квадратный корень из 16).
  • 5 задается как AZbYb(преобразовать 10 в базу 3, получая [1 0 1], и преобразовать полученный массив чисел в базу 2, получив 5).
  • 7 задается как Ymei(вычислить exp (2) и преобразовать в целое число).

A

K           - push 20                        | 20
 Ab         - convert to base 10             | [2 0]
   Scib     - convert from base 32           | 64
       Cmh  - hypot(TOS, 12)                 | 65.115
          c - round down and convert to char | 'A

n

C      - push 12            | 12
 Zb    - convert to base 3  | [1 1 0]
   s   - convert to string  | "110"
    i  - convert to integer | 110
     c - convert to char    | 'n

d

GmQ      - push 4             | 4
   Yb    - convert to base 2  | [1 0 0]
     s   - convert to string  | "100"
      i  - convert to integer | 100
       c - convert to char    | 'd

s

C         - push 12         | 12
 mf       - factors         | [2 2 3]
   Ymeib  - base 7          | 115
        c - convert to char | 's

h

I           - push 18                        | 18
 mq         - sqrt                           | 4.242
   me       - exp                            | 69.591
     Kmh    - hypot(TOS, 20)                 | 72.408
        c   - round down and convert to char | 'H
         el - lowercase                      | 'h

e

A      - push 10              | 10
 Zb    - convert to base 3    | [1 0 1]
   Ab  - convert from base 10 | 101
     c - convert to char      | 'c

a

KAbScibCmhc   - push 'A (see above) | 'A
           el - lowercase           | 'a

i

I              - push 18         | 18
 mq            - square root     | 4.242
   me          - exp             | 69.591
     Kmh       - hypot(TOS, 20)  | 72.408
        Amh    - hypot(TOS, 10)  | 73.095
           c   - convert to char | 'I
            el - lowercase       | 'i

,

K          - push 20              | 20
 AZbYbb    - convert to base 5    | [4 0]
       Bb  - convert from base 11 | 44
         c - convert to char      | ',

'

C        - push 12              | 12
 GmQb    - convert to base 4    | [3 0]
     Db  - convert from base 13 | 39
       c - convert to char      | ''

B

E         - push 14               | 14
 Yb       - convert to base 2     | [1 1 1 0]
   TYt    - replace elem 0 with 2 | [2 1 1 0]
      Zb  - convert from base 3   | 66
        c - convert to char       | 'B

u

F          - push 15             | 15
 Yb        - convert to base 2   | [1 1 1 1]
   GmQb    - convert from base 4 | 85
       c   - convert to char     | 'U
        el - lowercase           | 'u

t

E          - push 14             | 14
 Yb        - convert to base 2   | [1 1 1 0]
   GmQb    - convert from base 4 | 85
       c   - convert to char     | 'T
        el - lowercase           | 't

.

P          - push pi                        | 3.141
 Ymh       - hypot(TOS, 2)                  | 3.724
    me     - exp                            | 41.437
      Kmh  - hypot(TOS, 20)                 | 46.011
         c - round down and convert to char | '.
Esolanging Fruit
источник
1
Вы можете выполнять базовые преобразования с цифрами вне обычного диапазона для базы, например HYbYCtYbc, HYbXAtYbcи HYbXBtYbc.
Нитродон
7

Deadfish ~ , 943 байта

iiisdsiciiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiicddddddddddcddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcdddddddddddddddddddddsddddddcdddddddddddcdddcdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcdddddddddddddddddddddsddddddcddddddddddddddddddciiiiiiiicdddddcddddddddddddddddddddddddddddddddddddddddddddddddddddddddcddddddddddddciiiiiiiciiiiiiiiiiiiiiiiiiiiiiiiiiiciiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiicdcddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcdddddddddddddddddddddsdddddcddddddddddddcdddddddciiiiiiiiiiiiiiiiiiicdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcddddddddddddddddddddddddddddsddddddcdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcddddddddddddddddddddddsiiiiciciiiiiiiiiicdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddcdddddddc

Попробуйте онлайн!

Петли не допускаются :(

каменная паукообразная
источник
7

зло , 198 байт

aeeeannkhhwzuuuuuueaeuekwuuuuuuuuuunkhwzaeeeeehknwgueeywguuuuuuhhknnwuuuwhgwpwnngheeuwguuuuuwngwzaeeeaaaeeeeeewhhgwnguuuueewnngawpaawuwnngwpawhgwhhgeeuwpawhguuuueewpwhgwhgwawpwnngaaaaaaeeeewguuuueew

Попробуйте онлайн!

Это было довольно весело.

HyperNeutrino
источник
6

MATL , 187 158 байт

IEWQKEtqhpEqqKQHhthpKWEyQKWEqqYqQQXJwtQQQwKWEJKQthpYqKQHhthptQQQQQwIIhKQhpqKWEIWKQhpqIEWQQJQQtqKWEyIIhIhpYqQXJyKQthpYqwIWKQhpqyqKWEyJtQwhhPIIhKQhpQIWKQhpqvlec

Попробуйте онлайн!

Более читаемая версия: попробуйте онлайн! Ручная попытка построения строки. Вероятно, есть много места для игры в гольф, разрезая струны на удобные куски, используя Pи hдля переворачивания и построения струны. Я надеюсь, что кто-нибудь примет вызов, чтобы перехитрить меня. Основная проблема в том, что вы не можете использовать +или -, поэтому базовая арифметика часто невозможна.

Особенности:

  • KQthpYq: 25-е ( KQthp) простое число Yqравно 97, что соответствует букве a. Буква s(115) генерируется аналогично из 113, 30-го простого числа. Затем он широко используется в буфере обмена J.
  • hisсокращается путем сохранения hв буфере обмена J. Так как это ранее сохранено s, мы строим hisв обратном порядке, так что мы все еще можем извлечь недавнее sиспользование y, и перевернуть его после использования P.
  • Большое количество байтов сохранено благодаря Луису Мендо (в основном, путем изменения набора hв vle)
Sanchises
источник
Да, я действительно думал, что использование vпомешает hмне раньше. Думаю, мне следовало это сделать, а не просто предполагать. Кроме того, спасибо за заголовок, произошло чрезмерное удаление. Мне любопытно посмотреть, сможешь ли ты добиться большего успеха, чем это ...
Sanchises
Я бы хотел попробовать, но это подождет. Ответ на это, кажется, занимает много времени!
Луис Мендо
1
@LuisMendo Yup. Мне потребовался час или около того, чтобы сделать это, и это включает только очень локальную оптимизацию. Я уверен, что можно добиться большего, если взглянуть на вещи немного более глобально.
Санчиз
Моя попытка . Я не смотрел на тебя, так что подходы, надеюсь, разные
Луис Мендо
@ LuisMendo Я полностью забыл, что это Uозначает ^2, что это могло бы спасти меня довольно много байтов ...
Sanchises
6

MATL , 118 байт

KEUQtVQsQKBFZAXHKUqyyhsXJyyhdQtQQQwOJIUEyhdtKEhsHKQYqEEKQyywhdXJKEUQQHKUhstQwOytHKhsKYqyhdbJyqOHKhstQHKUqhsKUqYqqJvlec

Попробуйте онлайн!

Более читаемая версия (каждая строка соответствует одному символу, кроме операций перестановки стека).

объяснение

Программа выдает кодовые точки нужных символов в виде независимых чисел. В конце все эти числа объединяются в вектор-столбец, преобразуются в вектор-строку и преобразуются в символы. Результат неявно отображается.

Некоторые из используемых трюков:

  • Большинство кодовых точек ниже 32 отображаются в виде пробелов. Так 0используется для большинства пробелов, потому что он стоит только byte ( O).
  • Для первого пробела, однако, 15используется (генерируется как KUq), потому что он может быть использован повторно, добавив его в 100(char d), чтобы дать 115( s). В другом случае 5используется для пробела (генерируется как KQ), поэтому его можно впоследствии вычесть из 44( ,) в give 39( ').
  • Буфер обмена Jиспользуется для хранения символов, которые будут повторяться: сначала s, потом '. Точно так же Hхранит буфер обмена 100, который полезен для dи для генерации других символов.
  • Широко используются функции Q(сложение 1), q(вычитание 1), E(умножение на 2) и U(квадрат), а также предопределенные литералы в буферах обмена I( 3) и K( 4).
  • Произвольное сложение и вычитание выполняются путем объединения в вектор ( h) и вычисления его суммы ( s) или последовательных разностей ( d).
  • 100( d) генерируется как 4в двоичном, интерпретируется как десятичное число.
  • 110( n) получается из 65( A) путем преобразования в строку ( '65': кодовые точки [54 53]), добавления 1к кодовым точкам ( [55 54]), их суммирования и сложения 1.
  • Порядок, в котором генерируются числа, иногда изменяется для удобства; и затем они переупорядочиваются с помощью функций перестановки стека: swap ( w), bubble up b).
Луис Мендо
источник
1
Очень хорошо! Умное прикосновение, использующее Oвместо KWEпробелов. И вы подтвердили мое подозрение, что, вероятно, лучше пожертвовать другим буфером обмена H.
Санчиз
5

постоянный ток , 240 222 209 байт

OOOOOziOOOOOOOOOOOOOOOOOOOOOOOOOOOzddddddzkdddzasBdzasAdzscdzdasCzsdOOlAxlAxPOBlBxdIlAxoPAdlBxddsrIlAxssPPOPlsIZlCxddspPOZlCxPPOPlrdZlCxPlsPlrPlcPPKPdZlBxdZlAxPOAZlAxdPIZlCxdPrPdPlpPlrdZlCxPPKPOPPlpPlsPOPldPKP

Попробуйте онлайн!

Моя первая мысль была такой же, как у @seshoumara, просто поместил достаточно материала в стек, чтобы сгенерировать все значения ASCII символов. Тогда мне пришло в голову, что, поскольку +, -и *являются односимвольными операторами, я могу просто воссоздать их и иметь возможность использовать арифметику! Конечно, это будет меньше! И я не удивлюсь, если мне удастся отыграть больше байтов, но пока ... этот замысловатый подход сумел связать наивный.

OOOOOziOOOOOOOOOOOOOOOOOOOOOOOOOOOzddddddzkdddzasBdzasAdzscdzdasCzsdэто часть подхода, похожая на @ seshoumara's, но мы поднимаемся только до 46, то есть .. Мы делаем это, потому что нам нужно подняться до 45, -и нам также нужен период в нашей строке, поэтому просто пойти еще дальше на этот период (я думаю) дешевле. По пути мы храним некоторые значения: 5, 32, 39 - все пригодится позже. 5 для утилитарных вещей, 32 и 39 для их значений ASCII. Первоначально я делал 1-5, но это было дорого, и я мог просто избежать использования 4; используйте Z(введите значение, нажмите количество цифр, которое у него есть) на трех-, двух- или однозначное число для этих значений. На 42, 43 и 45, мы превращаем их в строки ( *, +и -соответственно) и сохранять их в виде макросов ( B, AиCсоответственно). Это означает, что без использования символов *+-теперь мы можем использовать эти операторы.

Отсюда мы в основном начинаем генерировать значения ASCII, используя математическую силу вместо простого накопления, сохраняя некоторые повторения по пути. 100, 105 и 115 достаточно, чтобы их хранение (в регистрах или иным образом) имело смысл. Первоначально я оставил стек заполненным 10 секундами и использовал их, чтобы сделать 100 секунд; в итоге мы сохранили байты, чтобы заполнить стек 32-мя и позже использовать их в качестве пробелов. Чуть более читаемая версия раздела ASCII: OOlAxlAxP OBlBxdIlAxoP AdlBxddsrIlAxssP P OP lsIZlCxddspP OZlCxP P OP lrdZlCxP lsP lrP lcP P KP dZlBxdZlAxP OAZlAxdP IZlCxdP rPdP lpP lrdZlCxP P KP OP P lpP lsP OP ldP KP.

Сбросил 18 байт путем: сохранения числа 5 в качестве входного радиуса вместо регистра; число 32 как точность вместо регистра; число 115 в качестве выходного радиуса вместо регистра; то пришлось изменить , KZчтобы IZгенерировать 1s и OZдля KZгенерировать 2s.

Сбросил еще 13 байтов, заполнив стек 32-мя; установка точности до 39; использование стековых манипуляций, чтобы избежать сохранения 116; вырезая двойную работу, которую я случайно оставил.

brhfl
источник
+1 Хорошая идея использовать aдля воссоздания этих операторов, а затем вызвать их с x. Это показывает поведение данных в коде dc. Когда у меня будет время, я применю ваш последний прием хранения данных в параметрах, а не в регистрах. Как вы думаете, мы могли бы получить еще более короткое решение по постоянному току, злоупотребив тем, как P работает для печати большего количества букв за раз, если нам повезет ввести необходимое огромное число, используя только шестнадцатеричное число?
сешумара
@seshoumara Это возможно, хотя мои попытки сделать это с другими проблемами предполагают, что это маловероятно просто потому, что эти значения быстро становятся большими. Просто чтобы получить первые две буквы «An», нам нужно P16750 или 0x416E. Если нам просто повезло, и одна из подстрок состояла исключительно из значений AF, то это могло бы дать нам ярлык. Это было бы немного удачи, хотя! В противном случае мы будем либо вводить большие числа каким-то образом, либо придумывать их, либо делать много сложений и умножать на 256. Что кажется ... короче, чем куча Ps.
brhfl
5

Japt , 87 байт

Bs g caA
HzG
Ts caV
iWisiiihiSisiUitiaihitiSitiuibu iUiSiWcaV idiiiaisiSieihisiSidiniau

Попробуй

объяснение

Первая строка генерирует 'и присваивает ее переменной U.

Bs g caA
B                            :11
 s                           :To string
   g                         :First character
     c                       :Character code
      a                      :  Absolute difference with
       A                     :  10

Вторая строка присваивает 2переменной V.

HzG
H                            :32
 z                           :Floor divided by
  G                          :16

Третья строка генерирует .и присваивает ее переменной W.

Ts caV
Ts                           :Convert 0 to a string
   caV                       :Absolute difference of its charcode with V (2)

Последняя строка затем строит строку по одному символу за раз в обратном порядке.

iW...ibu ...iWcaV ...iau
iW                           :Start by prepending W (.) to U (')
  ...                        :Each i prepends the literal character that follows it to the string, with S being space and U being "'"
     ibu                     :As B is the constant for 11 and it can't be quoted, here i prepends "b" to the string and u uppercases it
         ...                 :As above, each i is prepending the character/constant that follows it to the string
            iWcaV            :Gets the absolute difference of the charcode of W (.) and V (2) to get the "," and prepends that
                  ...        :Some more literals
                     iau     :And, finally, the same trick is used for the "A" as was for the "B", as A is the constant for 10
мохнатый
источник
Хорошее решение. Вы можете сохранить байт, заменив первую строку наQc dGaB
Embodiment of Ignorance
4

Красный , 272 байта

prin quote And prin sp prin quote she prin sp prin quote said prin comma prin sp prin subtract to sp mold quote G sp prin quote But prin sp prin quote that prin subtract to sp mold quote G sp prin quote s prin sp prin quote his prin dot prin subtract to sp mold quote G sp

Если необходимы двойные кавычки:

Красный , 344 байта

prin subtract to sp mold quote B sp prin quote And prin sp prin quote she prin sp prin quote said prin comma prin sp prin subtract to sp mold quote G sp prin quote But prin sp prin quote that prin subtract to sp mold quote G sp prin quote s prin sp prin quote his prin dot prin subtract to sp mold quote G sp prin subtract to sp mold quote B sp

Не работает в TIO, но работает в интерпретаторе Red.

Красная консоль

Объяснение:

Слова тривиальны - я печатаю их (печатать без перевода строки) как литералы quote. Красный имеет встроенное слово для пробела sp, равно как commaи dot. "и что 'еще интереснее: я печатал их, вычитая пробел из Bи, Gсоответственно, начиная с литерала Bи G, преобразовывая их сначала в строку с символом, moldа затем в символ (чтобы использовать для них вычитание) wtih to spRed есть преобразование по прототипу - преобразовать строка типа sp, который является символом).

Гален Иванов
источник
1
Вопрос был уточнен; они удалили интересную часть из этого.
Анатолий
@anatolyg Спасибо, мне все еще это нужно ', поэтому решение с 272 байтами такое же.
Гален Иванов
4

Forth (gforth), 351

CHAR A DUP EMIT
CHAR n EMIT
CHAR d EMIT
SPACE
CHAR s DUP EMIT
CHAR h EMIT
CHAR e EMIT
SPACE
EMIT
CHAR a EMIT
CHAR i EMIT
CHAR d EMIT
DUP CHAR m XOR EMIT
SPACE
CHAR f XOR DUP EMIT
CHAR B EMIT
CHAR u EMIT
CHAR t DUP EMIT
SPACE
DUP EMIT
CHAR h EMIT
CHAR a EMIT
EMIT
DUP EMIT
CHAR s EMIT
SPACE
CHAR h EMIT
CHAR i DUP EMIT
CHAR s EMIT
CHAR G XOR EMIT
EMIT

Жаль, что я не могу переопределить CHAR или EMIT для однобуквенных слов, поскольку для этого потребуется использовать либо :и ;(например : C CHAR ;), либо '(например ' CHAR ALIAS C)

На самом деле, если бы я мог определить слова, я мог бы сделать, : P CHAR EMIT ;а затем сделать, P xчтобы напечатать x. Ну что ж.

Я даже не могу создать буфер, записать эту последовательность символов туда, а затем использовать ее в качестве входных данных, поскольку запись в память требует использования !илиC!

therealfarfetchd
источник
3

Пепе , 266 байт

Я держу стек R пустым, а в стеке R

reeEeeeeeE reeEEeEEEe reeEEeeEee reEe REeEEEeeEE Reee reeEEeEeee reeEEeeEeE reEe Reee reeEEeeeeE reeEEeEeeE reeEEeeEee reeeEeEEee reEe reeeEeeeEe reeEeeeeEe reeEEEeEeE reeEEEeEee reEe reeEEEeEee reeEEeEeee reeEEeeeeE reeEEEeEee reeeEeeEEE Reee reEe reeEEeEeee reeEEeEeeE Reee reeeEeEEEe reeeEeeeEe

Это не на TIO, но вы можете попробовать это здесь

OrangeCherries
источник
3

постоянный ток , 240 байт

Основная идея состоит в том, чтобы постоянно увеличивать стек на 1 ( K), сохраняя ( sX) размер стека ( z) в пользовательских регистрах, когда он соответствует каждому уникальному ASCII-коду. Печать ( P) выполняется повсеместно.

KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKzsSKKzsQKKKKKzsqKKKKKzsCKKzsDKKKKKKKKKKKKKKKKKKKzPKzsBKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKzsaKKKzsdKzseKKKzshKzsiKKKKKzPldPlSPKKKKKzsszPlhPlePlSPlsPlaPliPldPlCPlSPlqPlBPKzdstzPdPlSPdPlhPlaPPlqPlsdPlSPlhPliPPlDPlqP

Попробуйте онлайн!

Я провел некоторую оптимизацию, например не сохранил букву, если она не используется после этого, например, продублировал ( d), например, букву t, например, t, в стеке для сохранения байта, так как функция rev ( lX) составляет 2 байта.

seshoumara
источник
Я придумал решение для постоянного тока, которое использует арифметику, создавая макросы для +, - и *. Это 262 байта. Я буду продолжать пытаться оптимизировать его, чтобы попытаться стать конкурентоспособным, но я должен сказать, что разочарован тем, что оно намного толще, чем (относительно) наивное решение.
brhfl
@brhfl Да, округ Колумбия довольно многословен. Тем не менее, я бы очень хотел увидеть ваше решение, так что опубликуйте его! В то же время, я также думаю больше о том, чтобы поиграть в гольф, использовать программу или придумать другую идею для DC.
сешумара
Мне удалось завязать 240! И я не удивлюсь, если бы смог сыграть в гольф еще один или два байта, но ... это гораздо более тупой подход к небольшому выигрышу. Во всяком случае, я разместил это где-то там ...
brhfl
Я опустился до 222, заменив некоторые из моих самых распространенных регистров с основанием и точностью ввода / вывода; сохраняет один байт в магазине и один байт при каждой загрузке ... Поскольку числа не имеют значения, это ни на что не влияет ... Возможно, вы также сможете использовать это в своих интересах!
brhfl
3

Машинный код 80186+, формат MS-DOS .COM, 822 787 байт

Только буквы и пробелы используются в дополнение к буквам. Учитывая, что большинство опкодов в разрешенном диапазоне - это определенные приращения, убывания, толчки, всплывающие окна и косвенные регистры AND и OR, в дополнение к IMUL, я использую тот факт, что регистр стека переносится, когда он достигает конца сегмента для изменения кода в обратном порядке! Сборка 80186+ требуется, потому что я выдвигаю непосредственные значения.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXjhX   GXkOXYIQSX GXjdX    GXkOXwIIIIIIIIIQhhihs kOXeQh ihutSXH    GXHHHHHH GXSX GYkOXDAAAQSX GXjGX    GXkOXtQhidhsahe hshhd hAnSX GXjTX   GXkOXdIIIQkOXgAQSX GXHHHHHHHHHHHHHHHHHHHHH  GXSX GYkOXbAAAAAAAAAAAAAAQhhlh  Xhh qM

Аннотированный источник (формат TASM):

IDEAL
P186

MODEL   TINY
CODESEG
ORG 100H

MAIN:   
REPT 582
    POP AX  ; Set up stack to end of string
ENDM

    PUSH 68H
    POP AX
    OR [BX+58H],AX
    IMUL CX,[BX+58H],59H ; 68H*59H=2428H
    DEC CX ; -1=2427H
    PUSH CX

    PUSH BX
    POP AX
    AND [BX+58H],AL
    PUSH 64H
    POP AX
    OR [BX+58H],AX
    IMUL CX,[BX+58H],77H ; 64H*77H=2E7CH
REPT 9
    DEC CX ; -9=2E73H
ENDM
    PUSH CX

    PUSH 6968H
    PUSH 2073H

    IMUL CX,[BX+58H],65H ; 64H*65H=2774H
    PUSH CX

    PUSH 6920H
    PUSH 7475H

    PUSH BX
    POP AX
    DEC AX
    OR [BX+58H],AX ; FFFFH
REPT 6
    DEC AX
ENDM
    AND [BX+58H],AL ; FFF9H
    PUSH BX
    POP AX
    AND [BX+59H],AL ; 00F9H
    IMUL CX,[BX+58H],44H ; 0F9H*44H=4224H
REPT 3
    INC CX ; +3=4227H
ENDM
    PUSH CX

    PUSH BX
    POP AX
    AND [BX+58H],AL
    PUSH 47H
    POP AX
    OR [BX+58H],AX
    IMUL CX,[BX+58H],74H ; 47H*74H=202CH
    PUSH CX

    PUSH 6469H
    PUSH 6173H
    PUSH 2065H
    PUSH 6873H
    PUSH 2064H
    PUSH 6E41H

;; CODE STARTS:
;; PUSH 0909H
;; POP AX
;; PUSH 046CH
;; POP DX
;; INT 21H
;; INT 20H

    PUSH BX
    POP AX
    AND [BX+58H],AL
    PUSH 54H
    POP AX
    OR [BX+58H],AX
    IMUL CX,[BX+58H],64H ; 54H*64H=20D0H
REPT 3
    DEC CX ; -3=20CDH
ENDM
    PUSH CX

    IMUL CX,[BX+58H],67H ; 54H*67H=21CCH
    INC CX ; 21CDH
    PUSH CX

    PUSH BX
    POP AX
    AND [BX+58H],AL
REPT 21
    DEC AX
ENDM
    OR [BX+58H],AX ; 0FFEBH
    PUSH BX
    POP AX
    AND [BX+59H],AL ; 0EBH
    IMUL CX,[BX+58H],62H ; 0EBH*62H=59F6H
REPT 14
    INC CX ; +14=5A04H
ENDM
    PUSH CX

    PUSH 6C68H
    PUSH 5809H
    PUSH 0968H

    JNO $+4FH

END MAIN
ENDS
ErikF
источник
Это не сборка, это машинный код ...
Артелиус
@ Артелиус Справедливо. Я обновил описание.
ErikF
3

Befunge-98 (FBBI) , 125 124 121 байт

wab









And she said   But that s his












wakekekaayyeapwayyaayybyapayybyapcyabcyaayycayyba
a



b
wayapapoq

Попробуйте онлайн! Вывод в файл с именем \n(одна новая строка). Спасибо Джо Кингу за его сценарий.

Вывод включает в себя 10 конечных строк.

Только для одного завершающего символа новой строки +1 байт , изменив следующую строку:

wakekekaayyeapwayydayybyapayybyapycyabcyaayycayyba

Попробуйте онлайн!


Объяснение:

Указатель инструкции перемещается следующим образом:IP-путь

Программа помещает не алфавитные символы в положение перед выводом этой строки в файл.

Befunge-98 содержит инструкции a... f, которые помещают соответствующее шестнадцатеричное значение в стек. Чтобы сгенерировать другие числа, он передает эти значения y(«Get SysInfo») в качестве аргументов для получения:

10  y-position
11  x-position
12  y-velocity (= 0)
13  x-velocity (= 1)

23* stack size

Помещая основную часть кода в y = 23, ayyможно использовать для повторного доступа к размеру стека, который затем используется для генерации кодов символов.

attinat
источник
Разве не разрешен только один завершающий символ новой строки?
Делиот
Пост гласит: «Пробелы полностью разрешены». Я думаю, что это круто - злоупотреблять этой формулировкой, чтобы оправдать отставание новой строки!
Анатолий
2

Pyth , 210 байт

pChyCdpCyhyhlGpCyytlGpdpChFhTyylGpCyylGpChyytlGpdpChFhTyylGpCtytytlGpChyylGpCyytlGpCyyhTpdpCtyyTpCyhCdpCtFyyCdhTpCyhFlGCdpdpCyhFlGCdpCyylGpCtytytlGpCyhFlGCdpCtyyTpChFhTyylGpdpCyylGpChyylGpChFhTyylGpCyhyhTpCtyyT

Попробуйте онлайн!

Я нашел несколько чисел, которые можно выразить, используя только буквы (например, T= 10, Z= 0, lG= длина (алфавит) = 26, Cd= код (пробел) = 32), и несколько функций, которые можно выполнять, используя только буквы (например, t= уменьшение, h= приращение, hF= повторное применение приращения = сложение), а затем просто запустили поиск методом грубой силы, чтобы найти кратчайшие комбинации этих функций и чисел, которые привели к каждой из нужных мне букв.

randomdude999
источник
2

16-битный код сборки x86, 665 байт

(бинарный алфавитный, а не исходный)

Я как-то забыл про правило, разрешающее пробелы. Конечно, код может быть гольф в результате.

Bytecode:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXsBFVKZPFFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPFPXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXkLAFQQZJJJRkDCGPLXDPDJRkDBEPZJJRLZDRDZAAAQPLYDQDYXXDQhishZhDRDhZsDQDhaththRDhuthZBDQDRhidhsaRDhhehZsDRDhndhZADTZPiDEFY

Источник:

    db    63 dup (58h) ;pop ax
    jnb   label1
    dw    5646h      ;magic #1
    dw    5a4bh      ;magic #2
    dw    4650h      ;magic #3
    dw    (42h-6)/2 dup ("PF")

label1:
    db    416 dup (58h) ;more pop ax
    imul  cx,[si+41h],46h ;cl=24h (string sentinel)
    push  cx         ;push string sentinel
    push  cx
    pop   dx         ;dl=24h
    dec   dx
    dec   dx
    dec   dx         ;dl=21h
    push  dx         ;save for later
    imul  ax,[si+43h],47h ;al=0CDh
    push  ax         ;push xxCDh
    dec   sp         ;insert xx
    pop   ax         ;ah=0CDh
    inc   sp         ;discard xx
    push  ax         ;push 0CDxx
    inc   sp         ;discard xx
    dec   dx         ;cl=20h (space)
    push  dx
    imul  ax,[si+42h],45h ;al=2Eh (dot)
    push  ax
    pop   dx         ;dl=2Eh
    dec   dx
    dec   dx         ;dl=2Ch (comma)
    push  dx         ;push xx2Ch
    dec   sp         ;insert xx
    pop   dx         ;dl=2Ch
    inc   sp         ;discard xx
    push  dx         ;push 2Cxxh
    inc   sp         ;discard xx
    pop   dx         ;dx=202Ch
    inc   cx
    inc   cx
    inc   cx         ;cl=27h (quote)
    push  cx         ;push xx27h
    push  ax         ;push xx2Eh
    dec   sp         ;insert xx
    pop   cx         ;ch=2Eh
    inc   sp         ;discard xx
    push  cx         ;push 2Exxh
    inc   sp         ;discard xx
    pop   cx         ;cx=272Eh
    pop   ax         ;discard xxxx
    pop   ax         ;ax=0CD21h
    inc   sp         ;discard xx
    push  cx         ;push ".'"
    push  7369h      ;push "is"
    push  685ah      ;push "h"+xx
    inc   sp         ;discard xx
    push  dx         ;" "+xx
    inc   sp         ;discard xx
    push  735ah      ;push "s"+xx
    inc   sp         ;discard xx
    push  cx         ;push "'"+xx
    inc   sp         ;discard xx
    push  7461h      ;push "at"
    push  6874h      ;push "th"
    push  dx         ;push " "+xx
    inc   sp         ;discard xx
    push  7475h      ;push "ut"
    push  425ah      ;push "B"+xx
    inc   sp         ;discard xx
    push  cx         ;push "'"+xx
    inc   sp         ;discard xx
    push  dx         ;push ", "+xx
    push  6469h      ;push "id"
    push  6173h      ;push "sa"
    push  dx         ;push " "+xx
    inc   sp         ;discard xx
    push  6568h      ;push "he"
    push  735ah      ;push "s"+xx
    inc   sp         ;discard xx
    push  dx         ;push " "+xx
    inc   sp         ;discard xx
    push  646eh      ;push "nd"
    push  415ah      ;push "A"+xx
    inc   sp         ;discard xx
    push  sp
    pop   dx         ;dx=sp
    push  ax
    imul  ax,[si+45h],5946h ;ah=09h

Это работает так:

  • перемещает указатель стека в конец кода через POP AX (не может POP SP, потому что он не алфавитный);

  • создает инструкцию для отправки вызова DOS (алгоритмически, потому что он не алфавитный);

  • конструирует неалфавитные символы;

  • помещает строку в стек;

  • помещает команду диспетчеризации в стек в точном конце кода, так что выполнение переходит непосредственно к этой инструкции;

  • создает инструкцию для печати строки;

  • отображает строку и их быстро вылетает. : - / (Изящный выход потребует больше кода)

Питер Ферри
источник
0

Машинный код 80186 + DOS, 91 байт

Текстовая версия:

hm  j   j   PPjzjzjgaAAA    JSJJ    RU  Sq  ReAA    JdJJJ   RfiJElK JEiS GtI And she said   But that s his   

Текстовая версия с заменой вкладок (код 9) 9и пробелов (код 32) *:

hm9j9j9PPjzjzjgaAAA9JSJJ9RU9Sq9ReAA9JdJJJ9RfiJElK9JEiS*GtI*And*she*said***But*that*s*his***

HexDump:

68 6D 09 6A 09 6A 09 50 50 6A 7A 6A 7A 6A 67 61
41 41 41 09 4A 53 4A 4A 09 52 55 09 53 71 09 52
65 41 41 09 4A 64 4A 4A 4A 09 52 66 69 4A 45 6C
4B 09 4A 45 69 53 20 47 74 49 20 41 6E 64 20 73
68 65 20 73 61 69 64 20 20 20 42 75 74 20 74 68
61 74 20 73 20 68 69 73 20 20 20

Машинный код появляется в файле с расширением .com. Когда я запускаю его, он печатает требуемое сообщение и затем зависает (выполнение случайных данных).

Высокоуровневое объяснение того, что он делает:

  1. Инициализирует регистры с постоянными значениями
  2. Заменяет пробелы в сообщении требуемыми специальными символами ( ,'.$)
  3. Исправляет код для генерации int 21инструкции, которая печатает сообщение
  4. Calls DOS

Код сборки (может быть скомпилирован tasm):

my_bp equ 7ah
my_si equ 7ah
my_di equ 67h
my_msg equ 13bh
    .model tiny
    .code
    .startup
    .186
    org 100h
    push 96dh   ; ax (ah = 0; al = don't care, but see below)
    push 9      ; cx
    push 9      ; dx
    push ax     ; bx = don't care
    push ax     ; don't care
    push my_bp
    push my_si
    push my_di
    popa
    inc cx
    inc cx
    inc cx
    or [bp+si+my_msg-my_bp-my_si+12], cx ; ,
    dec dx
    dec dx
    or [bp+si+my_msg-my_bp-my_si+14], dx ; '
    or [bp+di+my_msg-my_bp-my_di+23], dx ; '
    or [bp+si+my_msg-my_bp-my_si+30], dx ; '
    inc cx
    inc cx
    or [bp+si+my_msg-my_bp-my_si+29], cx ; .
    dec dx
    dec dx
    dec dx
    or [bp+si+my_msg-my_bp-my_si+31], dx ; $

    ; 0x2049 * 0x4b6c = 0x98301cc
    ; So this sets cx to 1cc (a temporary constant used to patch code)
    imul cx, [bp+si+my_msg-my_bp-my_si-2], 4b6ch
    ; 0x1cc | 0x2049 = 0x21cd (the instruction which calls DOS int 21)
    ; Here ah = 9 ("print" mode)
    or [bp+si+my_msg-my_bp-my_si-2], cx

    ; At address 101, there is the constant 96d, which was loaded into ax
    ; 0x96d * 0x7447 = 0x448013b
    ; So the following sets dx to 13b (adddress of the message)
    imul dx, [bp+di+101h-my_bp-my_di], 7447h

int21:
    dw 2049h

    db 'And she said   But that s his   '
    end

Он использует popaинструкцию для извлечения всех регистров, потому что обычный popне может заполнить все необходимые регистры (например pop di, это запрещенный код операции).

Адреса байтов для исправления находятся в диапазоне 0x100 ... 0x160. К счастью, они могут быть представлены как сумма 3 байтов с допустимыми значениями:

  • 0x7a в bp
  • 0x7a или 0x67 в siилиdi
  • Непосредственная ценность

Исправление байтов в сообщении работает путем логического OR0x20 (пробел) и небольшой константы (4, 7, 12 или 14). Маленькая константа получается путем инициализации cxи dxдо 9 (символ табуляции) и выполнения INCили по DECмере необходимости.

Исправление кода использует IMULинструкцию. Я нашел необходимые 16-битные константы для умножения с помощью перебора.

Наконец, адрес сообщения (0x13b) получается умножением. Чтобы сэкономить место, я взял одну из констант из одной инструкции, которая содержит непосредственное значение 0x96d. Здесь 9часть выбирает функцию печати DOS, а 6dчасть является свободным параметром. Оказывается, что6d единственная возможность, которая может дать 0x13b после умножения.

Разборка кодовой части:

06BA:0100 686D09            PUSH    096D
06BA:0103 6A09              PUSH    +09
06BA:0105 6A09              PUSH    +09
06BA:0107 50                PUSH    AX
06BA:0108 50                PUSH    AX
06BA:0109 6A7A              PUSH    +7A
06BA:010B 6A7A              PUSH    +7A
06BA:010D 6A67              PUSH    +67
06BA:010F 61                POPA
06BA:0110 41                INC     CX
06BA:0111 41                INC     CX
06BA:0112 41                INC     CX
06BA:0113 094A53            OR      [BP+SI+53],CX
06BA:0116 4A                DEC     DX
06BA:0117 4A                DEC     DX
06BA:0118 095255            OR      [BP+SI+55],DX
06BA:011B 095371            OR      [BP+DI+71],DX
06BA:011E 095265            OR      [BP+SI+65],DX
06BA:0121 41                INC     CX
06BA:0122 41                INC     CX
06BA:0123 094A64            OR      [BP+SI+64],CX
06BA:0126 4A                DEC     DX
06BA:0127 4A                DEC     DX
06BA:0128 4A                DEC     DX
06BA:0129 095266            OR      [BP+SI+66],DX
06BA:012C 694A456C4B        IMUL    CX,[BP+SI+45],4B6C
06BA:0131 094A45            OR      [BP+SI+45],CX
06BA:0134 6953204774        IMUL    DX,[BP+DI+20],7447
06BA:0139 CD21              INT     21 (after the code patches itself)

Интересный факт: Обычно я бы использовал offset messageвместо жестко запрограммированного 13bh, но в этом случае, поскольку во время синтаксического анализа его адрес неизвестен, tasm генерирует 16-битное немедленное смещение, тратя впустую 1 кодовый байт:

06BA:0131 098A4600          OR      [BP+SI+0046],CX
anatolyg
источник