Introduction

malb8dge is an esolang that aims to shorten code by removing words and reducing repetitions wherever possible, while still keeping it somewhat easy to write and understand. If that doesn't sound like your cup of tea, you still have about 2 chapters left to decide whether you want to stay or not.

Getting started

This chapter will teach you how to install and update malb8dge. You'll also learn how to write a "Hello, world!" program in malb8dge.

Installation

cargo stuff or something when done

Hello, world!

Now that you've successfully installed malb8dge, create a file called hello.mlb8 with the following contents:

;"Hello, world!"

To run this program, simply type malb8dge hello in your favorite terminal. If Hello, world! was printed to your console, then congratulations! You have written your first malb8dge program!

Note: malb8dge <file> isn't the only way to run malb8dge - an interactive shell also exists, which can be started by typing malb8dge without any arguments!

Now let's break down this program to understand what exactly is happening:

  • ; is an operator (more on that later) that prints everything that comes after it to the console.
  • "Hello, world!" is a string, which you probably already know from other programming languages. (If you have no programming experience, I strongly recommend immediately finding another activity to waste your precious time on.)

Great! It will almost certainly only go downhill from here on.

Making a guessing game

Now let's create something more advanced! A classic beginner project is a simple guessing game. Here is a list of instructions we want it to execute:

  • A secret random number between 1 and 100 is generated.
  • The program will repeatedly ask for the player's guess.
  • A message will be printed that states whether the guess was too high or too low.
  • If the guess is equal to the secret number, a message appears telling the player that they won and the program will stop.

Let's start with the first task - the next chapter will introduce malb8dge's operators and teach you how to generate a random number using one of them.

RNG using operators

Introducing malbd8ge's operators

Operators are usually funny mathematical symbols that have strange behaviors. malb8dge takes that to the maximum by making almost every simple function have its own 1 or 2 symbol combination, each with their own strange behavior for every single type of value. This means that malb8dge has many, many operators. If you were programming in another language and wanted to get the absolute value of a number, like for example -3, you would usually expect there to be a function that looks like abs(-3) or (-3).abs(). But guess what - malb8dge has an operator for that instead, so abs(-3) would turn into #-3. (By the way, - is another operator, so we've actually already used two operators in this example!)

Operators come in three different types:

  • Before (-x)
  • After (x$)
  • Binary (x + y)

The position is very important as it changes the entire meaning of the operator! Take 'x and x' for example - one converts a number to a character and vice versa, while the other rounds a number.

A list of all the operators in malb8dge can be found here.

Generating a random number

