Cheating a multiple choice test, part 2

This is sequel to this challenge by Adnan. If you like this challenge, chances are you'll like the other one too. Check it out!

A multiple choice test with 8 questions each with 4 choices might have the answers: BCADBADA. Converted to four different arrays, with true and false if the current letter is the answer, it will look like this

Q#: 1  2  3  4  5  6  7  8
B  C  A  D  B  A  D  A
A: [0, 0, 1, 0, 0, 1, 0, 1]
B: [1, 0, 0, 0, 1, 0, 0, 0]
C: [0, 1, 0, 0, 0, 0, 0, 0]
D: [0, 0, 0, 1, 0, 0, 1, 0]

This can be compressed using a bit of logic. Each of the choices A, B, C and D can be represented by two true/false values shown below:

A: 1 0
B: 0 1
C: 0 0
D: 1 1

Using this logic, we can compress the four vectors above to just two:

1  2  3  4  5  6  7  8
B  C  A  D  B  A  D  A
[0, 0, 1, 1, 0, 1, 1, 1]
[1, 0, 0, 1, 1, 0, 1, 0]

That is, the solution to your test is simply: 00110111, 10011010. By concatenating these, we get the binary number 0011011110011010, or 14234 in decimal. Use this decimal value to cheat on your test!

Challenge

Take a number N in the (inclusive) range [0, 65535], and output a string with the answer to the multiple choice test.

Test cases:

14234

38513
ABBDCAAB

0
CCCCCCCC

120
CBBBBCCC

65535
DDDDDDDD

39253
ABCDABCD

The output may be in upper or lower case letters, but you can not use other symbols.

• Does the output have to be the string as shown, or can the letters be on separate lines, in a list, etc? – xnor Sep 25 '16 at 16:47
• @xnor Optional :-) – Stewie Griffin Sep 25 '16 at 17:10
• Why not the obvious A=00,B=01,C=10,D=11? – immibis Sep 26 '16 at 1:57
• The reason was I first made A=10, B=01, then C=nor(A,B), and D=and(A,B), inspired by Adnan's challenge. In hindsight it might have been better to do it the other way around, but well... Too late now... – Stewie Griffin Sep 26 '16 at 6:35

Jelly, 14 bytes

How it works

d⁹              Divmod 256; yield [n : 256, n % 256].
+⁹            Add 256; yield [n : 256 + 256, n % 256 + 256].
B           Binary; convert both integers to base 2.
Z          Zip; group the quotient bits with corresponding remainder bits.
Ḅ         Unbinary; convert from base 2 to integer.
Ḋ        Dequeue; discard the first integer, which corresponds to the
dummy value introduced by adding 256 to quotient and remainder.
ị“BADC  Index into that string, mapping [1, 2, 3, 0] to "BADC".

05AB1E, 1918 16 bytes

Code:

žH+b¦2äøC’c‰±’sè

Uses the CP-1252 encoding. Try it online!

Explanation:

First, we add 65536 to the number (žH is a constant defined to 65536), which is also 10000000000000000 in binary. This is to pad the number with zeroes. Let's take the number 14234 as an example. 14234 + 65536 is equal to 79770. Which in binary is:

10011011110011010

We remove the first character, resulting in:

0011011110011010

We split the string into two pieces using :

00110111, 10011010

After that, we zip the array with ø:

01, 00, 10, 11, 01, 10, 11, 10

Converting them back into decimal (using C) results in:

1, 0, 2, 3, 1, 2, 3, 2

Now, we only need to index it with the string cbad. The compressed version for this string is ’c‰±’, which can also be tested here. Finally, we get the characters at the index of the above array. For the above example, this results in:

1, 0, 2, 3, 1, 2, 3, 2
b  c  a  d  b  a  d  a

JavaScript (ES6), 55 48 bytes

console.log(f(38513)); // ABBDCAAB
console.log(f(0));     // CCCCCCCC
console.log(f(120));   // CBBBBCCC
console.log(f(65535)); // DDDDDDDD
console.log(f(39253)); // ABCDABCD

Non-recursive version (55 bytes)

