The tricks from the JS wiki apply to Civet as well.
Special variables
#
#
by itself is an alias to this.length
. It's useful as a variable pre-initialized to undefined
, as well as a loop variable (as explained below).
#
is more generally a shortcut to .length
string#
array#
//instead of
string.length
array.length
&
and .
&
and .
can be used as argument placeholders, allowing short syntax for creating functions. They differ in that .
lifts outside a function call while &
does not.
[99..1].map console.log .,"beers on the wall"
[99..1].map &+" beers on the wall"
//instead of
[99..1].map (x)=>console.log x,"beers on the wall"
[99..1].map (x)=>x+" beers on the wall"
If you want to access a property of .
, you can't follow it with .
, as it fails to parse. Instead, ?
(which compiles to ?.
in JS) or !
(which compiles to .
in JS) can be used:
args.map console.log ..X //fails
args.map console.log .?X //okay
args.map console.log .!X //okay
@
@
is shorthand for this
and @X
is shorthand for this.X
.
Looping
The traditional for
-loop
for(i=0;i++<10;)console.log i
can be shortened in Civet to
for$=0;$++<10;console.log $
for$ of[1..10]console.log $
for[i=1..10]console.log i++
for;#^10;console.log #=-~#
[1..10].map console.log .
These are not always interchangeable, so which is shortest will depend on the rest of the code. Note that #
can also be used in place of $
.
Also try postfix loop, sometimes it could be shorter.
This is a bit cursed, but if you are using eval
, you can access the loop variable without ever assigning it directly:
for[0..9]eval "console.log(i)"
Late Assignment
a&&(b=3)
a&&b=3 //-2 bytes
i=1/(i+3)
i=1/i+=3 //-1 byte
Multiple Assignment
c=c*2+1
c++*=2 //-1 byte
Operators
Civet introduces a number of new operators that can help shorten your code.
Pipe operator
Sometimes using |>
can avoid an intermediate variable to save a byte.
s=a+b,console.log s*s
a+b|>console.log .*. //-1 byte
It can also be used to help lift the placeholder variable .
through multiple function calls.
args.map console.log f . //fails
console.log f $ for$ of args //use a for-loop
args.map console.log(.|>f) //or pipe into the inner function
Concat operator
The ++
operator is a shorter alternative to the concat
method.
[1,2,3]++[4,5,6] // [1,2,3,4,5,6]
Modulo operator
%%
always returns positive values.
-5%3 // -2 (remainder)
-5%%3 // 1 (modulo)
Other operators
"abc"<?"string" // typeof "abc" === "string"
"abc"!<?"string" // typeof "abc" !== "string"
a^^b // a xor b
a!^b // a xnor b
a^^=b // a = a xor b
a!^=b // a = a xnor b
a?=b // a??=b
a%/b // floor division: Math.floor(a/b)
a∈b // b.contains(a)
a?b //a?.b (optional chaining property access)
a?(b) //a?.(b) (optional chaining function call)
a? b //a?.(b), same as above
Chained comparisons
s<2&&console.log i
s<2<console.log i // -1 byte
Node.js features
Civet runs on Node.js, which makes additional functions available compared to pure JavaScript.
Buffer
Consider Buffer
as a way of accessing code points of an ASCII string or bytes of a Unicode string.
Buffer("Hello, World!").map console.log "Char code = ",.
It also can work in reverse, as an alternative to String.fromCharCode
.
console.log ""+Buffer [103,111,108,102]
write
If you need write
, you can still use it in Node with process.stdout.write
.
Chars golfing
Operators
There are Unicode alternatives for many operators. ∈\∉\∋\∌
could be useful even in bytes scoring.
Packing
eval
runs JavaScript code, not Civet code, so you'll need to edit your code accordingly before packing.
//To pack,
(Buffer.from "my source").toString "ucs2"
//Unpack & run
eval ""+Buffer "packed","ucs2"
If you have an odd number of characters in your source, then you can prepend ;
to it before packing, and use
eval 0+Buffer "packed","ucs2"