For our game, we will generate a number between 1 and 100, including both ends. Of course malb8dge has an operator for that: x?\. This will generate a random number between 1 and x. (It looks very ugly, but that's not the point of malb8dge. It will only get uglier.)

Create a new file called guessing_game.mlb8 and paste in the following code:

number = 100?\

This will generate a random number within our specified range and assign it to the variable number.

With our first piece of the puzzle in place, we can now move on to the next part: creating a loop and allowing the user to input their guesses.

Loops and input

Creating a loop

There are several different kinds of loops in malb8dge, but for our guessing game we'll only need the simplest one: an infinite loop. You might know this as a while true loop from other programming languages, but malb8dge has a shortcut for that:

? {

}

All our following instructions will go inside of this loop, i.e. between the curly braces, since we want the player to have infinitely many tries to guess our secret number.

Getting the player's input

We can get the player's guesses by using _, which will wait for the user to input something and return the input as text. After that, we can assign that value to another variable like so:

guess = _

We can also specify an input prompt like this:

guess = _("Your guess: ")

This will print Your guess: ‌ before waiting for user input.

Your code should now look something like this:

number = 100?\

? {
    guess = _("Your guess: ")
}

In the next chapter, we will compare the guess to the secret number and give the player some feedback on their guess!

Basic control flow

Now that we have both the secret number and the player's guess, we can compare the two and let the program decide what should happen next.

Here are the last two bullet points from the introduction:

  • A message will be printed that states whether the guess was too high or too low.
  • If the guess is equal to the secret number, a message appears telling the player that they won and the program will stop.

Conditional code with if expressions

To figure out whether the guess was too high or too low, we'll create an if expression with 2 branches. An if expression allows you to run a block of code only if a specific condition is met. In this case we want one branch to run only when the guess was too high, and the other one only when it's too low. malb8dge avoids words wherever possible, so the syntax looks quite different from what you're probably used to:

guess > number ? {

} ! guess < number ? {

}

As you may have noticed, the ? (which in this case stands for "if" as opposed to the infinite loop from earlier) comes after the specified condition. After that comes a block with the code we want to run when that condition is met. The ! after the block means "else", which is followed by another block with the code we want to run when the condition is not met. In the code example above, this else block is actually another if expression with a different condition, which is exactly how you chain if-else expressions in malb8dge.

Now that we have the basic structure, we can use the ; operator we learned about in chapter 1 to output a helpful message.

guess > number ? {
    ;"Too high!"
} ! guess < number ? {
    ;"Too low!"
}

Note: If you haven't already noticed, we are comparing a string (the input) to a number, which seems very odd. How will the comparison work if the input isn't a number? Instead of converting the string to a number, the number will be converted to a string, which isn't very useful. But if the player inputs an invalid guess, it will never be correct anyway. Instead, they might be a bit confused why hello is too high of a guess. But again, this is not the point of malb8dge. If you do care about these kinds of things, you're probably better off learning a language like Rust instead.

Breaking out of a loop

To solve the last bullet point, we will create another else block after the two existing branches. Inside this block, the player will be told that they have guessed the correct number and the program will be stopped. For that, we will use a break statement which will break out of the infinite loop, and since there is nothing after the loop, the program will end. The malb8dge equivalent of a break statement is %. After adding all of that, you should get this:

guess > number ? {
    ;"Too high!"
} ! guess < number ? {
    ;"Too low!"
} ! {
    ;"You guessed the number!"
    %
}

If we put these if expressions into our infinite loop and add a few finishing touches, our first llittle malb8dge project is finished!

;"Guess the number!"

number = 100?\

? {
    guess = _("Your guess: ")

    guess > number ? {
        ;"Too high!"
    } ! guess < number ? {
        ;"Too low!"
    } ! {
        ;"You guessed the number!"
        %
    }
}

Awesome! You have now learnt about some basic malb8dge syntax. In the next chapter, we will take a look at how we can compact the code that we've written in this chapter.

Compacting code

The main inspiration for creating malb8dge was code golf. Code golf is a competition where the goal is to write the shortest code that solves a specific problem. So that's exactly what we're going to do with our project from the last chapter!

Inlining everything

Let's take another look at our finished program:

;"Guess the number!"

number = 100?\

? {
    guess = _("Your guess: ")

    guess > number ? {
        ;"Too high!"
    } ! guess < number ? {
        ;"Too low!"
    } ! {
        ;"You guessed the number!"
        %
    }
}

We could easily remove almost half of the characters by deleting unnecessary spaces and newlines, but that would make the code pretty unreadable very fast - so we'll do that later. What we can do instead is trying to compact the parts inside of the curly brackets to single statements, so that we can remove the brackets entirely.

First, let's look at this part:

} ! {
    ;"You guessed the number!"
    %
}

malb8dge has a shortcut for exiting a program and also optionally printing a message: %%message. This means that we can replace the last block with a simple exit statement like so:

} ! {
    %%"You guessed the number!"
}

At the moment this doesn't look much shorter, but it will be once we remove the curly brackets!

The next thing we could do is compact everything that is inside of the loop into one statement. We can achieve this by inlining the guess variable, i.e. giving guess its value inside the if expression itself, since variable assignments in malb8dge also return the value that is being assigned. The code would look something like this:

(guess = _("Your guess: ")) > number ? {
    ;"Too high!"
} ! guess < number ? {
    ;"Too low!"
} ! {
    %%"You guessed the number!"
}

The brackets around the inline assignment are important, because otherwise guess would get the value of the entire if expression.

But of course, this can be shortened too. Using the anonymous global variable, we can even eliminate an entire variable name!

*_("Your guess: ") > number ? {
    ;"Too high!"
} ! & < number ? {
    ;"Too low!"
} ! {
    %%"You guessed the number!"
}

As you can see, the assignment has been replaced by a *, and the variable has turned into a &.

We cannot do the same thing to the number variable though, since we want the secret number to stay the same during the entire loop, so this is the best we can do!

Before we finally turn this program into an unreadable mess, we'll also look at how we can remove a few other repetitions, specifically the strings!

