# The Programming Language Quiz, Mark II - Cops

## Beatnik, 114 bytes, cracked by Johannes Griebler

Mit' tää kauniina kelaa?
Mil tää öisin pelaa?
Sun suu kauniina sanoo:
Kroohhpyyh-ZZZ-ZZZZ Z
Nukuttaapi kovin!


It's a poem in Finnish! And a program. It prints the numbers as bytes.

English translation:

What does that beautiful think?
What does it play at night?
(snoring) ZZZ ZZZ
I feel very sleepy!


I'm surprised it took this long to crack this, especially as the another Beatnik submission was cracked quickly.

This does not work with the Python interpreter (used in TIO) because of the way it handles special characters. It considers Kroohhpyyh-ZZZ-ZZZZ to be three different words, while it should be interpreted as one big. Use the C interpreter to run this.

Explanation:

Mit' tää                   | Push 1
kauniina kelaa?            | Duplicate and print
Mil tää                    | Push 1
öisin                      | Nop
pelaa?                     | Pop 2 and push their sum
Sun suu                    | Nop
kauniina                   | Duplicate
sanoo: Kroohhpyyh-ZZZ-ZZZZ | Push 101
Z                          | Subtract
Nukuttaapi kovin!          | Jump 12 words backwards (to the first "kauniina")


## Hexagony, 62 bytes, cracked by totallyhuman

i=100 while(i>0){p(100-i+"d")!}i=%<>--1;if(_@==0){_@=-100}end;


Prints decimals separated by a single lowercase d.

I'd be impressed if this works in any unintended language.

Since this has already been cracked, here is the actually executed code:

    i = 1 0 0      * equal to 105100, just has to be above 0 for the first number
. . . . . .
. . . . . . .
. . . . . . . .
" ) ! } i = % < >  * prints the number and stops if i % 100 == 0
. . . . . . . _
@ . . . . . .
. . . . . .
} . . d ;      * prints "d" and stores 100 in the memory edge


Everything else is a no-op, denoted by ..

## 8086 DOS COM, 58 bytes, cracked by tsh

huCX5DBP^h~0_GG1<h32X542P[18F18h42X%AAP[h!.X%OOSM a@<euws


I/O format: raw characters

### Explanation

The basic program looks like this:

    mov ax, 0x0e01 ; <b8><01><0e>
xor bx, bx     ; <31><db>
_loop:
pusha          ;
int 0x10       ; <cd><10>
popa           ; a
inc al         ; <fe><c0>
cmp al, 101    ; <e
jne _loop      ; u<f6>
ret            ; <c3>


However, this variant uses many unprintable characters, which would be a big hint. Fortunately, some printable instructions include:

and ax, imm16    %
xor [si], di     1<
xor [si+bx], di  18
xor ax, imm16    5
inc r16          @ABCDEFG
dec r16          HIJKLMNO
push r16         PQRSTUVW
pop r16          XYZ[\]^_
cmp al, imm8     <
pusha            
popa             a
push imm16       h


First, to avoid the unprintable characters caused by inc al, I used inc ax instead, since an overflow is not expected. Then I found a way to initialize AX and BX at the beginning with just printable characters.

    push 0x3234     ; h42
pop ax          ; X
and ax, 0x4141  ; %AA
push ax         ; P
pop bx          ; [

push 0x2e21     ; h!.
pop ax          ; X
and ax, 0x4F4F  ; %OO
_loop:
pusha           ;
int 0x10        ; <cd><10>
popa            ; a
inc ax          ; @
cmp al, 101     ; <e
jne _loop       ; u<f6>
ret             ; <c3>


Then, I employed self modifying code to fix the unprintables in int 0x10. That instruction in the final program resides at 0x0131, which is the value in SI these 5 instructions get me:

    push 0x4375     ; huC
pop ax          ; X
xor ax, 0x4244  ; 5DB
push ax         ; P
pop si          ; ^


Then, I found the best way to get the value of 0x10cd (x86 is little endian) is to xor 0x3080 with 0x204d:

    push 0x307e   ; h~0
pop di        ; _
inc di        ; G
inc di        ; G
xor [si], di  ; 1

; ...

pusha         ; 
dw 0x204d     ; M<space>
popa          ; a


Then, I used the same XOR value two more times, on the two final bytes in the program.

    push 0x3233     ; h32
pop ax          ; X
xor ax, 0x3234  ; 542
push ax         ; P
pop bx ; BX = 7 ; [

xor [si+bx], di ; 18
inc si          ; F
xor [si+bx], di ; 18

; ...

cmp al, 101     ; <e
db 0x75 ; jnz   ; u
dw 0x7377
`

First 0x7377 is xored with 0x3080 to get 0x43f7. Then 0x??43 (some garbage byte at 0x013a) ^ 0x3080 = 0x??c3, which sets the two final bytes to the correct values.