We write algorithms in the most unnecessary language in the world and suffer

Yes, dear readers, I strongly recommend that you read the previous article, in which I talked about the main “skeleton” of the language. If you are familiar with this information, it will be easier for you to perceive what is happening here. Here is the link https://habr.com/ru/articles/844450/

For the laziest and most desperate, here is a short summary:

  • The language uses 3 characters – space, tab and line break.

  • At the beginning of each command, a special prefix is ​​used – IMP, which characterizes the vector of the further command (for example – IMP interaction with the stack, with I/O, etc.)

  • The language manipulates numbers that are stored in binary representation: tabs are ones, spaces are zeros

  • Characters are produced by the language by matching a number from the stack to its ACSII code

  • Whitespace is a stack-based language, but it also has heap, which stores data “long-term”

So, let's write! Let's write a program that will determine whether the sum of numbers is divisible by a given divisor without a remainder.

It will work like this: the first input parameter is a list of numbers.

The second parameter is the number N, by which we will divide the sum of the entered array elements

If the sum of the numbers in the array is divisible by N, the program will output: The sum is divisible

Otherwise: The amount is not divided

Sounds easy, right?

Heeeey! Who do we have here?

I am you, the author of this article, only from the future. I thought this article would be short and concise. After 3 weeks I am with you again. This article is not laconic at all. This is 40 thousand characters of my immersion in an unnecessary stack programming language. So sit down comfortably, pour some coffee and enjoy.

In fact, I have absolutely no idea how to pull off such a trick. The only useful thing I found in the language source was the file calc.ws, and in it there was a wonderful program that reads numbers from the console ad infinitum until it comes to -1, and then prints their sum to the console. A similar structure would work for me: first I would enter the numbers of the array, then the desired divisor, and end with the number -1.

So, we have decided on the input structure.

In search of ideas for implementation, I continued to surf the web until I found another program that takes the first argument of an arithmetic operation – plus or minus, and then two operands, with which it performs the operation and displays the result on the console.

Example input:

+

7

13

Example output:

20

Let's look at its code (let's agree on the following conventions: S – space, T – tab, L – line break):

SSSTLTLTSSSSTSTTSTLSSSTLTTTTSSTLTSTLSSSTTLSSSTSLSSSTLTLTTTLTTTLTTSSSTSLSSSTTLTTTSLTTTTTSSSTLSTLLLLLLLSSTLSSSTTLSSSTSLSSSTLTLTTTLTTTLTTSSSTTLSSSTSLTTTSLTTTTTSSTTLSTLLL

By language standards, this program is very small. Let's take it apart brick by brick:

  1. SS STL – push the number 1 onto the stack

  2. TL TS – read the symbol from the console

  3. SS STSTTSTL – push the number 45 onto the stack

  4. SS STL – push the number 1 onto the stack

  5. TTT – Heap retrieve

  6. TS ST – arithmetic subtraction

  7. L TS TL – go to the TL label if there is 0 on top of the stack

  8. SS STTL – push the number 3 onto the stack

  9. SS STSL – push the number 2 onto the stack

  10. SS STL – push the number 1 onto the stack

  11. TL TT – read the number from the console

  12. TL TT – read the number from the console

  13. TL TT – read the number from the console

  14. SS STSL – push the number 2 onto the stack

  15. SS STTL – push the number 3 onto the stack

  16. TTT – Heap retrieve

  17. SLT – Swap 2 top elements

  18. TTT – Heap retrieve

  19. TSSS – addition

  20. TLST – print the top number of the stack

  21. LLL – end program

LSSTL – TL label

  1. SS STTL – push the number 3 onto the stack

  2. SSSTSL – push the number 2 onto the stack

  3. SSSTL – push the number 1 onto the stack

  4. TL TT – read the number from the console and put it on the stack

  5. TL TT – read the number from the console and put it on the stack

  6. TL TT – read the number from the console and put it on the stack

  7. SS STTL – push the number 3 onto the stack

  8. SS STSL – push the number 2 onto the stack

  9. TTT – Heap retrieve

  10. SLT – Swap 2 top elements

  11. TTT – Heap retrieve

  12. TSST – subtraction

  13. TLST – print the top number of the stack

  14. LLL – end of program

Honestly, it took me a long time to read this code. It worked, time after time, but I didn’t understand how. If you re-read the commands above, you won't find any commands store(). A teams retrieve() there are as many as 5. Why the hell are we accessing variables that we didn’t create?

At this point I only had a sketchy idea of ​​these functions – store saves something, but retrieve – on the contrary, it pulls out what was saved.

I started trying to experiment with the retrieve function, creating code samples from real spaces, but when the compiler gave me this:

The beater started hitting me, and I gave up. I couldn't read the spaces anymore, it was just terrible. After two hours of reading a mess of symbols, I felt like I had aged 10 years.

Yes, sorry, but there will be no pure whitespace. Actually, S, T and L are also half measures.

I believe that if we undertake to improve the readability of a language, we must do it thoroughly. So I wrote wrappers for whitespace functions in Kotlin. (posted on github – if you are crazy, then use it for your health)

Improving readability. A very simple wrapper in kotlin

Some code:

I made a class for IMP:

enum class IMP(val lexicalToken: String) {
    STACK_MANIPULATION(" "),
    ARITHMETIC("\t "),
    HEAP_ACCESS("\t\t"),
    FLOW_CONTROL("\n"),
    IO("\t\n");

    override fun toString(): String {
        return lexicalToken
    }
}

Abstract command class in whitespace:

abstract class Command(val imp: IMP, val commandValue: String) {
    override fun toString() = imp.lexicalToken+commandValue
}

After that, all that remains is to implement the commands themselves:

class PrintChar: Command(IMP.IO, "  ")
class PrintNumber: Command(IMP.IO," \t")
class ReadChar: Command(IMP.IO, "\t ")
class ReadNumber: Command(IMP.IO,"\t\t")

I/O commands

Fortunately, 16 of the 22 commands in whitespace do not accept any arguments, but the rest had to be a little confusing. For example, the stack push command looks like this:

class PushNumber(val number: Int): Command(IMP.STACK_MANIPULATION, " "){
    override fun toString() = super.toString() + decimalToWhitespaceBinary(number)
}

Implementation of the method decimalToWhitespaceBinary you can look at github

Commands manipulating labels (the standard goto concept) were implemented through another abstraction, which, in fact, simply overrides the toString method:

abstract class CommandWithLabel( command: String, val label: String): Command(IMP.FLOW_CONTROL, command){
    override fun toString() = super.toString()+label
}

What do the commands that work with tags look like (I’ll give an example of only 2 of the 7 methods, you know where to find the full code)

class Label(labelValue:String) : CommandWithLabel("  ", labelValue)

class JumpToLabel(labelValue:String) : CommandWithLabel(" \n", labelValue)

I did all this just to write beautifully in the main method:

fun main() {
    val whitespaceProgram = listOf(
        
        PushNumber(1),
        PrintNumber(),
        End()

    )
    
    whitespaceProgram.forEach {print(it.toString())}
}

Well, what a beauty, isn't it? After launch, the source code of these commands in whitespace will be displayed in the console, which we can put into the compiler. I used an online compiler from here.

Trying to write simple constructions

Now, in order not to litter the airwaves, we will consider only that part of the method mainwhich is inside listOf

So, a small demonstration of how the wrapper works:

PushNumber(65),
PrintNumber(),
End()

It is clear that this code will display the number 65

PushNumber(65),
PrintChar(),
End()

And this one is already the letter “A”

Let's write “hello, world!” for the sake of decency.

To do this, we will find the ASCII code of each character and push it onto the stack (remember, the stack is not a queue, it works on the FILO principle – First-in-last-out, so we will push the character codes in reverse order)

h – 104 e – 101 l – 108 l – 108 o – 111, – 44 – 32 w – 119 o – 111 r – 114 l – 108 d – 100! – 33

PushNumber(33),
PushNumber(100),
PushNumber(108),
PushNumber(114),
PushNumber(111),
PushNumber(119),
PushNumber(32),
PushNumber(44),
PushNumber(111),
PushNumber(108),
PushNumber(108),
PushNumber(101),
PushNumber(104),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
PrintChar(),
End()

This program, when compiled twice, first of our kotlin, and then of whitespace, will indeed produce “hello, world!”

The only thing I don't like here is the 13-fold repetition of the command PrintChar(). Give me an endless loop!

Label(label),
PrintChar(),
JumpToLabel(label),

Label, or mark, is any unique string. While we only have one label, we can give it the shortest possible name – 0. Zero in whitespace is a space. Any label ends with a line break character ‘\n’ (and the label consists of an arbitrary combination of spaces and tabs).

The online compiler, the link to which I gave above, refused to eat an infinite loop, so I found another.Everything works great here!

