Print the phrase And she said, 'But that's his.'
using only the following characters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
No punctuation or non-alphabetic characters whatsoever. You can use whatever programming language you want. Whitespace is completely allowed. Shortest program wins.
35 Answers
Husk, 408 bytes
mcJLQtDDQDsisNeJDDDDDisNeJDDDDDisNeJLDQQDDsisNeLtQtDDQDsisNLDDtDtDtDDDsisNJLtQDtDDDsisNeLtDDtDtDDDDsisNLttttQDtDDDsisNJLDDtDtDtDDDsisNeJLtDtDtDtDtDDDsisNeLtDDtDtDDDDsisNLQDtDDDsisNJDDDDDisNeDDiDsisNLtDDQDDsisNJLtDDQDDsisNeJLDDtDtDDDDsisNeJLDDtDtDDDDsisNeLtttPtDQDsisNDDDDDisNJLtDtDtDtDtDDDsisNeLtQDtDDDsisNLDDtDtDDDDsisNJLQDtDDDsisNeJDDDDDisNeLtDDtDtDDDDsisNLtQDtDDDsisNJLDtPDDsisNeLtDDtDtDDDDsisNLtDDQDDsisN
Well, that was an adventure.
The code was generated with this Python script. Not sure it's optimal, but it's good enough for me.
Explanation
So, limiting Husk to using only letters turned out to be a real pain... My first idea was to use s
to convert a value to string, use t
(drop first element) and D
(double) to change the length of this string, then convert it to a number by computing its length with L
: I could do this to generate the ASCII code of each character in the output string, and the convert them to characters with c
.
That was complex enough for my tastes, but then I realized that all the builtins associated to letters in Husk are functions (which cannot be converted to string), except for N
... which is the infinite list of natural numbers, good luck getting the length of that. Fortunately, i
can take a string and return the first integer found in that string, which for N
would be 1, so with sisN
I can get my string of length 1 and I can manipulate that to get all other lengths.
I wrote a python script to bruteforce the shortest way to build strings of every needed length starting from sisN
and using t
, D
, P
(permutations, works like a factorial), and Q
(substrings, works like n*(n+1)/2). I also realized that some values could be built more efficiently by working directly on numbers rather than strings, so isN
is 1, DisN
is 2, iDsisN
is 11 (double the string "1" and read that as a number) and so on... those values were not too many, so I just hardcoded them as alternatives and kept for each the shortest between the hardcoded string and the bruteforced one.
Only after I did all that I realized that I didn't have a way to combine different characters into an output string. Strings are just lists of characters, and e
can build a list of two arguments, but to build longer lists I would need :
...
This time I was saved by J
, join, which (among other things) can take a value and a list and insert that value between each pair in the list. If I want to concatenate three strings a b c I can do it with Jbeac
. The script does this recursively starting from the desired output by choosing b
as a single central element and a
and c
as the two halves separated by b
. This was my first attempt an miraculously it worked (if the length of the string was different I could have to join only two strings together, but this doesn't happen here). I have tried other ways to compose the string, but this remains the shortest working result I could produce.
BRASCA, 213 bytes
DoluRlugoHoEoDuRxluxluxMgoldUxgollUxgoEoDuRxluxluxMgoholDUmxMgoHoduxduxgoEoEuxhuxgoDuxDuxgoluxluxhumxMgoluxluxDuxgoEoluxluxDuxgoldUxgoholuxluxDuxgoEuxhuxgoDuRxluxluxMgoEoldUxgolDUmxMgoDuRxluxluxMgoduxDuxgoEuxhuxgo
Explanation
At first I wanted to port the ><> answer, before realizing that stack length wont work with only alphabetical characters. That's when I remembered that BRASCA has some nifty things ><> does not have: The g
and u
operators!
Using the lLeEdDhHK
built-ins for pushing numbers, u
to seperate them into individual digits, R
, m
and M
to rotate and shift the stack, x
to discard digits, and then g
to put them back together I can create and output any string using only the alphabet.
Breakdown
DoluRlugoHoEoDuRxluxluxMgoldUxgollUxgoEoDuRxluxluxMgoholDUmxMgoHoduxduxgoEoEuxhuxgoDuxDuxgoluxluxhumxMgoluxluxDuxgoEoluxluxDuxgoldUxgoholuxluxDuxgoEuxhuxgoDuRxluxluxMgoEoldUxgolDUmxMgoDuRxluxluxMgoduxDuxgoEuxhuxgo
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
A| Do
n| luRlugo
d| Ho
| Eo
s| DuRxluxluxMgo
h| ldUxgo
e| llUxgo
| Eo
s| DuRxluxluxMgo
a| ho
i| lDUmxMgo
d| Ho
,| duxduxgo
| Eo
'| Euxhuxgo
B| DuxDuxgo
u| luxluxhumxMgo
t| luxluxDuxgo
| Eo
t| luxluxDuxgo
h| ldUxgo
a| ho
t| luxluxDuxgo
'| Euxhuxgo
s| DuRxluxluxMgo
| Eo
h| ldUxgo
i| lDUmxMgo
s| DuRxluxluxMgo
.| duxDuxgo
'| Euxhuxgo
Actually, 2679 2618 2561 bytes
PPuPuPDDc uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuc buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuck D cHj
I'll golf each character one by one. So far I've golfed up to A
.
Explanation
I'll golf pushing the numbers over time, so I'll only explain k D cHj
for now.
k # Put all the characters into the list
D cH # Push the empty string
j # Join the list using the empty string
80186 machine code + DOS, 91 bytes
Text version:
hm j j PPjzjzjgaAAA JSJJ RU Sq ReAA JdJJJ RfiJElK JEiS GtI And she said But that s his
Text version, with tabs (code 9) replaced by 9
and spaces (code 32) replaced by *
:
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
The machine code appears in a file with extension .com
. When I run it, it prints the required message and then hangs (executing random data).
High-level explanation on what it does:
- Initializes registers with constant values
- Replaces spaces in the message by the required special symbols (
,'.$
) - Patches the code to generate the
int 21
instruction, which prints the message - Calls DOS
Assembly code (can be compiled with 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
It uses the popa
instruction to pop all registers, because regular pop
cannot fill all needed registers (e.g. pop di
is a forbidden opcode).
Addresses of bytes to patch are in the range 0x100...0x160. By luck, they can be represented as a sum of 3 bytes with allowed values:
- 0x7a in
bp
- 0x7a or 0x67 in
si
ordi
- Immediate value
Patching of bytes in the message works by doing logical OR
on 0x20 (space character) and a small constant (4, 7, 12 or 14). The small constant is obtained by initializing cx
and dx
to 9 (tab character) and doing INC
or DEC
as needed.
Patching of code uses the IMUL
instruction. I found the needed 16-bit constants to multiply using brute-force search.
Finally, the address of the message (0x13b) is obtained by multiplication. To save space, I took one of the constants from one of the instructions, which contains an immediate value 0x96d
. Here the 9
part chooses a DOS print function, and the 6d
part is a free parameter. It turns out that 6d
is the only possibility which can give 0x13b after multiplication.
Disassembly of the code part:
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)
Fun fact: Normally, I would use offset message
instead of the hard-coded 13bh
, but in this case, because at the time of parsing its address is unknown, tasm generates 16-bit immediate offset, wasting 1 code byte:
06BA:0131 098A4600 OR [BP+SI+0046],CX
CJam, 162 bytes
KFmfbcACZbbcDsXbcSFseesicHsXbcEsXbcSFseesicAsXbcIsXbcDsXbcDFmfbcSHAmfbcBsXbceuHseesicGseesicSGseesicHsXbcAsXbcGseesicHAmfbcFseesicSHsXbcIsXbcFseesicSciBbIbcHAmfbc
Each letter is outputted individually and all the source codes are concatenated. The individual codes are:
(1 byte)
S e# Space
'
(6 bytes)
HAmfbc
HA e# Push 17 and 10 17 10
mf e# Factorization 17 [2 5]
b e# Base conversion 39
c e# Convert to char ''
,
(6 bytes)
DFmfbc
DF e# Push 13 and 15 13 15
mf e# Factorization 13 [3 5]
b e# Base conversion 44
c e# Convert to char ',
.
(8 bytes)
SciBbIbc
Sci e# Push space as an integer 32
Bb e# Convert to base 11 [2 10]
Ib e# Convert from base 18 44
c e# Convert to char '.
A
(6 bytes)
KFmfbc
KF e# Push 20 and 15 20 15
mf e# Factorization 20 [3 5]
b e# Base conversion 65
c e# Convert to char 'A
B
(7 bytes)
BsXbceu
Bs e# Push 11 as a string "11" (i.e. [49 49])
Xb e# Convert from base 1 98
c e# Convert to char 'b
eu e# Uppercase 'B
a
(5 bytes)
AsXbc
As e# Push 10 as a string "10" (i.e. [49 48])
Xb e# Convert from base 1 97
c e# Convert to char 'a
The codes for d
, e
, h
and i
work exactly the same way as for a
. The codes are:
DsXbc -> 'd
EsXbc -> 'e
HsXbc -> 'h
IsXbc -> 'i
n
(6 bytes)
ACZbbc
ACZ e# Push 10, 12 and 3 10 12 3
b e# Base conversion 10 [1 1 0]
b e# Base conversion 110
c e# Convert to char 'n
s
(7 bytes)
Fseesic
Fs e# Push 15 as a string "15"
ee e# Enumerate [[0 '1] [1 '5]]
s e# Convert to string "0115"
ic e# Convert to char 's
The codes for t
and u
do the same thing but staring with G
(16) and H
(17):
Gseesic -> 't
Hseesic -> 'u
Most of these codes were found using another Cjam program to brute force all possible outputs for a given formula. If you want to use it, type some formula such as RTsbc
, and it will show you how to get to each possible output by replacing R
, T
and U
in the input by some 1 byte constant.
a-zA-Z
. In theory I could usew
rite andE
val to create the necessary instructions, but none of+-*,%'"
can be constructed without using (at least) one of+-*,%'"0-9
. \$\endgroup\$(programmer-of (language 'lisp))
dislikes this. \$\endgroup\$