Rayuela

From Esolang
Jump to navigation Jump to search
The icon for Rayuela.
Rayuela
Designed by User:Dreamvoyager
Appeared in 2021
Computational class Turing Complete
Reference implementation Python Interpreter
File extension(s) .rayu

Rayuela is an esolang created by dreamVoyager, and it is based on iterations that loop through various functions, using the previous function's output as the next function's input, until the iteration is completed; then the final result is printed and used for the next iteration.

Rayuela means “Hopscotch” in Spanish, and is also the name of a novel where the reader can “jump” between chapters. The file extension used for its files is .rayu.

Format

Rayuela code is (usually) composed of 10 functions, each defined in a line, with a number preceding it to determine which function it is. After the 10 functions, it takes an integer input.

Each iteration takes the integer (n) and runs the function associated with its first digit. Then, the function associated with the following digit is run, this time using the number that was obtained. This is continued until it reaches the last digit, and the final output is printed. Then, that final output is used in its iteration, and the cycle is repeated.

For example, say we have an input number “abc”. Then, the function fa(“abc”) is run. Its output, let’s say it’s “def”, is then used in fb(“def”). Its output, let’s say “ghi”, is used in fc(“ghi”). This set of functions is called an “iteration”, and it depends on the digits of its input. Note, if the input is negative, the - will be ignored when counting the “steps”, but will be considered when doing operations. Finally, the output of this iteration is used as an input in a similar iteration, this time with “ghi”, and this continues indefinitely, using the output of every iteration for the next one. A list of all the inputs from every iteration (including the original input) is printed in order as they are used. Note that if you aren’t careful, a program could loop infinitely.

A common Rayuela program looks like this:

0. n
1. 0
2. (n/2)+2
3. n-(n^2)
4. (n%5)
5. ((2*n)!=(5%n))+n
6. n>=6
7. ~
8. (2<(n^n))*~
9. 9-n
@314|10

The input, 314, is used in f3(314), which outputs 314 - (314^2)=-98282. This value is then used in f1(-98282)=0. Finally, 0 is used in f4(0), outputting as a result 0, which is also the result of the first iteration. Then, 0 is used in the next iteration. f0(0) outputs 0, so the program now constantly prints 0, as it can never reach the halting condition in this case.

314
0
0
0
...

What Everything Means

Rayuela uses the basic math operators, in addition to “.”, "n", “~”, "$", "#", "[]", “@”, “|”, and "&".

Operator What it does
. Used to define functions (a.). The number of functions is equal to the numerical base, which usually is 10.
0-9 or 0-J Numbers, used in mathematical operations or as function identifiers.
+, -, *, /, %, ^ Basic arithmetic operators. In the case of division, it will always round down.
=, >, <, >=, <=, != Comparison operators. They output either 0 or 1, depending on whether the equality is false or true.
() Parentheses, used to group operations to avoid ambiguity.
n Refers to the input of the current function.
~ Used to halt the program. If used in a math operation, the operation always evaluates to itself, unless it is multiplied or divided by/dividing 0.
$ Refers to the length of the function's current input.
# Refers to the current step of the current iteration. For example, for an iteration it(12321), if we're on the first step, # would be 0. On the last step, # would be 4.
[] Refers to a digit of the current iteration's input ([a]), and can also be used with operators, for example [a+b]. (If used with ~ outputs ~). This function wraps around, the first digit being 0 and the last -1. For example, for an iteration it(23745), [1] would be 3. [#] refers to the digit corresponding to the current function.
@ Used to determine the initial input (@a), which will be used for the first iteration. This is done after the functions are defined.
| Used after the input is defined, to specify its base, up to 20.
& Any character after this will be ignored, useful for commenting the code.

Note 1: If . is not preceded by a number, the function will be the same for every number below it. For example, if the first line is 0. <some function> and the second line is . <another function>, then functions 1-9 will be the same, to avoid having to type the same function every time.

Note 2: While # and [] might seem similar, they are very different. For example, for an iteration it(63526), [0] and [-1] (corresponding to the first and last digit) is the same, 6. However, # in the first step is 0, but in the last step is 4.

Note 3: If you leave the number after @ blank or no @ is entered, the program will ask for user input and use that as its input. If the number after | is blank or there is no |, it will default to base 10.

Turing Completeness

Technically it is possible to simulate brainfuck, but this proof uses the Collatz functions. Applying a generalized function to a Rayuela program, we have achieved turing completeness, with a, b, etc. being from list 1, and x, y, etc. being list 2, each of length i; for any base j.

. ((n*a)+x)*((n%i)=0)+((n*b)+y)*((n%i)=1)+...
@|j

While this program executes the functions of a Collatz function, it does not print each output of every step. However this is not necessary for the proof.

For lists [1/2, 3] and [0, 1], in base 10, the program looks like this:

. ((n*1/2)+0)*((n%2)=0)+((n*3)+1)*((n%2)=1)
@|10

A simulation of brainfuck has not been found yet, but theoretically it is possible.

Examples

Full Programs

Hello, Rayuela!

0. (n=7105544)*6384904+(n!=7105544)*n
1. (n=2190856)*~+(n!=2190856)*n
2. (n=2909704)*32+(n!=2909704)*n
3. (n=7300360)*2909704+(n=32)*5400328+(n!=7300360)*(n!=32)*n
4. (n=4743432)*6644232+(n=6646536)*7105544+(n!=4743432)*(n!=6646536)*n
5. (n=5400328)*6383624+(n!=5400328)*n
6. (n=6644232)*7103240+(n=6383624)*7956744+(n!=6644232)*(n!=6383624)*n
7. (n=7103240)*7103496+(n=7956744)*7694856+(n!=7103240)*(n!=7956744)*n
8. (n=7694856)*6646536+(n=6384904)*2190856+(n!=7694856)*(n!=6384904)*n
9. (n=7103496)*7300360+(n!=7103496)*n
@4743432|10


