9
\$\begingroup\$

Unlolify a lolified message!

I had to ask a coworker if they wanted to have lunch with me, but we're both hackers so it could not be in a lame way. The message asking that was roughly this:

please respond with 011110010110010101110011 if you'd like to join lunch today

The colleague being a hacker, just responded with 0x796573, to which I responded back:

0x636f6f6c2c206e696365

To save my colleague the trouble of unlolifying it, I wrote a Ruby function to unlolify and sent it along with the message. But the function itself was way more lengthier than the lolified message itself. I'd like to have a better alternative in the future and be able to send a much shorter unlolify function.

Can someone help me? :-)

The challenge

A lolified message (valid examples above) is just an integer number. Unlolify it by first getting the binary string representation of the number, then left-padding it with the character 0 (zero) as many times as necessary so that the string length is a multiple of 8. Then take each sequence of 8 digits (from left to right) and convert each one of them to its corresponding ASCII character (the digits form a binary representation of an integer). Finally, put together all the resulting characters so that they represent a text string.

The challenge is to write the code of the function unlolify, which takes a positive integer number as input and outputs the unlolified string.

For example, the lolified hexadecimal number 636f6f6c2c206e696365 will output the string cool, nice.

Rules:

  1. Output strings will always contain only ASCII characters. Thus, each character is exactly one byte long
  2. The number of bits of the input can be arbitrarily high
  3. The input must be a positive integer number (input > 0)

Standard rules apply.

\$\endgroup\$
10
  • 11
    \$\begingroup\$ Are we allowed to take a hexadecimal string instead of an integer? I feel like it would fit in the spirit of the challenge :) \$\endgroup\$
    – ovs
    Commented Sep 9, 2021 at 11:16
  • 1
    \$\begingroup\$ @Adám Taking as a base-10 string, sure. But in a different base as well? The challenge text talks about hexadecimal messages, but the rules just state the input is an integer, which I would assume usually implies base-10 \$\endgroup\$
    – ovs
    Commented Sep 9, 2021 at 11:40
  • 1
    \$\begingroup\$ @ovs Hence my upvote for your comment, and the introductory phrase "I think". \$\endgroup\$
    – Adám
    Commented Sep 9, 2021 at 11:41
  • 3
    \$\begingroup\$ Gotta be careful using "loli" these days. 💁🏻‍♀️ 😂 \$\endgroup\$
    – Taco
    Commented Sep 10, 2021 at 16:58
  • 4
    \$\begingroup\$ What does "lolifying" mean? What does "lol" have to do with base conversion? \$\endgroup\$
    – user
    Commented Sep 10, 2021 at 23:38

14 Answers 14

32
\$\begingroup\$

Vyxal, 3 bytes

₈τC

Try it Online!

 τ  # Convert to base...
₈   # 256
  C # Get charcodes
\$\endgroup\$
8
  • 13
    \$\begingroup\$ H.......... How'd you absolutely destroy me by 15 bytes?!?!? \$\endgroup\$
    – lyxal
    Commented Sep 9, 2021 at 11:04
  • 3
    \$\begingroup\$ @lyxal I don't actually know. I just saw this as a way of doing it. \$\endgroup\$
    – emanresu A
    Commented Sep 9, 2021 at 11:07
  • 21
    \$\begingroup\$ @lyxal IIRC, there is/was a "best of" category for outgolfing the creator of a language. This certainly qualifies. \$\endgroup\$
    – Adám
    Commented Sep 9, 2021 at 11:08
  • 6
    \$\begingroup\$ @AndréDiegoPiske That's because Vyxal's base conversion builtin converts to a list of numbers instead of a string of characters. \$\endgroup\$
    – emanresu A
    Commented Sep 9, 2021 at 11:13
  • 4
    \$\begingroup\$ @Joshua It's meant to take a base-10 number - prepend 0b to the number and it'll work - Try it Online! \$\endgroup\$
    – emanresu A
    Commented Sep 10, 2021 at 4:10
15
\$\begingroup\$

dc, 2 bytes

?P

Try it online!

A full program that ? reads input as an integer and P prints the string resulting from the operation specified in the challenge.