However, somehow this is not terrible. We can’t leave an infinite loop at the end of the program and leave.

We need a cycle for. And for this we need to store a counter variable. And for this we need to know how it works store And retrieve.

How do store and retrieve work?

Here is the simplest code for storing a number in a variable, getting that number and displaying it on the screen:

PushNumber(33),
PushNumber(100),
Store(),
PushNumber(33),
Retrieve(),
PrintNumber(),
End()

What???

Let's look at the initialization of our variable from the moment the function is called Store() – this function takes the top element of the stack and takes it by MEANING variable. Then it takes the next element from the stack, and that element counts ADDRESS according to which we will store MEANING.

As you understand, after storing the variable in heap, both elements are removed from our stack.

To get the value of our variable we use the function Retrieve()which in turn takes the top element of the stack and evaluates it as ADDRESS variable. At this address it is retrieved MEANING and is placed on top of the stack (if there is no value at the address, 0 will come to the top of the stack).

That is, we remove the address from the stack and put a value in its place.

Now let's understand the code above. It turns out that we store the value 100 at address 33 (we can speak in terms of a variable named 33), and then we put the number 33 on the stack, and call Retrieve()thereby saying: put on my stack instead of the number 33 the value that lies at address 33.

The number 100 will be placed on top of the stack, which we will display on the console. Class, we've sorted it out, let's return to the For loop.

I implemented it this way:

PushNumber(33),//кладем буквы фразы "hello, world!"
PushNumber(100),
PushNumber(108),
PushNumber(114),
PushNumber(111),
PushNumber(119),
PushNumber(32),
PushNumber(44),
PushNumber(111),
PushNumber(108),
PushNumber(108),
PushNumber(101),
PushNumber(104),

PushNumber(666),
PushNumber(-13),
Store(),//Инит переменной 666 со значением -13

Label(startOfCycle),

PushNumber(666),
Retrieve(),//Кладем значение переменной-счетчика 666 наверх стека

PushNumber(1),
Addition(), //Прибавляем к счетчику 1 (Поскольку он отрицателен, мы стремимся к нулю. То же самое, что и отсчет от +13 до 0)

Swap(),
PrintChar(),//Выводим нашу букву, но поскольку наверху стека лежит счетчик, делаем сначала swap

PushNumber(666),//Эти 3 команды сохраняют текущее значение переменной 666 в heap
Swap(),
Store(),

PushNumber(666),//некрасиво, но опять кладем на верх стека значение только что сохраненной переменной,
// потому что оператор if 2мя строчками ниже снимет это значение с верхушки стека
Retrieve(),

JumpToLabelIfTopOfStackIsNegative(startOfCycle),//повторять до тех пор, пока счетчик в 0 не уткнется
End()

Debugging while writing this code looked something like this (I managed to write a space instead of a tab in one of the IMPs):

Procedures like these brought tears to my eyes.

Procedures like these brought tears to my eyes.

A little more about Heap: how numbers get into it

So, after all: how can a number get into the heap if we do not call the store command?

I managed to find this on the Internet question on StackOverflow: It asked how you can print a character to the console (in whitespace, of course) – a trivial question, but in the answer I saw the following:

A kind person provided a trace of not only the stack, but also the heap – it became a lifeline. I went to re-read the doc – and damn it, the language puts any input from the console into hip at the address that lies at the top of the stack:

Read a character and place it in the location given by the top of the stack

For some reason it seemed obvious to me that a stack-based language would push input onto the stack, but I was wrong. He puts it in hip at the address he takes from the stack.

I've been going around for a long time, but now we're ready to:

  1. Understand how the program works from the beginning of the article

  2. Write your own program

The code from the beginning of the article in the format of my Kotlin wrapper under the spoiler:

Code
PushNumber(1),
ReadChar(),
PushNumber(45),
PushNumber(1),
Retrieve(),
Subtraction(),
JumpToLabelIfTopOfStackIsZero(label),

PushNumber(3),
PushNumber(2),
PushNumber(1),
ReadChar(),
ReadNumber(),
ReadNumber(),

PushNumber(2),
PushNumber(3),
Retrieve(),
Swap(),
Retrieve(),
Addition(),
PrintNumber(),
End(),

Label(label),
PushNumber(3),
PushNumber(2),
PushNumber(1),
ReadNumber(),
ReadNumber(),
ReadNumber(),

PushNumber(3),
PushNumber(2),
Retrieve(),
Swap(),
Retrieve(),
Subtraction(),
PrintNumber(),
End()

Let's, for analysis, divide the program into 3 parts:

  1. initial reading of the sign

  2. branching for the case when we entered “-“

  3. branching for the case when we entered “+”. (in fact, within the framework of this program, any sign other than a minus is considered a plus)

First part. Reading the sign:

PushNumber(1),
ReadChar(),
PushNumber(45),
PushNumber(1),
Retrieve(),
Subtraction(),
JumpToLabelIfTopOfStackIsZero(label),

The next two parts have a similar structure; in both, the stack is filled with numbers from 1 to 3x:

PushNumber(3),
PushNumber(2),
PushNumber(1),

Then there are three reads from the console…

ReadChar(),
ReadNumber(),
ReadNumber(),

So, wait a minute. We have already considered the sign of the operation. Then we must count two numbers on which this operation will be performed. But we see three read operations!

Lyrical digression: reading from the console

Why are there three reads from the console instead of two?

I restarted the program and ran it again. The input window opens three times. But in total there are four read operations in the program! I haven’t found the answer to this question anywhere on the Internet, so catch the exclusive.

This code counts 2 numbers one by one from the console and displays their sum:

PushNumber(1),
PushNumber(2),
ReadNumber(),
ReadNumber(),

PushNumber(1),
PushNumber(2),
Retrieve(),
Swap(),
Retrieve(),
Addition(),
PrintNumber(),
End(),

If you have made it this far, then I believe that reading this will not be difficult for you.

Now let’s change two lines in the program: instead of the initial ReadNumberlet's put ReadChar. Let's leave the rest of the code the same:

PushNumber(1),
PushNumber(2),
ReadChar(),
ReadChar(),

PushNumber(1),
PushNumber(2),
Retrieve(),
Swap(),
Retrieve(),
Addition(),
PrintNumber(),
End(),

What do you think will happen after the launch?

We remember that characters in whitespace are stored as their ascii codes, that is, this program, logically, should allow me to enter two characters and display the sum of their ascii codes on the console – didn't guess.

After launch, this program expects you to exactly one input. If you enter one character and press enter (this works great with numbers), then the language thinks that enter – that is, \n – a new line character, this is quite a user input, so our enter is matched with its ascii code – 10, and added to the code of the first entered character. The whole ridiculous thing is that you simply cannot not press enter when typing during runtime – the language will not count your input.

Let me give you an example: when the user enters the letter A during runtime, the number 75 will be displayed in the console. (The code for the letter A is 65)

Here in this online interpreter you can specify the arguments with which the program will be launched. Useful thing. She helped me understand the difference between character input and integer input.

Now we can answer the question – why was the extra reading from the console needed: in order to eat the newline character, which is automatically hung as a dead weight on any character input (No further manipulations are carried out with this character, it’s just a crutch to It is normal to count the following numbers).

***Complete lyrical digression***

Part 2: branch for +

Thus, if the user did not enter the “-” sign (and we assume that the user is conscientious and enters only valid characters, that is, + or -), then we read two numbers from the console, pull them out of the heap, add them, display the result on the screen and terminate the program.

Part 3: branch for –

If the user entered the “-” sign, then we jump to the label \tafter which a similar code occurs: we read two numbers from the console, pull them out of the heap, subtract the second from the first, display the result on the screen and terminate the program.

Final listing with comments:
PushNumber(1),
ReadChar(),//Считываем символ и кладем его ASCII-код по адресу 1
PushNumber(45), //Кладем в стек число 45: это число - код символа "-"
PushNumber(1),
Retrieve(),//Кладем число по адресу 1 наверх стека
Subtraction(),//Вычитаем из 45 код считанного символа.
JumpToLabelIfTopOfStackIsZero(label),//Если в остатке 0 (пользователь ввел "-"), то перемещаемся к метке label

PushNumber(3),
PushNumber(2),
PushNumber(1),
ReadNumber(),//Считываем с консоли символ переноса строки, оставшийся там с предыдущего ввода
ReadNumber(),
ReadNumber(),//И считываем 2 операнда в heap

PushNumber(2),
PushNumber(3),
Retrieve(),
Swap(),
Retrieve(),//Извлекаем значения операндов в стек

Addition(), //Суммируем и выводим на экран
PrintNumber(),
End(),

