59
\$\begingroup\$

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.

\$\endgroup\$
7
  • \$\begingroup\$ What about whitespace in output? (leading/trailing?) \$\endgroup\$
    – att
    Jun 13, 2019 at 7:04
  • 2
    \$\begingroup\$ Darn, my esolang can't complete because there's no ability to produce output with only a-zA-Z. In theory I could use write and Eval to create the necessary instructions, but none of +-*,%'" can be constructed without using (at least) one of +-*,%'"0-9. \$\endgroup\$ Jun 13, 2019 at 16:23
  • 18
    \$\begingroup\$ (programmer-of (language 'lisp)) dislikes this. \$\endgroup\$ Jun 13, 2019 at 22:05
  • 6
    \$\begingroup\$ Have to admit, I didn't think this was particularly interesting at first, but the combination of repeated and unique characters really made it something fun to optimize (especially on a stack language!). Very nice. \$\endgroup\$
    – brhfl
    Jun 14, 2019 at 18:01
  • 1
    \$\begingroup\$ Can you clarify if extra whitespace in the output is allowed? Like extra trailing newlines? Or only whitespace in the source, plus alphabetic characters. There's a Befunge answer that prints with extra an trailing newline. \$\endgroup\$ Jun 15, 2019 at 0:24

35 Answers 35

1
2
1
\$\begingroup\$

Husk, 408 bytes

mcJLQtDDQDsisNeJDDDDDisNeJDDDDDisNeJLDQQDDsisNeLtQtDDQDsisNLDDtDtDtDDDsisNJLtQDtDDDsisNeLtDDtDtDDDDsisNLttttQDtDDDsisNJLDDtDtDtDDDsisNeJLtDtDtDtDtDDDsisNeLtDDtDtDDDDsisNLQDtDDDsisNJDDDDDisNeDDiDsisNLtDDQDDsisNJLtDDQDDsisNeJLDDtDtDDDDsisNeJLDDtDtDDDDsisNeLtttPtDQDsisNDDDDDisNJLtDtDtDtDtDDDsisNeLtQDtDDDsisNLDDtDtDDDDsisNJLQDtDDDsisNeJDDDDDisNeLtDDtDtDDDDsisNLtQDtDDDsisNJLDtPDDsisNeLtDDtDtDDDDsisNLtDDQDDsisN

Try it online!

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.

\$\endgroup\$
1
\$\begingroup\$

BRASCA, 213 bytes

DoluRlugoHoEoDuRxluxluxMgoldUxgollUxgoEoDuRxluxluxMgoholDUmxMgoHoduxduxgoEoEuxhuxgoDuxDuxgoluxluxhumxMgoluxluxDuxgoEoluxluxDuxgoldUxgoholuxluxDuxgoEuxhuxgoDuRxluxluxMgoEoldUxgolDUmxMgoDuRxluxluxMgoduxDuxgoEuxhuxgo

Try it online!

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
\$\endgroup\$
1
\$\begingroup\$

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

Try it online!

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
\$\endgroup\$
0
\$\begingroup\$

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:

  1. Initializes registers with constant values
  2. Replaces spaces in the message by the required special symbols (,'.$)
  3. Patches the code to generate the int 21 instruction, which prints the message
  4. 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 or di
  • 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
\$\endgroup\$
0
\$\begingroup\$

CJam, 162 bytes

KFmfbcACZbbcDsXbcSFseesicHsXbcEsXbcSFseesicAsXbcIsXbcDsXbcDFmfbcSHAmfbcBsXbceuHseesicGseesicSGseesicHsXbcAsXbcGseesicHAmfbcFseesicSHsXbcIsXbcFseesicSciBbIbcHAmfbc

Try it online!

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.

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.