From its manual page:

   P      Pops  off  the  value  on top of the stack.  If it it a string, it is simply printed without a trailing newline.
          Otherwise it is a number, and the integer portion of its absolute value is printed out as a "base (UCHAR_MAX+1)"
          byte  stream.  Assuming that (UCHAR_MAX+1) is 256 (as it is on most machines with 8-bit bytes), the sequence KSK
          0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk could also accomplish this function,  except  for  the  side-effect  of
          clobbering the x register.

If the input can be assumed to be left on the stack, then just P would work for 1 byte.

\$\endgroup\$
9
\$\begingroup\$

Vyxal, 9 bytes

bṘ8ẇṘRvBC

Try it Online!

-6 thanks to @emanresuA

Well frick. I got played.

\$\endgroup\$
8
\$\begingroup\$

C (clang), 31 \$\cdots\$ 28 21 bytes

f(a,n){write(1,a,n);}

Try it online!

Saved 2 9 bytes with an idea from Johan du Toit!!!
Added 4 bytes to fix a bug

Inputs a pointer to the number and the number's length in bytes (since pointers in C carry no length info).
Outputs the message to stdout.

\$\endgroup\$
5
  • \$\begingroup\$ @JuhanduToit how does a simple puts work?? \$\endgroup\$
    – Wasif
    Commented Sep 9, 2021 at 15:18
  • \$\begingroup\$ @JohanduToit The challenge states: Unlolify it by first getting the binary string representation of the number, then left-padding it with the character 0. So left-padding it outside of the answer goes against that. \$\endgroup\$
    – Noodle9
    Commented Sep 9, 2021 at 15:21
  • \$\begingroup\$ @wasif puts(s) simply outputs string s to stdout follow by a carriage return. Doesn't work here because that string s needs to be null-terminated. \$\endgroup\$
    – Noodle9
    Commented Sep 9, 2021 at 15:28
  • \$\begingroup\$ @JohanduToit But if we null-terminate and then puts everything's fine - thanks! :D \$\endgroup\$
    – Noodle9
    Commented Sep 9, 2021 at 15:37
  • \$\begingroup\$ @JohanduToit that's brilliant - thanks! :D \$\endgroup\$
    – Noodle9
    Commented Sep 13, 2021 at 20:54
7
\$\begingroup\$

jq, 40 bytes

[while(.>0;./256%.)%256]|reverse|implode

Try it online!

-6 bytes from ovs.

\$\endgroup\$
1
  • \$\begingroup\$ You can do while(...)%256 for -2 and replace |floor with %., modulo floors the argument \$\endgroup\$
    – ovs
    Commented Sep 9, 2021 at 12:25
6
\$\begingroup\$

Ruby, 26 22 bytes

-4 bytes thanks to Dingus!

If we can take input as a hex string, the "%x"% can be removed.

->s{["%x"%s].pack'H*'}

Try it online!

The arbitrary base conversion builtin Integer#digits returns the digits in reverse order, which isn't helpful here:

->s{s.digits(256).reverse.pack'C*'}

Try it online!

\$\endgroup\$
0
6
\$\begingroup\$

Python 2, 31 bytes

Not very interesting, but there conveniently a direct builtin.

lambda n:('%x'%n).decode('hex')

Try it online!

Python 3, 28 bytes

str.decode('hex') no longer exists in Python 3, but is replaced with a similar b''.fromhex.

lambda n:b''.fromhex('%x'%n)

Try it online!

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Nice find, I totally forgot about the builtin. It seems you may take the input as a hexidecimal string, and skip the lambda altogether in Python 3 for a grand total of 11 bytes. \$\endgroup\$
    – Jitse
    Commented Sep 10, 2021 at 7:19
5
\$\begingroup\$

Python 3, 39 bytes

f=lambda n:n and f(n>>8)+chr(n%256)or''

Try it online!

-2 bytes thanks to ovs

\$\endgroup\$
0
5
\$\begingroup\$

JavaScript (Node.js), 37 bytes

Expects a BigInt.

f=n=>n?f(n>>8n)+Buffer([[n&255n]]):''