Label(label),//Оказываемся здесь, если ввели "-"
PushNumber(3),
PushNumber(2),
PushNumber(1),
ReadNumber(),//Считываем с консоли символ переноса строки, оставшийся там с предыдущего ввода
ReadNumber(),
ReadNumber(),//И считываем 2 операнда в heap

PushNumber(3),
PushNumber(2),
Retrieve(),
Swap(),
Retrieve(),//Извлекаем значения операндов в стек
Subtraction(),//Вычитаем из первого второй и выводим на экран
PrintNumber(),
End()

We carry out our plans

Now that we have all the trump cards, let's write the algorithm that we came up with at the beginning of the article:

The first N parameters are an array of numbers as input.

The second parameter is the number M, by which we will divide the sum of the entered array elements

If the sum of the numbers in the array is divisible by M, the program will output: The sum is divisible

Otherwise: The amount is not divided

I sketched out a plan for how the algorithm would work, taking into account the specifics of whitespace:

  1. We initialize the counter for the number of entered numbers.

  1. We initialize the counter for the sum of the entered numbers.

  2. Initialize the variable containing the last entered number (not counting -1)

Label the beginning of the cycle

  1. We read the number from the console. We increase the counter of entered numbers.

  2. If the entered number = -1, then run input validation routine:

  3. Otherwise, we put the entered number into the last number variable, add the entered number to the sum of the entered numbers and go to the label the beginning of the cycle

Subroutine input validity checks:

Here we remember that we also count the divisor (the last entered number) into the sum of all entered numbers. In the future, for correct calculation, we need to have a separate sum of all entered numbers, except for the divisor, and the divisor itself. Therefore, we need to subtract the divisor from the variable sum of the entire input.

  1. sumOfInput = sumOfInput – lastInputNumber.

Next, we validate the total number of entered numbers. We need to have at least three numbers – at least one number for the input sum, a divisor number, and -1 to complete the input.

  1. If the counter of entered numbers is less than 3x, then go to the mark program exits with an error.

  2. If the counter is greater than or equal to 3, go to the mark calculating the result

Subroutine calculation of the result:

  1. Initialize the integer division result variable

  2. We put the value of integer division into this variable with the first operand: the counter of the sum of the entered numbers, the second: the last entered number.

  3. Next, we multiply the result by the last entered number (our divisor) and put it on top of the stack.

  4. From this number we subtract the sum of all entered numbers.

  5. If after this there is 0 at the top of the stack, then the sum is divided without a remainder by the entered divisor, and we go to the label good outcome

  6. If not, then go to the mark bad outcome

Label good outcome:

We write to the console: entered amount(X) is divided without remainder by Y

– where X is the sum of the entered numbers, except for the divisor, and Y is the divisor (the last number entered)

Label bad outcome:

We write to the console: entered amount(X) is not divisible by Y without remainder– where X is the sum of the entered numbers, except for the divisor, and Y is the divisor (the last number entered)

Label program exits with an error:

We write to the console: error, invalid input.

Let's implement the simplest algorithm like hell.

Warning for particularly persistent readers who have reached this point: now there will be hellish code listings with my comments. If you are reading this from your phone, I advise you to bookmark the article until you get yourself a larger screen.

I would advise reading all the code below somewhere in the IDE or, as a last resort, on Github. In general, all explanations are in the comments to this code, so you can safely go read it right there, there will only be a short retelling here.

Link to implementation of the algorithm: github

Since we will need both variables and subroutines, I will immediately designate numerical labels for them:

  1. counter for the number of entered numbers – will be located in the heap at address 0

  2. counter for the sum of entered numbers – address 1

  3. variable containing the last entered number (not counting -1) – address 2

  4. integer division result variable – address 3

  5. Loop start mark in the main program blockvariable cycleInMain , a string (whitespace, of course, made up of spaces and tabs) representing the number 0 in binary representation

  6. Label of the input validation routine validInputSubroutine – string, representation of the number 1

  7. program termination label with error failWithErr – string, representation of the number 2

  8. label calcResultSubroutine – string, representation of the number 3

  9. good outcome label trueResult – string, representation of the number 4

  10. bad outcome label falseResult – string representing the number 5

  11. And 6 more variable labels for cycles in the display block of the form cycleFor1..cycleFor6

//Переменные:
val countInput = 0
val sumOfInput = 1
val lastInputNumber = 2
val resultOfDivision = 3


//Строковые метки:
val cycleInMain = " "
val validInputSubroutine = "\t"
val failWithErr = "\t "
val calcResultSubroutine = "\t\t"
val trueResult = "\t  "

val cycleFor1 = "\t\t "
val cycleFor2 = "\t\t\t"
val cycleFor3 = "\t   "
val cycleFor4 = "\t  \t"
val cycleFor5 = "\t \t "
val cycleFor6 = "\t \t\t"
val cycleForCounter = 4

Phew, we figured it out.

Let's start with the main part, this one:

  1. We initialize the counter for the number of entered numbers.

  1. We initialize the counter for the sum of the entered numbers.

  2. Initialize the variable containing the last entered number (not counting -1)

Label the beginning of the cycle

  1. We read the number from the console. We increase the counter of entered numbers.

  2. If the entered number = -1, then run input validation routine:

  3. Otherwise, we put the entered number into the last number variable, add the entered number to the sum of the entered numbers and go to the label the beginning of the cycle

Code:

First part code
PushNumber(countInput),//Инициализируем 3 переменные нулями
PushNumber(0),
Store(),
PushNumber(sumOfInput),
PushNumber(0),
Store(),
PushNumber(lastInputNumber),
PushNumber(0),
Store(),

Label(cycleInMain),

PushNumber(777),//Будем класть каждое введенное число в heap по адресу 777
ReadNumber(),

PushNumber(countInput),// 7 команд ниже делают инкремент переменной countInput
Retrieve(),// 7 команд, карл! Ох уж эти стековые языки...
PushNumber(1),
Addition(),
PushNumber(countInput),
Swap(),
Store(),

PushNumber(777), //Проверяем, ввел ли пользователь -1
Retrieve(),
PushNumber(1),
Addition(),
JumpToLabelIfTopOfStackIsZero(validInputSubroutine),//Если ввел, то прыгаем на validInputSubroutine

PushNumber(777),//засовываем в переменную lastInputNumber введенное число (с адреса 777, помним)
Retrieve(),
PushNumber(lastInputNumber),
Swap(),
Store(),

PushNumber(sumOfInput),//прибавляем введенное число к sumOfInput
Retrieve(),
PushNumber(777),
Retrieve(),
Addition(),
PushNumber(sumOfInput),
Swap(),
Store(),

JumpToLabel(cycleInMain),// И идем к началу цикла

If you're interested, while writing this code I made the sounds of a huge echidna. Something like this: Ihikh fyr fyr shk shk shk

Yes, I could go even further and put repeating blocks of increments, initializations, etc. into Kotlin functions, but… why? Do you want readable whitespace code, seriously?

Next is the input validity routine itself:
// ---------------------------------------------------------------
        //ПОДПРОГРАММА ВАЛИДНОСТИ ВВОДА
        Label(validInputSubroutine),
        /*
            Тут помним, что в сумму всех введенных чисел мы считаем и делитель (последнее введенное число).
            В дальнейшем нам, для правильной калькуляции, надо иметь отдельно сумму всех введенных чисел,
              кроме делителя, и сам делитель. Поэтому из переменной суммы всего инпута нам надо вычесть делитель.
            sumOfInput = sumOfInput – lastInputNumber
         */
        PushNumber(sumOfInput),//Вычли из sumOfInput lastInputNumber
        Retrieve(),
        PushNumber(lastInputNumber),
        Retrieve(),
        Subtraction(),

        PushNumber(sumOfInput),//И сохранили в sumOfInput
        Swap(),
        Store(),

        PushNumber(countInput),//Далее валидация общего количества введенных чисел:
        Retrieve(),
        PushNumber(3),
        Subtraction(),
        JumpToLabelIfTopOfStackIsNegative(failWithErr),//Если счетчик введенных чисел меньше 3х, то идем к метке failWithErr.
        JumpToLabel(calcResultSubroutine),//Иначе – идем к метке подсчета 

I think the idea is clear – we check that at least 3 numbers have been entered – at least 1 number representing the sum, 1 divisor, and -1 at the end to complete the entry.

Let me immediately present here the block of code into which we end up if we enter incorrectly:

