]> dollcode

a moderately cursed dollcode implementation

2024-10-24 23:18:14

recently, dollcode has become a thing frquently utilized by both this one's friends and other beings it observes. this is inconvenient, because many of them have written their own transcoders for the format, which can handle arbitrarily large numbers. at time of writing, the only two translators it has found (https://noe.sh/dollcode, https://999eagle.moe/dollcode) do not support nubbers larger than 64 bit integers. thusly, it can read few of its friends encoded strings.

the optimal solution to such a problem is probably either asking the sender of a given message what said message says, or asking them for their transcoder. this one being this one, it did neither: below, one may find a very good and very reasonable dollcode transcoder. one can tell it is good and reasonable because it contains the y combinator written in python lambda statements.

~/.local/bin/dollcode
#!/usr/bin/env -S bash -c 'python3 -c "__import__(\"sys\").setrecursionlimit(2**31-1); exec(open(\"$(which dollcode)\").read())" "$@"' _ 
print((lambda d,ud,args:d(int(args[-1]))if'-n'in args else d(int(''.join(map(lambda x:str(hex(ord(x))[2::]),args[-1])),16))if'-a'in args else ud(args[-1])if'-dn'in args else(lambda h:''.join(map(lambda i:chr(int(h[i:i+2],16)),range(0,len(h),2))))(hex(ud(args[-1]))[2::])if'-da'in args else"0x6e6174\'s dollcode conversion tool\n\t-n: encode decimal number as dollcode\n\t-a: encode ascii string as dollcode\n\t-dn: decode dollcode as decimal\n\t-da:decode dollcode as ascii string")(lambda n:''.join(map(lambda n:''.join(['▖','▘','▌'][int(n)]),(lambda f:(lambda x:f(lambda y:x(x)(y)))(lambda x:f(lambda y:x(x)(y))))(lambda f:lambda n:(lambda x,y:str(f(x))+str(y))(*divmod(n-1,3))if n else'')(n))),lambda d:__import__('functools').reduce(lambda a,d:a*3+d,map(lambda x:{'▖':1,'▘':2,'▌':3}[x],d),0),__import__('sys').argv))

python is a very good programming language. this is observable in that it allows integers to have up to 4300 digits[1]

one may wonder: "why is the shebang like that?" the answer to such a question is that it did not want to set the recursion limit inside the actual program (it did not realize it would hit recursion limit issues until after it was done writing the program), and it decided it would be amusing to have a really weird shebang line.

bafflingly, this program works:

~ λ dollcode -a nat
▖▖▖▖▘▖▖▖▖▘▌▖▖▖▘

it is very efficient:

~ λ dollcode -a "$(for i in {0..65536}; do echo -ne a; done)" >/dev/null & pid=$!; while kill -0 $pid 2>/dev/null; do pmap -x $pid | tail -n 1 | awk '{print ""$3/1024/1024 " GB"}'; sleep .5; done; wait $pid 
[1] 11113
0.0247803 GB
0.261642 GB
0.625462 GB
0.982468 GB
1.34475 GB
1.69653 GB
2.07035 GB
2.43603 GB
2.80609 GB
3.16292 GB
3.53598 GB
3.90202 GB
4.27491 GB
4.63856 GB
5.02195 GB
5.37629 GB
5.75089 GB
6.13502 GB
6.48058 GB
6.85527 GB
7.24199 GB
7.6222 GB
7.96089 GB
8.33753 GB
8.719 GB
9.0616 GB
9.44017 GB
9.82001 GB
10.1397 GB
10.526 GB
10.9109 GB
11.0703 GB
10.956 GB
10.8826 GB
10.8184 GB
0 GB
[1]  + done       dollcode -a "$(for i in {0..65536}; do echo -ne a; done)" > /dev/null

the reason for this is interesting: looking at the the argument passed to the encode function, d, we can see it is an integer such that if the integer were to be represented in base 16 and split in to groups of two characters, each set of two characters would represent the byte that a character to be encoded is (ex: "nat" -> 0x6e6174 -> 6e, 61, 74 -> n, a, t).

after this process of encoding the string to be encoded as a potentially very very big integer, d defines two important internal functions: we will call them a and b. a takes an argument n, and returns the result of b called on both return values of divmod(n-1, 3) (those being the quotient and modulus of n by 3). the second function, b, takes two arguments: x, and y. it then returns str(f(x)) + str(y), where f is defined by the y combinator to be the first function, a.

since, before b can return, a((n-1)//3) must first return, which in turn calls b with different arguments, we fill the stack with approximately log3(n) frames containing numbers smaller than the initial (arbitrarily large) number. not accounting for the overhead of the memory taken by each function, the number of bytes it takes to store an array of [n, n//3, n//9... 1] is approximately 2.7*n^2. if we plug 65536 in to our equation, we get 2.7*65536^2 = 11596411699.2. dividing this by 1024^3, we get 10.8, which is very nearly the amount of memory, in gigabytes, this program uses to encode 65536 chars

it is also very fast:[2]

~ λ time dollcode -a "$(for i in {0..65536}; do echo -ne a; done)" >/dev/null
dollcode -a "$(for i in {0..65536}; do echo -ne a; done)" > /dev/null  14.31s user 7.79s system 99% cpu 22.202 total
this post was rewritten on 2025-05-12, as part of the migration to the new website. the wording has been updated, however it remains similar to the original.

or, up to a value specified via sys.set_int_max_str_digits(some_int)[1] it is only like this for large inputs, it is near instant for short strings. the python interpreter really does not like this code.[2]

comments

as an anti-bot measure, in order for $VIEWER's comment to be stored on the server, $VIEWER MUST enter the commit hash of the current deployment found in the bottom right of the page footer. failure to do so will result in the comment being disregarded.