Try it online!

Or 33 bytes without BigInt support (i.e. limited to 32-bit integers):

f=n=>n?f(n>>8)+Buffer([n&255]):''

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ s=>Buffer(s.toString(16),'hex')+'' is 34 bytes \$\endgroup\$
    – tsh
    Commented Sep 10, 2021 at 9:35
4
\$\begingroup\$

05AB1E, 3 bytes

₁вç

Basically the same approach as @emanresuA's Vyxal answer, with integer as input.

Try it online or verify all test cases.

Explanation:

₁в   # Convert the (implicit) input-integer to base-256 as list
  ç  # Convert each integer in this list to a character with this codepoint
     # (after which the resulting list of characters is output implicitly)
\$\endgroup\$
4
\$\begingroup\$

Jelly, 3 bytes

b⁹Ọ

Try it online!

Same as @emanresu’s Vyxal answer but in Jelly, so be sure to upvote that one too!

\$\endgroup\$
3
\$\begingroup\$

Japt -P, 6 5 bytes

ìG²od

Try it

ìG²od     :Implicit input of integer
ì         :Convert to digit array in base
 G        :  16
  ²       :  Squared
   o      :  Range [0,G²)
    d     :  Characters at those codepoints
          :Implicitly join and output
\$\endgroup\$
1
\$\begingroup\$

Postscript, 23 bytes for hex input, 105 for decimal

The normal way to get a Postscript program to parse arbitrary formats is to concatenate the parser program and the input and send them to the interpreter. That's what I've done for the "no cheating" solutions.

