20
\$\begingroup\$

Jelly has compressed string literals, using the “...» delimiters. The way these work is by interpreting the ... as a base-250 integer, \$n\$, then repeatedly divmod-ing this integer until it reaches \$0 \newcommand{\d}[2]{ \left( \left\lfloor \frac {#1} {#2} \right\rfloor, #1 \text{ mod } #2 \right) }\$, building up the decompressed version as it goes by indexing into dictionaries and printable ASCII.

Jelly has 2 dictionaries, "short" and "long". "Short" contains \$20453\$ words of 5 letters or shorter. "Long" contains \$227845\$ words with 6 or more letters.

As the exact method is rather complicated, I'll work through how \$n\$ is decompressed:

  • First, we divmod \$n\$ by \$3\$: \$n, m = \d n 3\$. We then call \$m\$ the mode.
  • If the mode is \$0\$:
    • Divmod \$n\$ by \$96\$, yielding \$n, c = \d n {96}\$
    • Add the \$c\$th character in the printable ASCII range ( to ~) to the decompressed string. If \$c\$ is \$95\$ yield a newline instead of 0x7F
  • If the mode is \$1\$:
    • If \$n\$ is even, use the "long" dictionary and replace \$n\$ with \$\frac n 2\$
    • If \$n\$ is odd, use the "short" dictionary and replace \$n\$ with \$\frac {n-1} 2\$
    • Then, take the length \$l\$ of the dictionary (\$20453\$ for "short", \$227845\$ for "long"), calculate \$n, i = \d n l\$ and retrieve the \$i\$th element of the dictionary, the word
    • If the decompressed string is not empty, prepend a space to the word. Finally, append the word to the decompressed string
  • If the mode is \$2\$:
    • Calculate a flag \$f\$ as \$n, f = \d n 3\$ and update \$n\$
    • If \$n\$ is even, use the "long" dictionary and replace \$n\$ with \$\frac n 2\$
    • If \$n\$ is odd, use the "short" dictionary and replace \$n\$ with \$\frac {n-1} 2\$
    • Then, take the length \$l\$ of the dictionary (\$20453\$ for "short", \$227845\$ for "long"), calculate \$n, i = \d n l\$ and retrieve the \$i\$th element of the dictionary, the word
    • If the flag doesn't equal \$1\$, swap the case of the first character of the word
    • If the flag doesn't equal \$0\$ and the decompressed string is not empty or the flag equals \$0\$ and the decompressed string is empty, prepend a space to the word
    • Finally, append the word to the decompressed string
  • If \$n\$ is non-zero, go to the first step with the new value of \$n\$

We can work through an example, using \$n = 46886323035539\$:

  • First, we divmod by \$3\$: \$n = 15628774345179, m = 2\$.

    As the mode is \$2\$, we calculate \$n\$ and \$f\$ as \$n = 5209591448393, f = 0\$. \$n\$ is odd, so we're using the "short" dictionary and \$n\$ becomes \$2604795724196\$.

    Calculate the index and the updated value of \$n = \left\lfloor \frac {2604795724196} {20453} \right\rfloor = 127355191\$ and \$i = 2673\$. The \$2673\$th word in the "short" dictionary is Caird, so we call that our word.

    As \$f \ne 1\$, we swap the case of the first character of the word: caird. However, \$f = 0\$ and the decompressed string is empty, so we don't prepend a space. Finally, we append caird to the (empty) decompressed string, yielding d = 'caird'

    As \$n = 127355191\$, which is non-zero, we go to the first step again

  • Now, d = 'caird' and \$n = 127355191\$. Divmod by \$3\$ to get \$n = 42451730, m = 1\$.

    As the mode is \$1\$ and \$n\$ is even, we're going to use the "long" dictionary this time around and \$n\$ becomes \$21225865\$

    We calculate the index into the dictionary as \$n = \left\lfloor \frac {21225865} {227845} \right\rfloor = 93\$ and \$i = 36280\$. The \$36280\$th element of the "long" dictionary is coinhering, so we set that as our word.

    As d is non-empty, we prepend a space to our word, then append it to d: d = 'caird coinhering'

    As \$n = 93\$, which is non-zero, we go to the first step again

  • Now, d = 'caird coinhering' and \$n = 93\$. Divmod by \$3\$ to get \$n = 31, m = 0\$

    As the mode is \$0\$, we calculate \$n\$ and \$c\$ as \$n = 0, c = 31\$. The \$31\$st ASCII character (alternatively, the character with ordinal \$63\$) is ?

    We add ? to the end of d, resulting in d = 'caird coinhering?' and \$n = 0\$

    As \$n = 0\$, we are done, and we return caird coinhering? as our decompressed string


Alternatively, here is a version of the sss function adjusted slightly.

Task

You are to take a positive integer \$n\$ as input and output the decompressed string that \$n\$ maps to. You may also take the two dictionaries ("short" and "long") as input if you wish. The dictionaries can be found on TIO or in the Jelly repo

You will never be given an input \$n\$ outside the native bounds of integers in your language, but your program must theoretically work for arbitrarily large integers

This is , so the shortest code in bytes wins

Test cases

n			out
1			Aachen
2			aachen
3			!
47			Aah
218			aaronical
250			Abdul
745			abdominoplasties
7180			auto
8106			. aahs
364038195		Q unconfine
396478210		SoddyAberration
592528345		insulting abature
4060289999		Shool< aalborg
6079656777		CcircuityAachen
2402785962		njX abac
1192732966		flongAllel
69526673848		Kansu4Abderian
7240502929952		Eyehook% arval
7300618740196341	g noninterchangeableu mahwa
98944394632073037	/;streetwards Harz aachen
8092569718755799474	epos sporran@ Apriorism
11508828911594644653	/,e Waterbirdanelasticities
11209288138354511564	 eale Thuya&decokes		 	(note the leading space)
11683582443091721078	 Saveable! duly babbliest		(note the leading space)
13365392696538596641	tambourinists}Battu0abaca

Additionally, make sure your program works for \$n = 8609941742042387534416\$:

this
has
newlines

and also for \$n = 16505187\$:

a
b

And the outputs for \$1 \le n \le 100\$ (one per line): Try it online!

\$\endgroup\$
8
  • 1
    \$\begingroup\$ I'm assuming I can't submit "Jelly, 0 bytes" \$\endgroup\$
    – pxeger
    Mar 26, 2021 at 17:46
  • \$\begingroup\$ @pxeger That's why the input's the integer, not a compressed Jelly string ;) \$\endgroup\$ Mar 26, 2021 at 17:47
  • 2
    \$\begingroup\$ I upvoted just for the explanation of Jelly's insane compressor. \$\endgroup\$ Mar 26, 2021 at 17:47
  • 1
    \$\begingroup\$ What's the difference between mode 2, flag 1 and mode 1? \$\endgroup\$
    – Neil
    Mar 26, 2021 at 19:59
  • \$\begingroup\$ @Neil Mode 2 allows for both a case swap and a prefixed space (flag 2), whereas mode 1 doesn't \$\endgroup\$ Mar 26, 2021 at 21:50

3 Answers 3

12
\$\begingroup\$

JavaScript (Node.js),  173 170  163 bytes

Expects ([ long_dic, short_dic ])(n), where the dictionaries are arrays of words and n is a BigInt.

d=>F=(n,C)=>n?(B=Buffer,(g=k=>x=+[n%(n/=k=BigInt(k),k)])(3)?(q=x^2||g(3),b=B(d[g(2)][g(d[x].length)]),b[-q%2]^=32,q%3>0^C?' '+b:b):B([g(96)^95?x+32:10]))+F(n,1):''

Try it online!

Commented

d =>                        // outer function taking d[] = dictionaries
F = (n, C) =>               // inner function taking n and a flag C
n ?                         // if n is not equal to 0:
  ( B = Buffer,             //   B = alias for Buffer
    ( g = k =>              //   g is a helper function taking a divisor k
      x = +[                //     it computes and returns x = n modulo k
        n % (               //     and updates n to floor(n / k) afterwards
          n /=              //
            k = BigInt(k),  //     k is first converted to a BigInt
          k                 //     but x is converted back to a Number
        )                   //
      ]                     //
    )(3) ?                  //   extract the mode; if it's not 0:
      ( q =                 //     q = flag; we force q = 3 in mode 1
          x ^ 2 || g(3),    //     otherwise, it's extracted from n
        b = B(              //     b is a Buffer:
          d[g(2)]           //       select the relevant dictionary
          [g(d[x].length)]  //       and extract the relevant word from it
        ),                  //     end of Buffer
        b[-q % 2] ^= 32,    //     if q is even, toggle the case of the 1st char.
        q % 3 > 0 ^ C ?     //     if (q mod 3 != 0) XOR C is true:
          ' ' + b           //       append a space and the word
        :                   //     else:
          b                 //       just append the word
      )                     //
    :                       //   else (mode 0):
      B([                   //     use a Buffer to generate a character:
        g(96) ^ 95 ? x + 32 //       extract the character ID and add 32
                   : 10     //       or force a line-feed if it's 95
      ])                    //     end of Buffer
  )                         //
  + F(n, 1)                 //   append the result of a recursive call
:                           // else (n = 0):
  ''                        //   stop the recursion
\$\endgroup\$
5
\$\begingroup\$

Jelly, 11 bytes

Obligatory Jelly answer.

ḃØ⁵ịØJ⁾“»jV

Try it online!

How?

ḃØ⁵ịØJ⁾“»jV - Link: integer, n
ḃ           - convert (n) to bijective base:
 Ø⁵         -   250
   ị        - index into:
    ØJ      -   Jelly's code-page
      ⁾“»   - list of characters = "“»"
         j  - join -> "“...»"
          V - evaluate as Jelly code
\$\endgroup\$
1
  • 2
    \$\begingroup\$ So that's what bijective base is for! My attempts with b kept failing for ones that involved 250 in the base conversion \$\endgroup\$ Mar 28, 2021 at 0:59
3
\$\begingroup\$

Python 3, 245 bytes

def f(n,s,l,i=0):
	t=""
	while n:
		if n%3:
			if n%3>1:f=n//3%3;n//=9
			else:f=-1;n//=3
			d=[l,s][n%2];w=d[n//2%len(d)];t+=((t!="")^(f>0))*" "+[w[0].swapcase(),w[0]][f%2]+w[1:];n//=2*len(d)
		else:t+=chr((n//3%96+22)%117+10);n//=288
	return t

Try it online!

Pretty poorly optimized; working on a better approach.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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