Using a regular expression, we can do:

• How did you think of doing the bitwise operations? – ericw31415 Sep 25 '16 at 19:26
• @ericw31415 - Even if it's not doing so explicitly, the challenge is actually describing these bitwise operations in reverse order (starting at "This can be compressed using a bit of logic.") – Arnauld Sep 25 '16 at 20:09
• ...a bit of logic... – Neil Sep 26 '16 at 9:16

Python 2, 53 bytes

Test it on Ideone.

• I was trying to use (n&257)%127 but it's longer. Too bad 127 is prime. Maybe you can think of a way to optimize it. – xnor Sep 25 '16 at 18:13

CP-1610 assembly, 24 DECLEs (30 bytes)

This code is intended to be run on an Intellivision. (1)

A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. The actual function is 24 DECLEs long, starting at $4809 and ending at$4820.

The CPU registers are however 16-bit wide, so it will support any input value in 0x0000 .. 0xFFFF.

ROMW  10            ; use 10-bit ROM
ORG   $4800 ; start program at address$4800
4800 0002                   EIS                 ; enable interrupts (to enable display)

;; ---- usage example
4801 0001                   SDBD                ; load parameter in R0
4802 02B8 009A 0037         MVII  #14234, R0    ;
4805 0004 0148 0009         CALL  cheat         ; call function
4808 0017                   DECR  PC            ; infinite loop

;; ---- 'Cheat Your Test' function
cheat   PROC

4809 0082                   MOVR  R0,     R2    ; copy R0 to R2
480A 0040                   SWAP  R0            ; swap LSB/MSB in R0
480B 02BC 0214              MVII  #$214, R4 ; R4 = pointer to 2nd row of screen memory 480D 01DB @@loop CLRR R3 ; clear R3 480E 0052 RLC R2 ; extract highest bit of R2 to carry 480F 0053 RLC R3 ; inject carry into R3 4810 0050 RLC R0 ; extract highest bit of R0 to carry 4811 0053 RLC R3 ; inject carry into R3 4812 0001 SDBD ; add pointer to lookup table to R3 4813 02FB 001D 0048 ADDI #@@tbl, R3 ; 4816 029B MVI@ R3, R3 ; read character value 4817 0263 MVO@ R3, R4 ; write it to screen memory (also does R4++) 4818 037C 021C CMPI #$21C,  R4    ; 8 characters written? ...
481A 0225 000E              BLT   @@loop        ; ... if not, jump to @@loop

481C 00AF                   JR    R5            ; return

481D 011F 0117      @@tbl   DECLE $11F,$117    ; characters 'B', 'C', 'A' and 'D'
481F 010F 0127              DECLE $10F,$127    ; in white, using the built-in font

ENDP

Output (1) Granted that at least one compiler, several emulators and copyright-free replacement ROM files are freely available, I think that it doesn't infringe any PPCG submission rule. But please let me know if I'm wrong.

• We score in bytes, so add up the total number of bits, and your score is the decimal (float) result of dividing that value by eight. In this case, 27.5 bytes. – mbomb007 Sep 26 '16 at 20:31

CJam, 22 bytes

ri2bG0e[8/:.{1$=)^'A+} Try it online! Explanation Powered by magic... The mapping of bit pairs to letters in this challenge is a bit arbitrary. If we represent ABCD by 0, 1, 2, 3 (so we can just add them to the character A) then we want the following mapping: i1 i2 o 0 0 2 0 1 1 1 0 0 1 1 3 This mapping can be computed with a magical little formula: ((i1 == i2) + 1) ^ i1, where the equality check returns 0 or 1. Check out the following table, where each column corresponds to one input, each row corresponds to one operation, and each cell will show the stack at that point: [i1, i2]: [0, 0] [0, 1] [1, 0] [1, 1] copy i1: [0, 0, 0] [0, 1, 0] [1, 0, 1] [1, 1, 1] equals: [0, 1] [0, 0] [1, 0] [1, 1] inc: [0, 2] [0, 1] [1, 1] [1, 2] xor:     With that in mind here is the full breakdown of the source code: ri e# Read input, convert to integer. 2b e# Get binary representation. G0e[ e# Pad to 16 bits with zeros. 8/ e# Split into two halves of 8 bits each. :.{ e# For each pair of bits, i1 and i2... 1$   e#   Copy i1.
=    e#   Check equality with i2.
)    e#   Increment.
^    e#   Bitwise XOR.
'A+  e#   Add to 'A'
}

