Cheating a multiple choice test, part 2

26

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
BCADBADA

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.

Stewie Griffin

Posted 2016-09-25T15:14:09.583

Reputation: 43 471

Does the output have to be the string as shown, or can the letters be on separate lines, in a list, etc? – xnor – 2016-09-25T16:47:24.430

@xnor Optional :-) – Stewie Griffin – 2016-09-25T17:10:41.437

Why not the obvious A=00,B=01,C=10,D=11? – user253751 – 2016-09-26T01:57:34.993

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 – 2016-09-26T06:35:14.943

Answers

3

Jelly, 14 bytes

d⁹+⁹BZḄḊị“BADC

Try it online! or verify all test cases.

How it works

d⁹+⁹BZḄḊị“BADC  Main link. Argument: n

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".

Dennis

Posted 2016-09-25T15:14:09.583

Reputation: 196 637

10

05AB1E, 19 18 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

Adnan

Posted 2016-09-25T15:14:09.583

Reputation: 41 965

6

JavaScript (ES6), 55 48 bytes

f=(n,i=8)=>i--?"CBAD"[n>>i&1|n>>i+7&2]+f(n,i):''

console.log(f(14234)); // BCADBADA
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:

n=>"76543210".replace(/./g,i=>"CBAD"[n>>i&1|n>>+i+7&2])

Arnauld

Posted 2016-09-25T15:14:09.583

Reputation: 111 334

How did you think of doing the bitwise operations? – ericw31415 – 2016-09-25T19:26:13.263

@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 – 2016-09-25T20:09:07.550

3...a bit of logic... – Neil – 2016-09-26T09:16:55.553

4

Python 2, 53 bytes

f=lambda n,k=8:k*'_'and f(n/2,k-1)+'CBAD'[n>>7&2|n&1]

Test it on Ideone.

Dennis

Posted 2016-09-25T15:14:09.583

Reputation: 196 637

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 – 2016-09-25T18:13:45.920

4

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

screenshot


(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.

Arnauld

Posted 2016-09-25T15:14:09.583

Reputation: 111 334

1We 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 – 2016-09-26T20:31:22.333

3

PHP, 57 Bytes

for($i=8;$i--;)echo CBAD[($n=$argv[1])>>$i+7&2|$n>>$i&1];

Version without Bitwise operators 70 Bytes

for(;$i<8;)echo CABD[($s=sprintf("%016b",$argv[1]))[$i]+$s[8+$i++]*2];

Jörg Hülsermann

Posted 2016-09-25T15:14:09.583

Reputation: 13 026

Where is variable $i defined? – ericw31415 – 2016-09-25T16:08:25.507

@ericw31415 In the first use of a variable is initialized and automatically declared PHP this variable with a null reference – Jörg Hülsermann – 2016-09-25T16:45:53.043

That's PHP (tm) – tomsmeding – 2016-09-25T21:57:45.740

3

Mathematica, 75 73 68 66 bytes

StringPart["CBAD",#+##+1]&@@IntegerDigits[#,2,16]~Partition~8<>""&

Thanks to @MartinEnder for saving 2 bytes.

JungHwan Min

Posted 2016-09-25T15:14:09.583

Reputation: 13 290

@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 – 2016-09-25T18:40:55.703

1Oh, I didn't realise that # and #2 were the entire lists. – Martin Ender – 2016-09-25T18:43:36.803

3

JavaScript, 113 93 90 88 bytes

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

n=>{r="";b=("0".repeat(15)+n.toString(2)).slice(-16);for(i=0;i<8;i++)r+="CBAD"[parseInt(b[i]+b[i+8],2)];return r}

n=>{r="";b=(65536+n).toString(2).slice(1);for(i=0;i<8;i++)r+="CBAD"[+b[i+8]+2*b[i]];return r}

n=>eval('r="";b=(65536+n).toString(2).slice(1);for(i=0;i<8;i++)r+="CBAD"[+b[i+8]+2*b[i]]')

n=>eval('r="";b=n.toString(2).padStart(16,0);for(i=0;i<8;i++)r+="CBAD"[+b[i+8]+2*b[i]]')

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

ericw31415

Posted 2016-09-25T15:14:09.583

Reputation: 2 229

1(65536+n).toString(2).slice(1) and [+b[i+8]+2*b[i]] would be shorter, for example. – Neil – 2016-09-26T09:21:19.227

padStart, should it be accepted into a future version of ECMAscript, would result in a bigger saving. – Neil – 2016-09-26T09:24:03.577

1Instead of {…;return }, use eval("…") – Cyoce – 2016-10-02T16:55:29.083

@Neil It seems that padStart now exists in ECMAScript. – ericw31415 – 2017-12-02T00:41:45.200

3

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:       [2]        [1]        [0]        [3]

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:

ri2bG0e[8/z2fb"CBAD"f=

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.

Martin Ender

Posted 2016-09-25T15:14:09.583

Reputation: 184 808

3

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

Ton Hospel

Posted 2016-09-25T15:14:09.583

Reputation: 14 114

1

MATL, 16 bytes

16&B8eXB'BADC'w)

Try it Online!

or Verify all test cases

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

Suever

Posted 2016-09-25T15:14:09.583

Reputation: 10 257

1

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

pasbi

Posted 2016-09-25T15:14:09.583

Reputation: 411

0

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="")

Billywob

Posted 2016-09-25T15:14:09.583

Reputation: 3 363