Looking for repetitions

Here's our progress so far:

;"Guess the number!"

number = 100?\

? {
    *_("Your guess: ") > number ? {
        ;"Too high!"
    } ! & < number ? {
        ;"Too low!"
    } ! {
        %%"You guessed the number!"
    }
}

As you might have noticed, our program now mostly consists of only text! We can immediately tell that the parts " the number!" and "Too " each appear twice. The simplest solution to removing the second " the number!" is to just assign it to a new variable using the method we saw in the previous chapter:

;"Guess" + (t = " the number!")

...

%%"You guessed" + t

This looks like quite a lot of extra symbols... But wait - the ; operator can actually print more than just a single value! By creating a list instead of adding the strings together, we can get the same outcome while also removing the brackets, as shown in this code block:

;"Guess", t = " the number!"

Note: Unfortunately, malb8dge only allows one value to be stored in the global variable at a time. This means that we cannot use the global variable again, since we've already used it to replace the variable that stores the player's input. You will have to get creative to find a way that will remove as many characters as possible using this method!

Great! Now let's move on to the next part. To eliminate the duplicate "Too ", we will actually use a different method. The last block that prints the winning message exits the game immediately, which means that all the other branches print "Too " plus another word. We can use this to print another list, with the first part being "Too " and the second one being the if expression:

;"Too ", *_("Your guess: ") > number ? {
    "high!"
} ! & < number ? {
    "low!"
} ! {
    ### if the program exits here, the outer print statement will not run
    %%"You guessed" + t
}

Note: The ### syntax starts a comment which continues until the end of the line. Everything inside a comment will not be treated as code! Comments can be used to help the reader understand what your code is doing, like in the block above.

There is one last shortcut that will be helpful in this chapter: the / operator. It works like the ; operator, but it will add spaces between the elements of the list we give it. Using this trick we can also remove the space character from "Too ":

/"Too", *_("Your guess: ") > number ? {
    "high!"
} ! & < number ? {
    "low!"
} ! {
    %%"You guessed" + t
}

That's about as far as we can go compacting the logic part. Here's a quick overview of what we've created:

;"Guess", t = " the number!"

number = 100?\

? {
    /"Too", *_("Your guess: ") > number ? {
        "high!"
    } ! & < number ? {
        "low!"
    } ! {
        %%"You guessed" + t
    }
}

Now comes the fun part - in the next chapter, we will turn this confusing mess of symbols into an even worse confusing mess of symbols by removing every single character that doesn't contribute to the program's function!

Removing all formatting

We're going to start by renaming the number variable to something shorter:

;"Guess", t = " the number!"

n = 100?\

? {
    /"Too", *_("Your guess: ") > n ? {
        "high!"
    } ! & < n ? {
        "low!"
    } ! {
        %%"You guessed" + t
    }
}

Then removing the curly brackets:

;"Guess", t = " the number!"

n = 100?\

? /"Too", *_("Your guess: ") > n ? "high!" ! & < n ? "low!" ! %%"You guessed" + t

Then the spaces:

;"Guess",t=" the number!"
n=1?\100
?/"Too",*_("Your guess: ")>n?"high!"!&<n?"low!"!%%"You guessed"+t

If we move all the statements into one line, there's another trick we can use. Because the goal is to remove as many characters as possible, malb8dge doesn't actually require you to separate statements with a special symbol like a semicolon. You will only have to add semicolons when it's not clear where the statement would end. For example, let's combine our first two statements: ;"Guess",t=" the number!"n=100?\. Since there is no comma between them, this would be invalid syntax - but malb8dge just ignores that and starts a new statement! Unfortunately we can't do that with the other two statements, because 100?\?... would be an if expression instead of an infinite loop, which means that we have to add a semicolon:

;"Guess",t=" the number!"n=100?\;?/"Too",*_("Your guess: ")>n?"high!"!&<n?"low!"!%%"You guessed"+t

Now there's one thing left that we can do! We can write %%"You guessed"+t as %%"You guessed{t}". This looks like we're adding an extra character - but at the end of a program, it is not necessary to close all strings and brackets! This means that we can omit the } and ", saving us another character:

;"Guess",t=" the number!"n=100?\;?/"Too",*_("Your guess: ")<n?"low!"!&>n?"high!"!%%"You guessed{t

Nice! Now our program only contains 97 characters!