This one is fun. Due to how Rayuela handles input, it can't differentiate from 2 iterations with the same input. So it would seem impossible to print, for example, the "llo" part of "Hello, Rayuela!". After one "l" there is another "l", but after that "l", there is a "o". Since there's no way to know how many times an iteration has been run, we must find a way to express the same letter as two different numbers. Thankfully, there is one! ASCII has a special character, \b, also known as "backspace", is equivalent to pressing backspace on the keyboard, deleting the character behind it. This way, we can, for example, refer to "l" as either "la\b" or "lb\b", since both "a" and "b" get deleted. This allows us to convert each number in this format to a binary ASCII code. These values are then converted to base 10, and are the numbers that get outputted each iteration. Because of how each function has been designed, it is ensured each iteration changes n only once, and thus does not "skip" any numbers. However this is not a generalization for any text, and is exclusive to "Hello, Rayuela!". Running this program yields:

4743432: Ha\b
6644232: eb\b
7103240: lc\b
7103496: ld\b
7300360: oe\b
2909704: ,f\b
32: <space>
5400328: Rg\b
6383624: ah\b
7956744: yi\b
7694856: uj\b
6646536: ek\b
7105544: ll\b
6384904: am\b
2190856: !n\b

After converting these numbers to binary, and then those to ASCII text, the string "Hello, Rayuela!" is obtained. Simple, right?

Print "100" (any input)

. (n=100)*~+($=1)*100+(($>1)*(n/(10)))

The program consists of the same function for every digit, in base 10, and it takes input. If the input is 100, the (n=100) condition is met, and the program is halted because (n=100) = 1, which multiplies the ~, halting the program. Prints 100. If the input is not 100, the (n=100) becomes 0, and the ~ is cancelled. If it has 1 digit, it simply outputs 100, so the next iteration will be using 100, which halts the program. Prints the input, followed by 100. It is impossible for the input to not be printed. If the input has more than one digit, each time the function is run it divides the number by 10, ensuring that when it reaches the last step its input is a 1 digit number, making the output of the iteration 100. The next time the iteration is run, using 100, the program halts. Prints the input, followed by 100.

Cat

. ~

The program takes an input, and immediately halts, outputting only the original input.

Reverse Cat

. (#=0)*(n*(10^$)-[#]*(10^(2*$))+[#])+(#!=0)*(n+([#]*(10^#))-([#]*(10^($-1))))

This program, in the first step it multiplies the input by a power of 10 to double its digits, "leaving room" for the reversed digit sequence, and it adds to it the first digit. Then it deletes the leftmost digit. For every step after this, it does a similar thing, except it doesn't multiply by 10. Instead, it adds the corresponding digit to the step multiplied by a power of 10, and deletes its opposing digit. That way, when it reaches the end of the iteration, we have reversed the input. The program doesn't halt, so each iteration it oscillates between the reversed and unreversed number.

For example, for an input 2553, each step it does:

2553 (input)
5530002 (step 0)
530052 (step 1)
30552 (step 2)
3552 (step 3)

Each iteration:

2553
3552
2553
3552
...

Truth Machine

0. ~
1. 1
@|2

Halts if the input is 0, prints 1 infinitely if the input is 1. As other cases (if the input is bigger than 1) are not specified, its behaviour is based on these two functions, making any input that isn't 0 act as 1.

Print all even numbers up to 10^k-1.

. (($<k)*(n+2+($-1)*10^k))+(($>=k)*(n-10^k))+(n=10^k)*~
@0

The function takes two opposing conditions. When $ is smaller than k, it outputs (n+2+($-1)*10^k) each time the function is run. Otherwise, it outputs (n-10^k)+(n=10^k)*~, which, when (n=10^k) halts the program. This can be generalized, see below:

Print all multiples of j (with offset i) up to about 10^k-1.

. (($<k)*(n+j+($-1)*10^k))+(($>=k)*(n-10^k))+(n=10^k)*~
@i|10

This works very similarly to the program above, for any numbers i, j, and k.

For a number abc, output abccba.

. (#=0)*(n*(10^$)+[#])+(n+([#]*10^#))*(#!=0)

Each iteration mutiplies the number by 10^$, and then adds the each digit in order:

(it0): abc
(it1): (a) abc00a -> (b) abc0ba -> (c) abccba
(it2): (a) abccba00000a -> (b) abccba0000ba -> (c) abccba000cba -> (c) abccba00ccba -> (b) abccba0bccba -> (a) abccbaabccba
...

Quine

Sadly, a quine isn't possible in Rayuela, as it is impossible to output special characters like ".", "n", etc.

Snippets

(n=x*~)+y  

Halt if n = x, else return y.

(n=x)*a+(n=y)*b 

If n = x, return a, if n = y, return b. Otherwise, return 0.

1-n 

Flip 1 to 0 and 0 to 1. (Binary)

(n>0)*(n)+(n<0)*(-n)

An implementation of the absolute value function.

Interpreter

You can run a .rayu file using the Python interpreter, made possible with the help of Digin/Xanman12321. However, it is not finished yet, and bases other than 10 have not been implemented yet.