Tips for golfing in Japt

Moving from JavaScript to Japt

As you may know, Japt is simply a shortened, extended version of JavaScript. I created Japt because I was tired of long property names, like String.fromCharCode(x) and Math.floor(x), and the tediousness of doing things such as creating a range. Here's the bare minimum you need to know when going from JavaScript to Japt:

  • Japt is a transpiled language; Japt code is transpiled to JavaScript and then run as JS. (I guess you could say compiled, but transpiled sounds more hipster. Disclaimer: I know absolutely nothing about being hipster)
  • All entries are full programs by default. The input is implicitly parsed, and the first six inputs are put into the variables U, V, W, X, Y, and Z; the full array is stored in N. The result of the last expression is automatically printed.
  • All uppercase letters are variables, and stay the same when transpiled. Most have preset values, which you can find in the "Variables" section of the Japt docs (at the interpreter).
  • All lowercase letters are prototype functions, or methods. Japt adds the methods a-z (and à-ÿ) on numbers, strings, and arrays. When you use one of these letters, Japt fills in the . and (; Uc in Japt is equivalent to U.c( in JavaScript, which could mean ceil, charCodeAt, or concat, depending on the type of U. This is where most of Japt's power comes from; you can find full lists of these methods under the "_____ functions" sections of the Japt docs (at the interpreter).
  • A space represents ), and ) represents )). This is because when I first designed Japt, I wanted to save as many bytes as possible, and that's how I first thought of doing this. (Though Us w n does look better than Us)w)n), IMHO.)
  • A function is denoted as ABC{...}, where the ABC can be any string of variables. Functions work for the most part as they do in JS, the main difference being the last expression is automatically returned (rather than having to use return or fancy ES6 parentheses).
  • ' denotes a single char string (i.e. 'a is the same as "a"), and # takes the next char-code and becomes that number (#e is the same as 101).
  • Anything between dollar signs $ stays the same during the transpilation process. You can use this to implement for loops, for example, since Japt doesn't have those, but I would suggest using other methods (such as m on strings and arrays, or o on numbers).
  • Most other chars commonly used in JS — "", 0-9, (, +, =, etc. — stay the same when transpiled (for the most part, anyway).

And that is all you need to know to write basic Japt code. Achieving maximum golf power in Japt requires more knowledge, but that can be found in other answers.


Here's a basic example. Say you have want to take a string of ASCII characters and replace each with its hexadecimal char code. Here's how you might do that in JavaScript:

U.split("").map(x=>x.charCodeAt(0).toString(16)).join("")

Now to convert to Japt. .split("") in JS is equivalent to q"" in Japt, or even shorter, just q. .join("") is also just q, the difference being that the object is an array instead of a string. .map( is m, .charCodeAt( is c, and .toString( is s. So our Japt code might look like:

Uq mX{Xc0 s16} q 

In Japt, though, m works as well on strings as it does on arrays, so we can remove both qs:

UmX{Xc0 s16}

Test it online! As you can see in the "JS code" box, this directly transpiles to:

U.m(function(X){return X.c(0).s(16)})

As you learn to work with Japt, you'll become less and less focused on converting back and forth from JavaScript and be able to code in Japt as its own language. Here's an explanation leaving out the JavaScript portion entirely:

UmX{Xc0 s16}
               // Implicit: U = input string
UmX{       }   // Take U, and replace each character X with the result of this function:
    Xc0        //   Take the char-code at index 0 in X (the first and only one).
        s16    //   Convert this to a hexadecimal string.
               // Implicit: output result of last expression

Compressing String Arrays

UPDATE: The tools featured in this tip have since be rewritten, improved and integrated into my Japt interpreter. For the best results it is recommended that you use that compressor over any of those linked below. I'll revisit this tip when I have some more time and rewrite it with the new compressor in mind.

Introduction

If you have an array of strings in your code, the most obvious way to compress it would be to run each string through Oc individually. For the purposes of this tip, we'll be working with the array ["lollipop","marshmallow","nougat","oreo"], which weighs in at 42 bytes initially. Running each string through Oc gives us:

[`lo¥ipop`,`Ú\hÚaow`,`Í`,`eo`]

That's now 33 bytes, a decent saving.


Step 1

But, we can do better. If we join the array to a newline separated string, we can get rid of the brackets, commas, and extraneous backticks and split on newline to get our array. Applying that to our example array gives us the following:

`lo¥ipop
Ú\hÚaow
Í
eo`·

Down to 26 bytes now.


Step 2

But, we can do better still! We could use a lowercase letter to delimit the strings instead of a newline, which might get included in the compression. z isn't used in any of our strings so let's drop that in, and see how we get on.

`lo¥ipopzÚ\hÚaowzÍzeo`qz

Ah, nuts - no improvement there; our byte count has gone up by one! There might be another letter you could use but, depending on your strings, there could be quite a few to try - in our example there are 11: b,c,d,f,j,k,q,v,x,y,z. Trying each would be pretty tedious, which is where this handy tool comes in; feed it your newline separated strings and it will try to delimit the strings with each letter that's not contained in any of them and output:

  • the shortest compressed string,
  • the delimiter it uses, and
  • its length.

Running our sample strings through it shows that b gives the best results:

`lo¥ipáæqrÚaowbÍÞo`qb

And there you have it, we're down to just 24 bytes.


Step 3

But, we can do even better! If the order of strings in your array doesn't matter, maybe there's a different permutation combined with a different delimiter that could work out even shorter. Trying each possibility is going to be much more tedious, though. With our 4 strings, there are 24 different permutations to try. With each of the 11 possible letters that becomes 264! That's where this tool comes into play. Again, feed it your newline separated strings and it will try every combination of every permutation and every delimiting letter, outputting:

  • the order of the strings in the shortest compressed string,
  • the compressed string,
  • the delimiter it uses, and,
  • its length.

Running our sample strings through it shows that "nougat","oreo","lollipop","marshmallow" with b as a delimiter gives the best results, with a final byte count of just 23:

`ÍÞo½o¥ipáæqrÚaow`qb


Bonus Tip: Integer Array Compression

You can apply the same principle to arrays of integers by first converting each to a higher base. Using this sample, 36 byte array:

[588181,156859,595676,475330,680474]

We can get that down to 29 bytes by first converting it to an array of base 32 strings and then running it through the first compression programme:

`huclt4p5r5ÛÊg62tkogq`qt mnH

Or as low as 27 bytes using the second programme:

`4p5Ïcl5ÛÊg62tkogq`qt mnH

You might be able to save another byte or 2 on top of that by moving the integer conversion into a method you're already running on the array.


Notes

  1. Don't forget to factor in the 1 or 2 extra bytes q<letter>(<space>) costs over ·. Although, you may be able to use one of the Unicode shortcuts to get a byte back, depending on your delimiter ( is the same as ql<space>, for example).
  2. A word of caution when using the last tool: the more strings you have, the more permutations there will be and the slower the programme will run, until it eventually craps out. As detailed above, with our 4 sample strings and 11 possible letters to try, there are 264 possible combinations, increase the number of strings by just 1 with the same 11 letters and we already have 1320 combinations to try. (You can use this tool to count the number of combinations, if you want).

Credits

  • Oliver for the inspiration to create the tools found in this tip.
  • ETHproductions for proofreading.

Shortening Numbers With Char-Codes

In Japt, you can use #, followed by a character to create a char-code. This comes in handy when shortening longer numbers.

As @ETHproductions mentioned, this only works on three-digit runs in the range 100-255, unless you are willing to switch to UTF-8.

Examples:

123 can be shortened to #{

101 can be shortened to #e

You can even chain these together:

123101 can be shortened to #{#e

You can use String.fromCharCode(123) in JavaScript, or 123d in Japt to find the appropriate character.

String.fromCharCode(123) returns {