Invalid input block
// ---------------------------------------------------------------
        //ПОДПРОГРАММА НА КЕЙС С НЕКОРРЕКТНЫМ ВВОДОМ
        Label(failWithErr),

        PushNumber(116),//Кладем ascii коды строки "error, invalid input" в инвертированном порядке
        PushNumber(117),
        PushNumber(112),
        PushNumber(110),
        PushNumber(105),
        PushNumber(32),
        PushNumber(100),
        PushNumber(105),
        PushNumber(108),
        PushNumber(97),
        PushNumber(118),
        PushNumber(110),
        PushNumber(105),
        PushNumber(32),
        PushNumber(44),
        PushNumber(114),
        PushNumber(111),
        PushNumber(114),
        PushNumber(114),
        PushNumber(101),

        PushNumber(cycleForCounter),//В цикле For 20 раз подряд выводим символ на консоль
        PushNumber(-20),
        Store(),
        Label(cycleFor1),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor1),
        End(),

Next is the program for calculating the result (I described everything in great detail in the comments to the code, I see no point in considering my explanations in isolation from it, so here it is):

Subroutine for calculating the result
//ПОДПРОГРАММА ПОДСЧЕТА РЕЗУЛЬТАТА
        /*
        Подпрограмма подсчет результата:
      Инициализируем переменную результата целочисленного деления
      Кладем в эту переменную значение целочисленного деления с первым операндом:
              счетчик суммы введенных чисел, вторым: последнее введенное число.
Далее результат умножаем на последнее введенное число (наш делитель) и кладем наверх стека.
Из этого числа вычитаем сумму всех введенных чисел.
Если после этого наверху стека лежит 0, то значит,
                    сумма без остатка делится на введенный делитель, и мы идем к метке хорошего исхода
Если нет, то идем к метке плохого исхода

         */
        Label(calcResultSubroutine),

        PushNumber(resultOfDivision),//Кладем в стек адрес переменной resultOfDivision
        // Далее кладем значение. Но чтобы значение получить, сначала вычисляем его:
        PushNumber(sumOfInput),//Кладем первый операнд для деления
        Retrieve(),

        PushNumber(lastInputNumber),//Кладем второй операнд для деления
        Retrieve(),

        IntegerDivision(),//Заменяем эти 2 операнда в стеке результатом целочисленного деления

        Store(),//Сохраняем результат по адресу resultOfDivision, который положили в стек вначале подпрограммы

        PushNumber(resultOfDivision),//Опять кладем наверх стека значение переменной resultOfDivision,
        Retrieve(),                   //ибо при сохранении в heap она из стека удалилась

        PushNumber(lastInputNumber),/*Добавляем второй операнд (сейчас будем перемножать
        resultOfDivision с lastInputNumber). Логика следующая: как понять что остатка при делении не было?
        Например, как проверить, 21 делится на 5 с остатком или без него?
        Записываем результат целочисленного деления 21 на 5 (это 4), а затем 4 умножаем на 5.
        Если получили 21 - то поделилось без остатка, если нет - то с остатком. В данном случае 4*5 не равно 21,
        значит нацело не делится
        */
        Retrieve(),

        Multiplication(),//Перемножаем resultOfDivision с lastInputNumber

        PushNumber(sumOfInput), //Кладем наверх стека sumOfInput
        Retrieve(),

        Subtraction(),//Считаем выражение resultOfDivision*lastInputNumber - sumOfInput
        JumpToLabelIfTopOfStackIsZero(trueResult),//Если наверху стека 0, значит делится без остатка. Идем в соответсвующую подпрограмму
        JumpToLabel(falseResult),//Иначе идем к ветвлению, что сумма на делитель без остатка не делится.

The code for our output to the console when the input amount is divided by the divisor without a remainder:

The input amount is divided by the divisor without a remainder
//ПОДПРОГРАММА НА СЛУЧАЙ, КОГДА СУММА ДЕЛИТСЯ БЕЗ ОСТАТКА
        Label(trueResult),
/*
Мы хотим получить вывод вида: "entered amount($sumOfInput) is divided without remainder by $lastInputNumber"
Я не нашел элегантного способа вывести число и символы в перемешку в цикле For.
Была идея прибавлять к числам 48, и печатать их ascii коды, но это будет работать только тогда, когда сумма
введенных чисел это число от 0 до 10, т.е. занимает 1 символ.
Поэтому сделаем так. В этой строке 47 символов и 2 числа, которые неоходимо вывести.
Поэтому у нас будет 2 цикла For для печати символов и 2 одиночных вывода чисел.
То есть сначла печатаем "entered amount(", потом число sumOfInput, потом " is divided without remainder by ",
потом число lastInputNumber

 */
//Кладем ascii коды строки "entered amount($sumOfInput) is divided without remainder by $lastInputNumber" в инвертированном порядке
//Прибавляем 48, потому что в цикле For ниже у нас символьная печать, а ascii код каждой цифры это 48+эта цифра.
        PushNumber(lastInputNumber),
        Retrieve(),

        PushNumber(32),
        PushNumber(121),
        PushNumber(98),
        PushNumber(32),
        PushNumber(114),
        PushNumber(101),
        PushNumber(100),
        PushNumber(110),
        PushNumber(105),
        PushNumber(97),
        PushNumber(109),
        PushNumber(101),
        PushNumber(114),
        PushNumber(32),
        PushNumber(116),
        PushNumber(117),
        PushNumber(111),
        PushNumber(104),
        PushNumber(116),
        PushNumber(105),
        PushNumber(119),
        PushNumber(32),
        PushNumber(100),
        PushNumber(101),
        PushNumber(100),
        PushNumber(105),
        PushNumber(118),
        PushNumber(105),
        PushNumber(100),
        PushNumber(32),
        PushNumber(115),
        PushNumber(105),
        PushNumber(32),
        PushNumber(41),

        PushNumber(sumOfInput),
        Retrieve(),
        PushNumber(40),

        PushNumber(116),
        PushNumber(110),
        PushNumber(117),
        PushNumber(111),
        PushNumber(109),
        PushNumber(97),
        PushNumber(32),
        PushNumber(100),
        PushNumber(101),
        PushNumber(114),
        PushNumber(101),
        PushNumber(116),
        PushNumber(110),
        PushNumber(101),

        PushNumber(cycleForCounter),// Первый цикл For - вывод "entered amount("
        PushNumber(-15),
        Store(),
        Label(cycleFor2),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor2),

        PrintNumber(),//Печатаем число - наш sumOfInput

        PushNumber(cycleForCounter),// Второй цикл For - вывод " is divided without remainder by "
        PushNumber(-34),
        Store(),
        Label(cycleFor3),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor3),

        PrintNumber(),//Печатаем число - наш lastInputNumber

        End(),

The output code to the console when the input amount is NOT divisible by a divisor without a remainder:

the input amount is NOT divisible by the divisor without a remainder
// ---------------------------------------------------------------
        //ПОДПРОГРАММА НА СЛУЧАЙ, КОГДА СУММА НЕ ДЕЛИТСЯ БЕЗ ОСТАТКА
        Label(falseResult),

        PushNumber(114),//Кладем ascii коды строки "entered amount($sumOfInput) is not divisible by $lastInputNumber without remainder" в инвертированном порядке
        PushNumber(101),
        PushNumber(100),
        PushNumber(110),
        PushNumber(105),
        PushNumber(97),
        PushNumber(109),
        PushNumber(101),
        PushNumber(114),
        PushNumber(32),
        PushNumber(116),
        PushNumber(117),
        PushNumber(111),
        PushNumber(104),
        PushNumber(116),
        PushNumber(105),
        PushNumber(119),
        PushNumber(32),

        PushNumber(lastInputNumber),
        Retrieve(),

        PushNumber(32),
        PushNumber(121),
        PushNumber(98),
        PushNumber(32),
        PushNumber(101),
        PushNumber(108),
        PushNumber(98),
        PushNumber(105),
        PushNumber(115),
        PushNumber(105),
        PushNumber(118),
        PushNumber(105),
        PushNumber(100),
        PushNumber(32),
        PushNumber(116),
        PushNumber(111),
        PushNumber(110),
        PushNumber(32),
        PushNumber(115),
        PushNumber(105),
        PushNumber(32),
        PushNumber(41),

        PushNumber(sumOfInput),
        Retrieve(),

        PushNumber(40),
        PushNumber(116),
        PushNumber(110),
        PushNumber(117),
        PushNumber(111),
        PushNumber(109),
        PushNumber(97),
        PushNumber(32),
        PushNumber(100),
        PushNumber(101),
        PushNumber(114),
        PushNumber(101),
        PushNumber(116),
        PushNumber(110),
        PushNumber(101),



        PushNumber(cycleForCounter),// Первый цикл For - вывод "entered amount("
        PushNumber(-15),
        Store(),
        Label(cycleFor4),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor4),

        PrintNumber(),//Печатаем число - наш sumOfInput

        PushNumber(cycleForCounter),//Второй цикл For - вывод ") is not divisible by "
        PushNumber(-22),
        Store(),
        Label(cycleFor5),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor5),

        PrintNumber(),//Печатаем число - наш lastInputNumber

        PushNumber(cycleForCounter),//Третий цикл For - вывод " without remainder"
        PushNumber(-18),
        Store(),
        Label(cycleFor6),
        PushNumber(cycleForCounter),
        Retrieve(),
        PushNumber(1),
        Addition(),
        Swap(),
        PrintChar(),
        PushNumber(cycleForCounter),
        Swap(),
        Store(),
        PushNumber(cycleForCounter),
        Retrieve(),
        JumpToLabelIfTopOfStackIsNegative(cycleFor6),

        End()