I've set up TIO in Bash to put the program in the code section and the message in the input section. The header and footer arrange to concatenate the two and pass them to the interpreter. In the case of binary encoding, TIO's character count is wrong (it expects UTF-8 but we've got hex) so the header puts a line in the debug window with the correct count.

Hex input, no binary encoding, no cheating, 64 bytes

{currentfile 9 string readhexstring exch print not{exit} if}loop

Try it online!

There's nothing clever here. readhexstring does the heavy lifting. The 9 is arbitrary, any size will work.

TIO counts the code as 64 bytes, but it will be mandatory to have whitespace between the program and the concatenated input string. I'm not sure if that should be counted.

If we're prepared to put a limit on the maximum size of the input message then we can make this smaller:

{currentfile 999999 string readhexstring pop print}exec

As shown, the limit could be sufficiently high that it's not a problem in practice. However, the question explicitly says no limit, so I won't persue this any further.

Hex input, binary encoding, no cheating, 23 bytes

7b 92 1f 39 92 a5 92 7c 92 3e 92 76 92 70 7b 92
40 7d 92 54 7d 92 65

Try it online!

This is a straight binary encoding of the preceding solution. Unlike the non-binary-encoded version, no whitespace is needed between the program and the input.

Hex input, no binary encoding, cheating, 7 bytes

If we're prepared to allow non-standard ways of passing the input, then we can use Postscript's hex string literals to do all the work. This involves sending character "<", then the hex coding of the input, and finally ">print". This is 7 bytes more than the original message.

<the message in hex goes here>print

Try it online!

Because the message and the program are interleaved, TIO can't count the program characters.

Hex input, binary encoding, cheating, 4 bytes

And, of course there's the binary encoded version of the cheating method where we replace print with its binary encoding \x92\x76. This means adding just four bytes to the message being decoded.

<the message in hex goes here>\x92v

Try it online!

Note that TIO's bash input insists on UTF-8 encoding its input which mangles the \x92 into two characters so I've used iconv in the header to undo that.

Decimal input, no binary encoding, no cheating, 202 bytes

There's a discussion in the comments about whether hex should be allowed. For Postscript, this makes a big difference.

Postscript doesn't have any big integer handling. Integer limits are implementation dependent but you can't reliably expect anything longer than 32 bits to work. For hex, the input can be processed in arbitrary chunks. For decimal, we need to convert manually. This makes it a much more interesting problem.

The best I have so far is:

[[]{{currentfile read{48 sub exch{10 mul add
dup 256 mod exch -8 bitshift}forall
dup 0 eq {pop} if][exch}{exit}ifelse}loop
dup length 1 sub -1 0{2 copy get 1 string
dup 0 4 3 roll put print pop}for}exec

Try it online!

Note that this leaves two objects on the stack. As with the earlier non-binary-encoded answer there needs to be whitespace between the program and the input.

This requires a lot more explanation:

% Our state when we're parsing the input integer is to have two elements
% on the stack, a mark (which we'll use later) and an array containing the
% integer so far in base 256, least-significant digit first.
%
% When we read a digit, we multiply the values in the array by ten modulo
% 256 overflowing into the next digit.
%
% The code won't deal with characters that aren't decimal digits, so you
% have to be very careful setting up the input to avoid whitespace creeping
% in (including a newline at the end). Adding code to deal with this adds 38
% characters to the minimised version.
[ []             % Initialise the stack with mark and zero
{                % Start of exec (so we don't start parsing till the whole
                 % program has been loaded)
    {            % Start of the per-input-digit loop
        currentfile read    % Read one character from the input
        {                   % True path: we read a character
            48 sub          % Convert ASCII digit to decimal ('5' -> 5)
            exch            % Now have: mark new-digit array-of-current-total
            {               % Start of per-existing-digit loop
                % Stack: mark already-processed-digits adder next-digit
                10 mul      % Multiply the existing base-256 digit by ten
                add         % Add new input digit (first pass) or overflow
                dup         % Need the result twice: new digit and overflow
                256 mod exch % New digit
                -8 bitshift % Overflow
                % Stack: mark already-processed-digits adder=overflow
            } forall        % End of per-existing-digit loop
            dup 0 eq {pop} if % If the last overflow was zero, discard it
                            % We don't want lots of zeros at the top
            ]               % Use the mark on the stack to reform the array
            [ exch          % Replace the mark below the array
        }
        {exit} ifelse       % False path: end of file encountered
    } loop                  % End of input processing
    % We now have an array with the input converted to base 256
    % We can't use forall on this as that would start with the
    % least-significant digit and we need to start at the top. So, we'll
    % use a count-down for loop to access the array elements.
    dup length 1 sub -1 0
    {  % Start of per-character output loop
       % To convert to a character we put the digit into a 1 character string
        % For the next bit, "1 index exch" is neater than "2 copy ... pop"
        % but the latter is two characters shorter in non-binary encoding.
        % In binary, they're the same length.
                            % Stack: mark base-256-array index
        2 copy              % Stack: mark array index array index
        get                 % Stack: mark array index digit
        1 string dup 0      % Stack: mark array index digit string string 0
        4 3 roll            % Stack: mark array index string string 0 digit
        put                 % Stack: mark array index string
        print               % Print the converted character
        pop                 % Lose the duplicated index
    } for % End of per-character output loop
} exec

It feels like it should be possible to golf this down to something shorter.

Decimal input, binary encoding, no cheating, 105 bytes

5b 5b 5d 7b 7b 92 1f 92 7b 7b 34 38 92 a9 92 3e
7b 31 30 92 6c 92 01 92 38 32 35 36 92 6a 92 3e
2d 38 92 0f 7d 92 49 92 38 30 92 3d 7b 92 75 7d
92 54 5d 5b 92 3e 7d 7b 92 40 7d 92 55 7d 92 65
92 38 92 62 20 31 92 a9 2d 31 20 30 7b 32 92 19
92 4b 31 92 a5 92 38 30 88 04 33 92 87 92 78 92
76 92 75 7d 92 48 7d 92 3f

Try it online!

This is a straight binary encoding of the preceding solution. No whitespace is needed between the program and the input.

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

Charcoal, 8 bytes

⭆↨N²⁵⁶℅ι

Try it online! Link is to verbose version of code. Prefers to input a decimal integer, but you can make Charcoal accept hexadecimal by prefixing [0x and suffixing ] as per the linked example. Explanation:

  N         Input as an integer
 ↨ ²⁵⁶      Convert to base 256
⭆           Map over values and join
       ι    Current value
      ℅     Convert to ASCII character
            Implicitly print
\$\endgroup\$

Your Answer

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

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