An alternative solution with the same byte count which is decidedly less magical:

And in case it's useful to anyone, if you turn the i1 and i2 bits back into a single number (i.e. when you want the mapping 0 -> 2, 1 -> 1, 2 -> 0, 3 -> 3) this can be computed even more easily as (~n - 1) & 3 or (~n - 1) % 4 if your language gets modulo on negative values right. I think this can be written concisely as 3&~-~n in many languages. In CJam this turns out to be a byte longer, because of the additional conversion back from base 2.

PHP, 57 Bytes

for($i=8;$i--;)echo CBAD[($n=$argv)>>$i+7&2|$n>>$i&1]; Version without Bitwise operators 70 Bytes for(;$i<8;)echo CABD[($s=sprintf("%016b",$argv))[$i]+$s[8+$i++]*2]; • Where is variable$i defined? – ericw31415 Sep 25 '16 at 16:08
• @ericw31415 In the first use of a variable is initialized and automatically declared PHP this variable with a null reference – Jörg Hülsermann Sep 25 '16 at 16:45
• That's PHP (tm) – tomsmeding Sep 25 '16 at 21:57

Mathematica, 757368 66 bytes

Thanks to @MartinEnder for saving 2 bytes.

• @MartinEnder #+## and Infix work, but using StringPart is inevitable because the head of "C"["B","A","D"][[#+##]] is "C", not List; StringJoin doesn't work. – JungHwan Min Sep 25 '16 at 18:40
• Oh, I didn't realise that # and #2 were the entire lists. – Martin Ender Sep 25 '16 at 18:43

Perl, 42 bytes

Includes +1 for -n

Give input on STDIN:

perl -nE 'say+(A..D)[2-($>>8-$_&257)%127]for/$/..8' <<< 39253 Just the code: say+(A..D)[2-($>>8-$_&257)%127]for/$/..8

JavaScript, 1139390 88 bytes

A big thanks to @Neil for helping me save 20 bytes!
-3 bytes thanks to @Cyoce

Sadly, JavaScript lacks functions like decbin, bindec, and str_pad that PHP has.

• (65536+n).toString(2).slice(1) and [+b[i+8]+2*b[i]] would be shorter, for example. – Neil Sep 26 '16 at 9:21
• padStart, should it be accepted into a future version of ECMAscript, would result in a bigger saving. – Neil Sep 26 '16 at 9:24
• Instead of {…;return }, use eval("…") – Cyoce Oct 2 '16 at 16:55
• @Neil It seems that padStart now exists in ECMAScript. – ericw31415 Dec 2 '17 at 0:41

MATL, 16 bytes

Try it Online!

Explanation

% Implicitly grab input
16&B    % Convert to binary string with at least 16 bits
8e      % Reshape the resulting string to have 8 rows and 2 columns
XB      % Convert each row from binary to decimal
'BADC'  % Push this string literal
w)      % Use the decimal numbers to index into this string (modular indexing)
% Implicitly display the resulting string

Julia, 73 Bytes

Gives a function f taking N as input and returning the answer as string.

f(N)=(b=bin(N,16);join(["CBAD"[parse("0b$(b[i])$(b[i+8])")+1]for i=1:8]))

Try it

Depending if a char array counts as string, one can omit the join (67 Bytes)

f(N)=(b=bin(N,16);["CBAD"[parse("0b$(b[i])$(b[i+8])")+1]for i=1:8])

Try it

R, 110 bytes

Came up with a vectorized solution in R. This should probably by golfable by coming up with a smarter conversion int to binary conversion.

x=as.integer(intToBits(scan()));cat(LETTERS[1:4][match(paste0(x[16:9],x[8:1]),c("10","01","00","11"))],sep="")