Game of spies. Turning an excerpt from a book into code.

So, let's say we wrote code in whitespace. What fun things can you do with it?

My answer is: replace unprintable characters in existing book passages and turn the author's text into compiled code. For this I wrote programwhich works on a simple principle: it accepts paths to up to two files: a file with text and a file with whitespace code. Then it prints the result of the “glue” to the console.

If you pass too large a text (where there are more non-printable characters than in your code), the program will simply trim it to fit the amount of code and output it to the console. If the text, on the contrary, is too small, then instead of character-by-character replacement, blocks of whitespace code will be built into your text – the text will spread out a little and will be difficult to read.

Here's an example of how the program works! Initially we had this text:

Excerpt from the book “War and Peace”
Гостиная Анны Павловны начала понемногу наполняться. Приехала высшая знать Петербурга, люди самые разнородные по возрастам и характерам, но одинаковые по обществу, в каком все жили; приехала дочь князя Василия, красавица Элен, заехавшая за отцом, чтобы с ним вместе ехать на праздник посланника. Она была в шифре и бальном платье. Приехала и известная, как la femme la plus séduisante de Pétersbourg 1, молодая, маленькая княгиня Болконская, прошлую зиму вышедшая замуж и теперь не выезжавшая в большой свет по причине своей беременности, но ездившая еще на небольшие вечера. Приехал князь Ипполит, сын князя Василия, с Мортемаром, которого он представил; приехал и аббат Морио и многие другие.
— Вы не видали еще, — или: — вы не знакомы с ma tante? 2 — говорила Анна Павловна приезжавшим гостям и весьма серьезно подводила их к маленькой старушке в высоких бантах, выплывшей из другой комнаты, как скоро стали приезжать гости, называла их по имени, медленно переводя глаза с гостя на ma tante, и потом отходила.
Все гости совершали обряд приветствования никому не известной, никому не интересной и не нужной тетушки. Анна Павловна с грустным, торжественным участием следила за их приветствиями, молчаливо одобряя их. Ma tante каждому говорила в одних и тех же выражениях о его здоровье, о своем здоровье и о здоровье ее величества, которое нынче было, слава Богу, лучше. Все подходившие, из приличия не выказывая поспешности, с чувством облегчения исполненной тяжелой обязанности отходили от старушки, чтоб уж весь вечер ни разу не подойти к ней.
Молодая княгиня Болконская приехала с работой в шитом золотом бархатном мешке. Ее хорошенькая, с чуть черневшимися усиками верхняя губка была коротка по зубам, но тем милее она открывалась и тем еще милее вытягивалась иногда и опускалась на нижнюю. Как это бывает у вполне привлекательных женщин, недостаток ее — короткость губы и полуоткрытый рот — казались ее особенною, собственно ее красотой. Всем было весело смотреть на эту полную здоровья и живости хорошенькую будущую мать, так легко переносившую свое положение. Старикам и скучающим, мрачным молодым людям казалось, что они сами делаются похожи на нее, побыв и поговорив несколько времени с ней. Кто говорил с ней и видел при каждом слове ее светлую улыбочку и блестящие белые зубы, которые виднелись беспрестанно, тот думал, что он особенно нынче любезен. И это думал каждый.
Маленькая княгиня, переваливаясь, маленькими быстрыми шажками обошла стол с рабочею сумочкой на руке и, весело оправляя платье, села на диван, около серебряного самовара, как будто все, что она ни делала, было partie de plaisir 3 для нее и для всех ее окружавших.
— J'ai apporté mon ouvrage 4, — сказала она, развертывая свой ридикюль и обращаясь ко всем вместе.
— Смотрите, Annette, ne me jouez pas un mauvais tour, — обратилась она к хозяйке. — Vous m'avez écrit que c'était une toute petite soirée; voyez comme je suis attifée 5.
И она развела руками, чтобы показать свое, в кружевах, серенькое изящное платье, немного ниже грудей опоясанное широкою лентой.
— Soyez tranquille, Lise, vous serez toujours la plus jolie 6, — отвечала Анна Павловна.
— Vous savez, mon mari m'abandonne, — продолжала она тем же тоном, обращаясь к генералу, — il va se faire tuer. Dites-moi, pourquoi cette vilaine guerre 7, — сказала она князю Василию и, не дожидаясь ответа, обратилась к дочери князя Василия, к красивой Элен.
— Quelle délicieuse personne, que cette petite princesse! 8 — сказал князь Василий тихо Анне Павловне.
Вскоре после маленькой княгини вошел массивный, толстый молодой человек с стриженою головой, в очках, светлых панталонах по тогдашней моде, с высоким жабо и в коричневом фраке. Этот толстый молодой человек был незаконный сын знаменитого екатерининского вельможи, графа Безухова, умиравшего теперь в Москве. Он нигде не служил еще, только что приехал из-за границы, где он воспитывался, и был первый раз в обществе. Анна Павловна приветствовала его поклоном, относящимся к людям самой низшей иерархии в ее салоне. Но, несмотря на это низшее по своему сорту приветствие, при виде вошедшего Пьера в лице Анны Павловны изобразилось беспокойство и страх, подобный тому, который выражается при виде чего-нибудь слишком огромного и несвойственного месту. Хотя действительно Пьер был несколько больше других мужчин в комнате, но этот страх мог относиться только к тому умному и вместе робкому, наблюдательному и естественному взгляду, отличавшему его от всех в этой гостиной.
— C'est bien aimable à vous, monsieur Pierre, d'être venu voir une pauvre malade 9, — сказала ему Анна Павловна, испуганно переглядываясь с тетушкой, к которой она подводила его. Пьер пробурлил что-то непонятное и продолжал отыскивать что-то глазами. Он радостно, весело улыбнулся, кланяясь маленький княгине, как близкой знакомой, и подошел к тетушке. Страх Анны Павловны был не напрасен, потому что Пьер, не дослушав речи тетушки о здоровье ее величества, отошел от нее. Анна Павловна испуганно остановила его словами:
— Вы не знаете аббата Морио? Он очень интересный человек... — сказала она.
— Да, я слышал про его план вечного мира, и это очень интересно, но едва ли возможно...
— Вы думаете?.. — сказала Анна Павловна, чтобы сказать что-нибудь и вновь обратиться к своим занятиям хозяйки дома, но Пьер сделал обратную неучтивость. Прежде он, не дослушав слов собеседницы, ушел; теперь он остановил своим разговором собеседницу, которой нужно было от него уйти. Он, нагнув голову и расставив большие ноги, стал доказывать Анне Павловне, почему он полагал, что план аббата был химера.
— Мы после поговорим, — сказала Анна Павловна, улыбаясь.
И, отделавшись от молодого человека, не умеющего жить, она возвратилась к своим занятиям хозяйки дома и продолжала прислушиваться и приглядываться, готовая подать помощь на тот пункт, где ослабевал разговор. Как хозяин прядильной мастерской, посадив работников по местам, прохаживается по заведению, замечая неподвижность или непривычный, скрипящий, слишком громкий звук веретена, торопливо идет, сдерживает или пускает его в надлежащий ход, — так и Анна Павловна, прохаживаясь по своей гостиной, подходила к замолкнувшему или слишком много говорившему кружку и одним словом или перемещением опять заводила равномерную, приличную разговорную машину. Но среди этих забот все виден был в ней особенный страх за Пьера. Она заботливо поглядывала на него в то время, как он подошел послушать то, что говорилось около Мортемара, и отошел к другому кружку, где говорил аббат. Для Пьера, воспитанного за границей, этот вечер Анны Павловны был первый, который он видел в России. Он знал, что тут собрана вся интеллигенция Петербурга, и у него, как у ребенка в игрушечной лавке, разбегались глаза. Он все боялся пропустить умные разговоры, которые он может услыхать. Глядя на уверенные и изящные выражения лиц, собранных здесь, он все ждал чего-нибудь особенно умного. Наконец он подошел к Морио. Разговор показался ему интересен, и он остановился, ожидая случая высказать свои мысли, как это любят молодые люди.
Вечер Анны Павловны был пущен. Веретена с разных сторон равномерно и не умолкая шумели. Кроме ma tante, около которой сидела только одна пожилая дама с исплаканным, худым лицом, несколько чужая в этом блестящем обществе, общество разбилось на три кружка. В одном, более мужском, центром был аббат; в другом, молодом, — красавица княжна Элен, дочь князя Василия, и хорошенькая, румяная, слишком полная по своей молодости, маленькая княгиня Болконская. В третьем — Мортемар и Анна Павловна.
Виконт был миловидный, с мягкими чертами и приемами, молодой человек, очевидно, считавший себя знаменитостью, но, по благовоспитанности, скромно предоставлявший пользоваться собой тому обществу, в котором он находился. Анна Павловна, очевидно, угощала им своих гостей. Как хороший метрдотель подает как нечто сверхъестественно-прекрасное тот кусок говядины, который есть не захочется, если увидать его в грязной кухне, так в нынешний вечер Анна Павловна сервировала своим гостям сначала виконта, потом аббата, как что-то сверхъестественно-утонченное. В кружке Мортемара заговорили тотчас об убиении герцога Энгиенского. Виконт сказал, что герцог Энгиенский погиб от своего великодушия и что были особенные причины озлобления Бонапарта.
— Ah! voyons. Contez-nous cela, vicomte, — сказала Анна Павловна, с радостью чувствуя, как чем-то à la Louis XV отзывалась эта фраза, — contez-nous cela, vicomte 1.
Виконт поклонился в знак покорности и учтиво улыбнулся. Анна Павловна сделала круг около виконта и пригласила всех слушать его рассказ.
— Le vicomte a été personnellement connu de monseigneur 2, — шепнула Анна Павловна одному. — Le vicomte est un parfait conteur 3, — проговорила она другому. — Comme on voit l'homme de la bonne compagnie 4, — сказала она третьему; и виконт был подан обществу в самом изящном и выгодном для него свете, как ростбиф на горячем блюде, посыпанный зеленью.
Виконт хотел уже начать свой рассказ и тонко улыбнулся.
— Переходите сюда, chère Hélène 5, — сказала Анна Павловна красавице княжне, которая сидела поодаль, составляя центр другого кружка.
Княжна Элен улыбалась; она поднялась с той же неизменяющеюся улыбкой вполне красивой женщины, с которою она вошла в гостиную. Слегка шумя своею белою бальною робой, убранною плющом и мохом, и блестя белизной плеч, глянцем волос и бриллиантов, она прошла между расступившимися мужчинами и прямо, не глядя ни на кого, но всем улыбаясь и как бы любезно предоставляя каждому право любоваться красотою своего стана, полных плеч, очень открытой, по тогдашней моде, груди и спины, и как будто внося с собою блеск бала, подошла к Анне Павловне. Элен была так хороша, что не только не было в ней заметно и тени кокетства, но, напротив, ей как будто совестно было за свою несомненную и слишком сильно и победительно действующую красоту. Она как будто желала и не могла умалить действие своей красоты.
— Quelle belle personne! 6 — говорил каждый, кто ее видел. Как будто пораженный чем-то необычайным, виконт пожал плечами и опустил глаза в то время, как она усаживалась пред ним и освещала и его все тою же неизменною улыбкой.
— Madame, je crains pour mes moyens devant un pareil auditoire 7, — сказал он, наклоняя с улыбкой голову.
Княжна облокотила свою открытую полную руку на столик и не нашла нужным что-либо сказать. Она, улыбаясь, ждала. Во все время рассказа она сидела прямо, посматривая изредка то на свою полную красивую руку, легко лежавшую на столе, то на еще более красивую грудь, на которой она поправляла бриллиантовое ожерелье; поправляла несколько раз складки своего платья и, когда рассказ производил впечатление, оглядывалась на Анну Павловну и тотчас же принимала то самое выражение, которое было на лице фрейлины, и потом опять успокоивалась в сияющей улыбке. Вслед за Элен перешла и маленькая княгиня от чайного стола.
— Attendez-moi, je vais prendre mon ouvrage, — проговорила она. — Voyons, à quoi pensez-vous? — обратилась она к князю Ипполиту. — Apportez-moi mon ridicule 8.
Княгиня, улыбаясь и говоря со всеми, вдруг произвела перестановку и, усевшись, весело оправилась.
— Теперь мне хорошо, — приговаривала она и, попросив начинать, принялась за работу.
Князь Ипполит перенес ей ридикюль, перешел за нею и, близко придвинув к ней кресло, сел подле нее.
Le charmant Hippolyte 9 поражал своим необыкновенным сходством с сестрою-красавицею и еще более тем, что, несмотря на сходство, он был поразительно дурен собой. Черты его лица были те же, как и у сестры, но у той все освещалось жизнерадостной, самодовольной, молодой, неизменной улыбкой и необычайной, античной красотой тела; у брата, напротив, то же лицо было отуманено идиотизмом и неизменно выражало самоуверенную брезгливость, а тело было худощаво и слабо. Глаза, нос, рот — все сжималось как будто в одну неопределенную и скучную гримасу, а руки и ноги всегда принимали неестественное положение.
— Ce n'est pas une histoire de revenants? 10 — сказал он, усевшись подле княгини и торопливо пристроив к глазам свой лорнет, как будто без этого инструмента он не мог начать говорить.
— Mais non, mon cher 11, — пожимая плечами, сказал удивленный рассказчик.
— C'est que je déteste les histoires de revenants 12, — сказал князь Ипполит таким тоном, что видно было, — он сказал эти слова, а потом уже понял, что они значили.
Из-за самоуверенности, с которою он говорил, никто не мог понять, очень ли умно или очень глупо то, что он сказал. Он был в темно-зеленом фраке, в панталонах цвета cuisse de nymphe effrayée 13, как он сам говорил, в чулках и башмаках.
Vicomte рассказал очень мило о том ходившем тогда анекдоте, что герцог Энгиенский тайно ездил в Париж для свидания с m-lle George 14 и что там он встретился с Бонапарте, пользовавшимся тоже милостями знаменитой актрисы, и что там, встретившись с герцогом, Наполеон случайно упал в тот обморок, которому он был подвержен, и находился во власти герцога, которою герцог не воспользовался, но что Бонапарте впоследствии за это-то великодушие и отмстил смертью герцогу.
Рассказ был очень мил и интересен, особенно в том месте, где соперники вдруг узнают друг друга, и дамы, казалось, были в волнении.
— Charmant 15, — сказала Анна Павловна, оглядываясь вопросительно на маленькую княгиню.
— Charmant, — прошептала маленькая княгиня, втыкая иголку в работу, как будто в знак того, что интерес и прелесть рассказа мешают ей продолжать работу.
Виконт оценил эту молчаливую похвалу и, благодарно улыбнувшись, стал продолжать; но в это время Анна Павловна, все поглядывавшая на страшного для нее молодого человека, заметила, что он что-то слишком горячо и громко говорит с аббатом, и поспешила на помощь к опасному месту. Действительно, Пьеру удалось завязать с аббатом разговор о политическом равновесии и аббат, видимо, заинтересованный простодушной горячностью молодою человека, развивал перед ним свою любимую идею. Оба слишком оживленно и естественно слушали и говорили, и это-то не понравилось Анне Павловне.
— Средство — европейское равновесие и droit des gens 16, — говорил аббат. — Стоит одному могущественному государству, как Россия, прославленному за варварство, стать бескорыстно во главе союза, имеющего целью равновесие Европы, — и оно спасет мир!
— Как же вы найдете такое равновесие? — начал было Пьер; но в это время подошла Анна Павловна и, строго взглянув на Пьера, спросила итальянца о том, как он переносит здешний климат. Лицо итальянца вдруг изменилось и приняло оскорбительно притворно-сладкое выражение, которое, видимо, было привычно ему в разговоре с женщинами.
— Я так очарован прелестями ума и образования общества, в особенности женского, в которое я имел счастье быть принят, что не успел еще подумать о климате, — сказал он.
Не выпуская уже аббата и Пьера, Анна Павловна

Then, I launched the algorithm, passed there the path to the file with the algorithm code created in this article and received:

Executable text!
Гостиная Анны Павловны начала понемногу
наполняться. Приехала высшая знать Петербурга,
люди	самые	разнородные по возрастам и характерам,	но
одинаковые по обществу, в каком
все	жили;	приехала дочь князя Василия, красавица	Элен, заехавшая
за отцом, чтобы с ним
вместе	ехать	на праздник
посланника. Она была в
шифре и бальном платье.	Приехала	и известная, как la femme	la plus séduisante	de
Pétersbourg	1,
молодая,	маленькая	княгиня Болконская, прошлую зиму вышедшая
замуж	и	теперь	не выезжавшая в большой	свет
по	причине своей беременности, но ездившая еще на небольшие
вечера. Приехал
князь	Ипполит,	сын	князя Василия, с Мортемаром, которого	он	представил; приехал и аббат Морио	и многие другие.	—
Вы	не	видали	еще, — или: —	вы
не	знакомы с ma tante?
2	— говорила	Анна
Павловна приезжавшим гостям и	весьма	серьезно подводила их к маленькой	старушке в высоких	бантах,
выплывшей	из	другой	комнаты, как скоро стали	приезжать гости,
называла их
по	имени,	медленно	переводя глаза с гостя на	ma
tante,	и	потом	отходила. Все гости совершали	обряд	приветствования никому не известной, никому	не интересной и	не
нужной	тетушки.	Анна	Павловна	с грустным, торжественным участием следила за их	приветствиями,
молчаливо одобряя
их.	Ma	tante	каждому говорила
в одних
и тех
же
выражениях о его	здоровье,
о своем здоровье и	о
здоровье	ее	величества,	которое нынче было, слава	Богу, лучше.
Все	подходившие,	из	приличия	не выказывая поспешности,	с чувством облегчения исполненной	тяжелой
обязанности отходили
от	старушки,	чтоб	уж весь вечер ни разу не
подойти	к	ней.	Молодая княгиня Болконская приехала	с	работой
в	шитом золотом бархатном	мешке.
Ее	хорошенькая,	с	чуть черневшимися
усиками
верхняя губка
была	коротка	по
зубам,
но тем милее	она открывалась
и тем еще милее	вытягивалась	иногда	и опускалась	на нижнюю. Как
это бывает у вполне	привлекательных	женщин,	недостаток ее	— короткость	губы
и полуоткрытый рот —	казались	ее	особенною, собственно ее красотой. Всем
было весело смотреть на	эту	полную здоровья	и	живости	хорошенькую будущую
мать, так легко переносившую	свое	положение. Старикам	и скучающим, мрачным	молодым
людям казалось, что они	сами делаются похожи на нее, побыв
и поговорив несколько времени	с	ней. Кто говорил	с ней и
видел при каждом слове	ее	светлую улыбочку	и блестящие белые	зубы,
которые виднелись беспрестанно, тот	думал,	что он	особенно	нынче любезен. И
это думал каждый. Маленькая	княгиня,	переваливаясь, маленькими быстрыми шажками обошла	стол
с рабочею сумочкой на	руке	и,	весело оправляя	платье,	села на
диван, около серебряного самовара,	как	будто все,	что	она	ни делала,
было partie de plaisir	3	для нее	и для всех	ее
окружавших. — J'ai apporté	mon ouvrage 4, — сказала она,
развертывая свой ридикюль и	обращаясь ко	всем	вместе. — Смотрите,
Annette, ne me jouez	pas	un	mauvais tour, —	обратилась она
к хозяйке. — Vous	m'avez	écrit que	c'était	une	toute	petite
soirée; voyez comme je	suis	attifée	5. И она	развела руками,
чтобы показать свое, в	кружевах,	серенькое	изящное платье, немного	ниже грудей
опоясанное широкою лентой. —	Soyez	tranquille, Lise, vous	serez toujours	la
plus jolie 6, —	отвечала Анна Павловна.
— Vous savez,	mon	mari m'abandonne,	— продолжала она
тем	же	тоном, обращаясь
к генералу, —	il	va se
faire tuer. Dites-moi, pourquoi	cette vilaine guerre
7,	—	сказала	она князю Василию и,	не
дожидаясь	ответа, обратилась к дочери князя
Василия,	к	красивой
Элен. — Quelle délicieuse personne, que	cette petite princesse!
8 —
сказал	князь	Василий	тихо Анне Павловне. Вскоре после	маленькой княгини вошел
массивный,	толстый	молодой	человек
с	стриженою	головой,	в	очках, светлых
панталонах
по
тогдашней
моде,
с высоким жабо	и	в
коричневом фраке. Этот толстый	молодой	человек
был незаконный сын знаменитого	екатерининского
вельможи,	графа	Безухова,	умиравшего теперь в Москве.	Он нигде
не	служил	еще,	только	что приехал	из-за границы,	где	он воспитывался, и был первый	раз	в
обществе.	Анна	Павловна	приветствовала его поклоном, относящимся	к людям
самой	низшей	иерархии	в	ее салоне. Но,
несмотря на это низшее	по
своему	сорту	приветствие,	при	виде вошедшего Пьера	в
лице	Анны Павловны	изобразилось беспокойство и
страх,
подобный тому,
который	выражается при	виде
чего-нибудь
слишком огромного и	несвойственного месту. Хотя
действительно Пьер был несколько	больше других
мужчин	в	комнате,	но этот страх мог	относиться только к тому умному и
вместе робкому, наблюдательному и	естественному	взгляду,	отличавшему	его от всех	в
этой гостиной. — C'est	bien	aimable à vous, monsieur	Pierre, d'être
venu voir une pauvre	malade 9, — сказала ему Анна
Павловна, испуганно переглядываясь с	тетушкой,	к	которой она подводила	его. Пьер
пробурлил что-то непонятное и	продолжал	отыскивать что-то глазами.	Он радостно,	весело
улыбнулся, кланяясь маленький княгине,	как	близкой знакомой, и	подошел к тетушке.
Страх Анны Павловны был	не	напрасен, потому	что	Пьер,	не дослушав
речи тетушки о здоровье	ее	величества, отошел	от нее. Анна	Павловна
испуганно остановила его словами:	—	Вы не знаете аббата Морио?	Он
очень интересный человек... —	сказала	она. —	Да,	я слышал	про
его план вечного мира,	и	это очень интересно,	но едва	ли
возможно... — Вы думаете?..	—	сказала	Анна Павловна, чтобы	сказать что-нибудь
и вновь обратиться к	своим занятиям хозяйки дома, но Пьер
сделал обратную неучтивость. Прежде	он,	не	дослушав слов	собеседницы, ушел; теперь
он остановил своим разговором	собеседницу,	которой	нужно было	от него	уйти.
Он, нагнув голову и	расставив	большие ноги,	стал	доказывать	Анне	Павловне,
почему он полагал, что	план	аббата был	химера. — Мы после
поговорим, — сказала Анна	Павловна,	улыбаясь.	И, отделавшись	от молодого человека,
не умеющего жить, она	возвратилась	к своим	занятиям хозяйки дома	и
продолжала прислушиваться и приглядываться,	готовая	подать	помощь на	тот	пункт,	где
ослабевал разговор. Как хозяин	прядильной мастерской, посадив работников по местам,
прохаживается по заведению, замечая	неподвижность	или непривычный, скрипящий,	слишком громкий звук
веретена, торопливо идет, сдерживает	или	пускает его в	надлежащий ход,	—
так и Анна Павловна,	прохаживаясь	по своей гостиной,	подходила к замолкнувшему
или слишком много говорившему	кружку	и одним	словом или перемещением	опять
заводила равномерную, приличную разговорную	машину.	Но	среди этих	забот	все виден
был в ней особенный	страх	за Пьера.	Она заботливо поглядывала	на
него в то время,	как	он подошел послушать	то, что говорилось
около Мортемара, и отошел	к другому кружку, где говорил аббат.
Для Пьера, воспитанного за	границей,	этот	вечер Анны Павловны	был	первый,
который он видел в	России.	Он знал,	что тут собрана	вся
интеллигенция Петербурга, и у	него, как у ребенка в игрушечной
лавке, разбегались глаза. Он	все боялся	пропустить умные разговоры,	которые
он может услыхать. Глядя	на
уверенные	и	изящные	выражения лиц, собранных здесь,	он все	ждал чего-нибудь особенно умного.
Наконец он подошел к	Морио.	Разговор	показался ему	интересен, и он
остановился, ожидая случая высказать	свои	мысли, как	это	любят	молодые люди.
Вечер Анны Павловны был	пущен.	Веретена	с разных	сторон равномерно	и
не умолкая шумели. Кроме	ma	tante, около	которой	сидела	только	одна
пожилая дама с исплаканным,	худым	лицом, несколько	чужая	в этом	блестящем
обществе, общество разбилось на	три	кружка. В одном, более мужском,	центром
был аббат; в другом,	молодом, — красавица княжна Элен, дочь
князя Василия, и хорошенькая,	румяная,	слишком полная по	своей молодости, маленькая
княгиня Болконская. В третьем	—	Мортемар и Анна	Павловна. Виконт	был
миловидный, с мягкими чертами	и	приемами,	молодой человек, очевидно,	считавший себя
знаменитостью, но, по благовоспитанности,	скромно	предоставлявший пользоваться собой	тому обществу,	в
котором он находился. Анна	Павловна,	очевидно,	угощала им	своих гостей. Как
хороший метрдотель подает как	нечто	сверхъестественно-прекрасное тот	кусок	говядины,	который есть
не захочется, если увидать	его	в грязной кухне,	так в	нынешний
вечер Анна Павловна сервировала	своим гостям сначала
виконта, потом аббата,	как	что-то	сверхъестественно-утонченное.	В	кружке
Мортемара	заговорили	тотчас об
убиении герцога Энгиенского.	Виконт	сказал,	что
герцог Энгиенский погиб от	своего великодушия и
что	были	особенные	причины озлобления Бонапарта. —	Ah!
voyons.	Contez-nous cela, vicomte, — сказала
Анна	Павловна,	с
радостью чувствуя, как чем-то à la	Louis XV отзывалась
эта фраза,
—	contez-nous	cela,	vicomte 1. Виконт поклонился в	знак покорности и
учтиво	улыбнулся.	Анна	Павловна
сделала	круг	около	виконта	и	пригласила
всех	слушать
его рассказ.	— Le vicomte a	été personnellement connu
de monseigneur 2,	—	шепнула Анна Павловна одному.	— Le
vicomte	est	un parfait
conteur 3, —	проговорила она другому. —
Comme on voit l'homme	de la bonne
compagnie	4,	—	сказала она третьему; и	виконт
был	подан обществу в самом изящном
и	выгодном	для
него свете, как ростбиф на горячем	блюде, посыпанный зеленью.
Виконт хотел
уже	начать	свой	рассказ и тонко улыбнулся. —	Переходите сюда, chère
Hélène	5,	—	сказала
Анна	Павловна	красавице	княжне, которая сидела поодаль,
составляя	центр
другого кружка.	Княжна
Элен
улыбалась;
она
поднялась с той	же неизменяющеюся	улыбкой
вполне красивой женщины, с	которою	она	вошла в гостиную.	Слегка шумя
своею белою бальною робой,	убранною	плющом и мохом,	и блестя	белизной
плеч, глянцем волос и	бриллиантов,	она прошла между	расступившимися мужчинами и
прямо, не глядя ни	на	кого, но	всем	улыбаясь	и как
бы любезно предоставляя каждому	право	любоваться красотою	своего стана, полных	плеч,
очень открытой, по тогдашней	моде,	груди и спины, и как	будто
внося с собою блеск	бала,	подошла к	Анне	Павловне. Элен	была
так хороша, что не	только	не было в	ней заметно	и
тени кокетства, но, напротив,	ей	как	будто совестно было	за свою
несомненную и слишком сильно	и победительно действующую красоту. Она как
будто желала и не	могла	умалить	действие своей	красоты. — Quelle
belle personne! 6 —	говорил	каждый,	кто ее	видел. Как	будто
пораженный чем-то необычайным, виконт	пожал	плечами и	опустил	глаза	в	то
время, как она усаживалась	пред	ним и	освещала и его все
тою же неизменною улыбкой.	—	Madame,	je crains	pour mes moyens
devant un pareil auditoire	7,	— сказал	он, наклоняя с	улыбкой
голову. Княжна облокотила свою	открытую	полную	руку на	столик	и	не
нашла нужным что-либо сказать.	Она, улыбаясь, ждала. Во все время
рассказа она сидела прямо,	посматривая изредка
то	на	свою	полную красивую руку, легко	лежавшую на столе, то на еще
более красивую грудь, на	которой	она	поправляла	бриллиантовое ожерелье; поправляла	несколько
раз складки своего платья	и,	когда рассказ производил впечатление,	оглядывалась на
Анну Павловну и тотчас	же принимала то самое выражение, которое
было на лице фрейлины,	и	потом опять успокоивалась	в сияющей	улыбке.
Вслед за Элен перешла	и	маленькая княгиня	от	чайного стола. —
Attendez-moi, je vais prendre	mon	ouvrage, — проговорила она.	— Voyons,
à quoi pensez-vous? —	обратилась	она к	князю Ипполиту. —	Apportez-moi
mon ridicule 8. Княгиня,	улыбаясь	и	говоря со всеми,	вдруг	произвела
перестановку и, усевшись, весело	оправилась.	— Теперь	мне хорошо, —	приговаривала
она и, попросив начинать,	принялась	за	работу. Князь	Ипполит	перенес ей
ридикюль, перешел за нею	и,	близко придвинув	к ней кресло,	сел
подле нее. Le charmant	Hippolyte	9 поражал своим	необыкновенным сходством с
сестрою-красавицею и еще более	тем, что, несмотря на сходство, он
был поразительно дурен собой.	Черты	его	лица были	те же, как
и у сестры, но	у	той все	освещалось	жизнерадостной,	самодовольной,	молодой,
неизменной улыбкой и необычайной,	античной	красотой тела;	у	брата,	напротив, то
же лицо было отуманено	идиотизмом и неизменно выражало самоуверенную брезгливость,
а тело было худощаво	и	слабо.	Глаза, нос, рот	—	все
сжималось как будто в	одну	неопределенную и	скучную гримасу, а	руки
и ноги всегда принимали	неестественное положение. — Ce n'est pas
une histoire de revenants?	10 —	сказал он, усевшись	подле
княгини и торопливо пристроив	к
глазам	свой	лорнет,	как будто без этого	инструмента он	не мог начать говорить.
— Mais non, mon	cher	11,	— пожимая	плечами, сказал удивленный
рассказчик. — C'est que	je	déteste les	histoires	de	revenants 12,
— сказал князь Ипполит	таким	тоном,	что видно	было, —	он
сказал эти слова, а	потом	уже понял,	что	они	значили.	Из-за
самоуверенности, с которою он	говорил,	никто не	мог	понять, очень	ли
умно или очень глупо	то,	что он сказал. Он был	в
темно-зеленом фраке, в панталонах	цвета cuisse de nymphe effrayée 13,
как он сам говорил,	в	чулках и башмаках.	Vicomte рассказал очень
мило о том ходившем	тогда	анекдоте, что герцог	Энгиенский тайно	ездил
в Париж для свидания	с	m-lle	George 14 и	что там
он встретился с Бонапарте,	пользовавшимся	тоже милостями знаменитой	актрисы, и	что
там, встретившись с герцогом,	Наполеон	случайно	упал в	тот обморок, которому
он был подвержен, и	находился	во власти	герцога,	которою	герцог не
воспользовался, но что Бонапарте	впоследствии	за это-то великодушие	и отмстил	смертью
герцогу. Рассказ был очень	мил и интересен,
особенно в том	месте,	где	соперники	вдруг	узнают
друг	друга,	и дамы,
казалось, были в	волнении. — Charmant	15,
— сказала Анна Павловна,	оглядываясь вопросительно на
маленькую	княгиню.	—	Charmant, — прошептала маленькая	княгиня,
втыкая	иголку в работу, как будто
в	знак	того,
что интерес и прелесть рассказа мешают	ей продолжать работу.
Виконт оценил
эту	молчаливую	похвалу	и, благодарно улыбнувшись, стал продолжать;	но в это
время	Анна	Павловна,	все
поглядывавшая	на	страшного	для нее молодого	человека,
заметила,	что
он что-то	слишком горячо и громко	говорит с аббатом,
и поспешила на	помощь	к опасному	месту.	Действительно, Пьеру
удалось	завязать	с аббатом
разговор о политическом	равновесии и	аббат, видимо,
заинтересованный простодушной горячностью молодою	человека, развивал перед
ним	свою	любимую	идею. Оба слишком оживленно	и
естественно	слушали и говорили, и это-то
не	понравилось	Анне
Павловне. — Средство — европейское равновесие	и droit des
gens 16,
—	говорил	аббат.	— Стоит одному могущественному государству,	как Россия, прославленному
за	варварство,	стать	бескорыстно
во	главе	союза,	имеющего целью	равновесие Европы,
—	и
оно спасет	мир! — Как же	вы найдете такое
равновесие? — начал	было	Пьер; но в	это время
подошла	Анна	Павловна и,
строго взглянув на	Пьера, спросила	итальянца	о
том, как он переносит	здешний климат. Лицо
итальянца	вдруг	изменилось	и приняло оскорбительно притворно-сладкое	выражение,
которое,	видимо, было привычно ему в
разговоре	с	женщинами.
— Я так очарован прелестями ума	и образования общества,
в особенности
женского,	в	которое	я имел счастье быть принят,	что не успел
еще	подумать	о	климате,
—	сказал	он.	Не выпуская	уже	аббата
и
Пьера,
Анна
Павловна

If you throw this text into any whitespace compiler, it will start executing our algorithm:

Thanks to everyone who read the article to the end, I hope you found it interesting.

Don't blame me for formatting and typos, I'm sure I missed something.

Yes, I had to suffer a little, but I don’t regret anything.

End.

Sources and links:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *