<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nikolai</title>
    <description>The latest articles on DEV Community by Nikolai (@askepit).</description>
    <link>https://dev.to/askepit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1451161%2F89529989-6fce-490a-a598-a9327c6d87cd.jpg</url>
      <title>DEV Community: Nikolai</title>
      <link>https://dev.to/askepit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/askepit"/>
    <language>en</language>
    <item>
      <title>Git in conditions of extreme branch atomicity</title>
      <dc:creator>Nikolai</dc:creator>
      <pubDate>Mon, 13 May 2024 06:49:13 +0000</pubDate>
      <link>https://dev.to/askepit/git-in-conditions-of-extreme-branch-atomicity-23mp</link>
      <guid>https://dev.to/askepit/git-in-conditions-of-extreme-branch-atomicity-23mp</guid>
      <description>&lt;p&gt;How are your branches organized in Git? What do they look like, and what size are they? Below, I'll tell you how to restrict yourself within limits and then deal with the consequences using a nifty life hack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantage of Small Branches
&lt;/h2&gt;

&lt;p&gt;How are your Git branches organized? What do they look like, and what size are they?&lt;/p&gt;

&lt;p&gt;My branches strive to be as small and atomic as possible. This is in contrast to the approach where you start a branch for a specific feature, then include refactoring of the entire project within its scope. Along the way, you fix a persistent bug you’ve discovered. And then suddenly you end up with a branch whose name doesn't reflect what's actually done in it. You, yourself, can't even describe in one sentence what the branch is about. Testers struggle because it's unclear what to test, and reviewers are hesitant to look at your PR/MR since they don't want to descend into that hellish branch.&lt;/p&gt;

&lt;p&gt;I strictly maintain my branches to be small and laconic. Each branch performs a single specific task. Sometimes, I even split a branch into two or more when I realize it's starting to spread in different directions.&lt;/p&gt;

&lt;p&gt;For example, suppose you needed to write a subsystem for your project and a GUI for that subsystem. It's already clear that this will be two branches — one for the subsystem itself and one for the GUI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1p5zreqp9q07kuombs3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1p5zreqp9q07kuombs3.png" alt="Branches" width="642" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;master&lt;/code&gt; branch, &lt;code&gt;subsystem&lt;/code&gt; is branched, and &lt;code&gt;subsystem_ui&lt;/code&gt; is built on top of it.&lt;/p&gt;

&lt;p&gt;While writing &lt;code&gt;subsystem&lt;/code&gt;, you might have written a considerable number of core classes that aren't related to your subsystem but are general-purpose classes that could be useful to all programmers on the project. It's a good reason to split the branch in half and move these classes beyond the &lt;code&gt;subsystem&lt;/code&gt; scope:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kwveslusihnprg73qhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kwveslusihnprg73qhw.png" alt="Branches Split" width="421" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite a clear picture. However, some of you might already feel uneasy because a problem related to this approach is emerging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem with Small Branches
&lt;/h2&gt;

&lt;p&gt;It's not hard to see that with this approach, there might be situations where you just end up with long chains of dependent branches:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfjuf521r029nbp0cy2v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfjuf521r029nbp0cy2v.png" alt="Branches hell" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, this is a real case for me, especially during intense development periods at work. Testers are bombarded with emails, reviewers can't catch up with the pile, and your tree of branches just keeps growing.&lt;/p&gt;

&lt;p&gt;The key challenge in such a development mode is to ensure that all my depending-on-each-other branches remain up-to-date and to prevent them becoming old and full of conflicts with master/main. Your morning starts with coffee — my morning starts with merging master/main into the branches. Since master/main is continuously updated with significant changes from all colleagues, a few days of inactivity can result in a merge conflict nightmare, which tends to grow like a snowball.&lt;/p&gt;

&lt;p&gt;Moreover, in each branch in my tree, there's an equal chance that I might add something, fix something, or make adjustments. And all these changes must make their way into the branches depending on the modified one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Simplify Your Life
&lt;/h2&gt;

&lt;p&gt;I'm quite stubborn, but even for me, all the work of keeping branches in the proper state eventually became an annoying routine, consuming time and bringing no pleasure at all.&lt;/p&gt;

&lt;p&gt;Therefore, it's natural that, like a typical programmer, at some point, I got annoyed with the routine enough to pythonize a small automation that made my life a little more enjoyable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="c1"&gt;# CONFIG
&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mah_project&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;branches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inventory_mechanics&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ingame_market&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;remove_legacy_classes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;new_item_types_project_migration&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inventory_mechanics&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;configs_refactor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;new_item_types_project_migration&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inventory_mechanics&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;new_item_types&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;new_item_types_project_migration&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# CODE
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;UNSUCCESS. ABORT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;    

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;git fetch&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;way&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;way&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;way&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;dst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;way&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;git checkout &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;git pull&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;git merge origin/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;git push&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, the script works as follows: in the branches variable, you list all the paths you take from one branch to another during merges. Note that branches is an array of arrays. Since your branch web is, in general, a directed graph, you cannot traverse it with just one path. You’ll probably need several paths.&lt;/p&gt;

&lt;p&gt;The script simply goes through all your branches and merges the previous branch in the chain into each of them. For example, &lt;code&gt;master&lt;/code&gt; will merge into &lt;code&gt;inventory_mechanics&lt;/code&gt;, &lt;code&gt;inventory_mechanics&lt;/code&gt; will merge into &lt;code&gt;ingame_market&lt;/code&gt;, and so on. According to the merges, the same will happen for the other three chains, covering the entire branch graph.&lt;/p&gt;

&lt;p&gt;Yes, the script is simple and contains no magic. Yes, it will stop at the first merge conflict, which you still have to resolve yourself. Yes, after resolving another conflict, you need to restart the script. But how pleasant it is when all you need to do is run the following in the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;py chain_merge.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for a moment, engage in something more enjoyable or meaningful.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Utilizing git to make Rust development even sweatier</title>
      <dc:creator>Nikolai</dc:creator>
      <pubDate>Wed, 08 May 2024 12:12:54 +0000</pubDate>
      <link>https://dev.to/askepit/utilizing-git-to-make-rust-development-even-sweatier-2b67</link>
      <guid>https://dev.to/askepit/utilizing-git-to-make-rust-development-even-sweatier-2b67</guid>
      <description>&lt;p&gt;Rust was created to make programmers suffer, right? So why not make git collaborate with Rust and make it all even more hardcore?&lt;/p&gt;

&lt;p&gt;Actually, the article is more about git than Rust, so if you're not particularly familiar with Rust, don't hesitate — the narrative will be more about the development flow than the language itself. Rust was chosen for the article mainly for its convenient package manager &lt;code&gt;cargo&lt;/code&gt;, which makes the storytelling more laconic and illustrative.&lt;/p&gt;

&lt;h1&gt;
  
  
  You’ve got a task
&lt;/h1&gt;

&lt;p&gt;You and your team work on a project — a chess engine. You've got a task. There is a code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The essence of your task: the board in the engine is represented as a two-dimensional matrix. Cells on the board are addressed by coordinates &lt;code&gt;(row; col)&lt;/code&gt;, where &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;col&lt;/code&gt; are in the range &lt;code&gt;[0; 7]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You are asked to implement the &lt;code&gt;Address::parse()&lt;/code&gt; method. It should parse a human-readable string address of a chessboard cell, for example, &lt;code&gt;"e2"&lt;/code&gt;, and turn it into an &lt;code&gt;Address&lt;/code&gt; object that the engine can work with. For &lt;code&gt;"e2"&lt;/code&gt;, this should yield &lt;code&gt;(1, 4)&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Initial task implementation
&lt;/h1&gt;

&lt;p&gt;Okay, it seems like we need the &lt;code&gt;trait FromStr&lt;/code&gt; here since we want to create an object from a string. And &lt;code&gt;Address::parse()&lt;/code&gt; method will be a thin wrapper around the &lt;code&gt;from_str&lt;/code&gt;. Let's do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;FromStr&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;Err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'h'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'H'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'7'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That wasn't too difficult — a straightforward, understandable method. We make sure everything compiles with &lt;code&gt;cargo check&lt;/code&gt; command, then commit it to the repo.&lt;/p&gt;

&lt;p&gt;Later, we remember that we forgot about the &lt;code&gt;parse&lt;/code&gt; method. Okay, just call &lt;code&gt;from_str&lt;/code&gt; within it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, so good — commit, push and report that task is ready for QA.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Feedback
&lt;/h1&gt;

&lt;p&gt;IIn a very short period, we get bad feedback because "it doesn't even compile," and we're asked not to let this happen again. Huh, let's see what might be wrong. We did &lt;code&gt;cargo check&lt;/code&gt; previously and everything was fine. Let's do it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;E0308&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;mismatched&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;chess_address&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;     &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;                              &lt;span class="o"&gt;----&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;because&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;
&lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;         &lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;         &lt;span class="o"&gt;^^^^^^^^^^^^^^^^^^^^&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oops, we forgot to check &lt;code&gt;parse()&lt;/code&gt;, that was hastily written and pushed without any checks. Well, that's an annoying mistake: we rushed and forgot to call &lt;code&gt;unwrap()&lt;/code&gt;. We also neglected to recheck the build — just hurried to push our work ASAP. Let's do it right way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;cargo check&lt;/code&gt;, and this time the code compiles without errors. Great! Commit again and push, report that task is ready for QA.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Feedback II
&lt;/h1&gt;

&lt;p&gt;In a very short period, we get a scolding because &lt;code&gt;parse&lt;/code&gt; is not working correctly, and we are asked to fix it and cover our code with unit tests. Shame on me, my bad.&lt;/p&gt;

&lt;p&gt;In the best traditions of TDD, let's write tests and try to find out where we went wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;address_parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r_char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'h'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r_char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;addr_str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r_id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c_id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;check_neg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$addr:expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$addr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"f11"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"6e"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"f9"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"j5"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2789"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1f"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;check_neg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time to find that infamous bug, run &lt;code&gt;cargo test&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;assertion&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;right&lt;/code&gt; is what we expected, &lt;code&gt;left&lt;/code&gt; is what actually happened. &lt;code&gt;row&lt;/code&gt; for some reason is one more than it should be. Let's see how &lt;code&gt;row&lt;/code&gt; is calculated in the method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'7'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, OH SHI~ — we made a typo and started indexing chess rows from zero, even though in chess, columns start from number 1, and we messed up the indexing. Urgently making corrections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'8'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the build, &lt;code&gt;cargo build&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Process finished with exit code 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Process finished with exit code 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hooray! The bug is fixed, code compiles, and our reputation among colleagues is not as good as it was now.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Am I Doing Wrong?
&lt;/h1&gt;

&lt;p&gt;At this stage, we begin to understand that something needs to be changed in the workflow because our level of carelessness is high, but the desire to quickly push our stuff is high as well. Both factors slow down our work and the work of our colleagues.&lt;/p&gt;

&lt;p&gt;Automating the process and creating a clever script that can run &lt;code&gt;cargo check&lt;/code&gt;, &lt;code&gt;cargo test&lt;/code&gt;, and a couple more &lt;code&gt;cargo&lt;/code&gt; goodies just before committing could be a right solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  Left Hook
&lt;/h1&gt;

&lt;p&gt;I suppose it’s obvious that the narrative here strongly hints at using &lt;a href="https://git-scm.com/docs/githooks"&gt;git hooks&lt;/a&gt;, which simply won't allow committing non-working code if the hook is cooked right. From the variety of Git hooks, we choose the &lt;a href="https://git-scm.com/docs/githooks#_pre_commit"&gt;&lt;code&gt;pre-commit&lt;/code&gt;&lt;/a&gt; hook because we want to do all our checks &lt;em&gt;before committing&lt;/em&gt;. &lt;a href="https://git-scm.com/docs/githooks#_pre_push"&gt;&lt;code&gt;pre-push&lt;/code&gt;&lt;/a&gt; could work as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compilation and Tests
&lt;/h2&gt;

&lt;p&gt;Navigate to the &lt;code&gt;.git/hooks&lt;/code&gt; folder, create a file named &lt;code&gt;pre-commit&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

cargo check &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Surprisingly simple. After some experiments with intentional syntax and logic errors in the code, we find that it even works. The code simply refuses to commit if tests fail or if there are compilation errors. So, we achieved the minimum – no more shame and punishment from colleagues!&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting
&lt;/h2&gt;

&lt;p&gt;What else could we include in the hook? Well, &lt;code&gt;cargo fmt&lt;/code&gt; would be a good option – a command that formats your Rust code according to a unified style guide. Okay, add it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

cargo check &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;fmt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insert an extra space into the code and try committing this change to see what &lt;code&gt;cargo fmt&lt;/code&gt; does. Now, here's where things don't go as planned. Firstly, the commit with an extra space gets through. Secondly, Git shows that there are not staged changes; let's see what they are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;@@ -57,7 +57,13 @@&lt;/span&gt; mod tests {
                 let addr_str = format!("{}{}", c_char, r_char);
                 let addr = Address::parse(&amp;amp;addr_str);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-                assert_eq!(addr, Address { row: r_id as u8, col: c_id as u8 });
&lt;/span&gt;&lt;span class="gi"&gt;+                assert_eq!(
+                    addr,
+                    Address {
+                        row: r_id as u8,
+                        col: c_id as u8
+                    }
+                );
&lt;/span&gt;             }
         }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right, our code indeed needed some formatting according to &lt;code&gt;cargo fmt&lt;/code&gt;. Formatting is done, but it missed the commit, and that's a problem.&lt;/p&gt;

&lt;p&gt;Let's break down what we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cargo fmt&lt;/code&gt; (if the command is executed exactly in this form, without flags) never returns an error. It always runs successfully unless there's some severe internal inconsistency, which is unlikely to happen. Therefore, this command &lt;em&gt;cannot stop the commit&lt;/em&gt;; it will always go through.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cargo fmt&lt;/code&gt; makes changes to the code, and these changes, obviously, will be considered as not staged changes.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;pre-commit&lt;/code&gt; hook runs &lt;em&gt;before&lt;/em&gt; the commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Analyzing all these points, we conclude that we need to apply the changes made by &lt;code&gt;cargo fmt&lt;/code&gt; right away in the hook. What if we run &lt;code&gt;git add .&lt;/code&gt; right in the hook? Nothing stops us from trying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

cargo check &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;fmt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's roll back the mess we made with &lt;code&gt;git reset --hard HEAD~1&lt;/code&gt; and try the procedure again: insert an extra space somewhere in the code and attempt to commit it. Check what happened: &lt;code&gt;git status&lt;/code&gt; shows everything is clean, and the commit history shows our commit, whose diff looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;@@ -57,7 +57,13 @@&lt;/span&gt; mod tests {
                 let addr_str = format!("{}{}", c_char, r_char);
                 let addr = Address::parse(&amp;amp;addr_str);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-                assert_eq!(addr, Address { row: r_id as u8, col: c_id as u8 });
&lt;/span&gt;&lt;span class="gi"&gt;+                assert_eq!(
+                    addr,
+                    Address {
+                        row: r_id as u8,
+                        col: c_id as u8
+                    }
+                );
&lt;/span&gt;             }
         }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hooray! Our &lt;code&gt;git add .&lt;/code&gt; inside the hook worked, and we became even more invincible – our code will always be formatted, even if we don't follow the formatting rules during development. Isn't it a miracle?&lt;/p&gt;

&lt;h2&gt;
  
  
  Linter
&lt;/h2&gt;

&lt;p&gt;What other interesting &lt;code&gt;cargo&lt;/code&gt; utilities do we know that can make our code better and cleaner? &lt;code&gt;cargo clippy&lt;/code&gt; is a linter, a tool for static code analysis to identify and warn about suspicious or suboptimal code.&lt;/p&gt;

&lt;p&gt;Remembering the quirks of &lt;code&gt;cargo fmt&lt;/code&gt;, let's go to the &lt;a href="https://doc.rust-lang.org/stable/clippy/usage.html"&gt;&lt;code&gt;cargo clippy&lt;/code&gt; documentation&lt;/a&gt; right away to find out what pitfalls await us. We learn that in a typical situation, clippy returns exit code 0 (successful execution) even if it found and displayed warnings. This is not suitable for us – we'll see warnings on the screen, but our train will already leave, and the commit will be made despite the presence of warnings. We need to make clippy take warnings more seriously and return a failure, so the commit is rejected by the hook.&lt;/p&gt;

&lt;p&gt;In the documentation, we find an approach that suits us:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For &lt;a href="https://doc.rust-lang.org/stable/clippy/continuous_integration/index.html"&gt;CI&lt;/a&gt;, all warnings can be elevated to errors which will in turn fail the build and cause Clippy to exit with a code other than &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`cargo clippy -- -Dwarnings`
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, let's add this to our hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

cargo check &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;fmt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo clippy &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; warnings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try to commit something to our code. Will clippy even catch anything?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;casting&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;truncates&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;             &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'h'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;                                &lt;span class="o"&gt;^^^^^^^^^&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;instead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="sc"&gt;b'a'&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;further&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt; &lt;span class="nn"&gt;clippy&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;implied&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;

&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;casting&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;truncates&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;28&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;             &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'H'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;                                &lt;span class="o"&gt;^^^^^^^^^&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;instead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="sc"&gt;b'A'&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;further&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8&lt;/span&gt;

&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;casting&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;truncates&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;33&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;             &lt;span class="sc"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'8'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;                                &lt;span class="o"&gt;^^^^^^^^^&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt; &lt;span class="n"&gt;instead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="sc"&gt;b'1'&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
   &lt;span class="p"&gt;|&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;
   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;further&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, that's what I call a service – the linter showed us how to make the code not only correct but also a bit shorter. Now we can replace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'h'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'H'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;'8'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;b'a'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;b'h'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;b'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sc"&gt;b'A'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;b'H'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;b'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sc"&gt;b'1'&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="sc"&gt;b'8'&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;b'1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseAddressError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;With such a hook, we can hope that we won't get scolded, and overall, we'll have automated code quality checks with minimal chances of messing everything up. All that remains is to remember to honestly сover our code with unit tests.&lt;/p&gt;

&lt;p&gt;So, the final look of our hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

cargo check &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;fmt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo clippy &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; warnings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that the &lt;code&gt;pre-commit&lt;/code&gt; hook is &lt;em&gt;local&lt;/em&gt;. This means we don't need to worry about pushing it to the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Don't Code in Rust, I'm Here for the Idea
&lt;/h2&gt;

&lt;p&gt;For your stack, the hook, &lt;em&gt;in essence&lt;/em&gt;, will not fundamentally differ from what is written here. You just need to find a way to run your compiler, test utility, formatter, and linter through the hook script. Something might not be present, or perhaps an additional utility specific to your stack or pipeline might be added.&lt;/p&gt;

&lt;p&gt;I assume that your hook might look more complex, as not every language/framework has such a convenient package manager as &lt;code&gt;cargo&lt;/code&gt; (if it even has a package manager – hello, C++).&lt;/p&gt;

&lt;p&gt;You can write hooks not only in Bash but also in Python or, God forgive me, Perl. In that case, write &lt;code&gt;#!/usr/bin/env python&lt;/code&gt; or &lt;code&gt;#!/usr/bin/perl&lt;/code&gt; at the top of the hook. However, there might be problems with Python on Windows – you can read more about them in &lt;a href="https://habr.com/ru/companies/dins/articles/584562/"&gt;this Habr article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Code in Rust, Halp
&lt;/h2&gt;

&lt;p&gt;The hook described in the article can be organized through a utility specially made for this – &lt;a href="https://github.com/swellaby/rusty-hook"&gt;&lt;code&gt;rusty-hook&lt;/code&gt;&lt;/a&gt;. All you need to do is create a &lt;code&gt;.rusty-hook.toml&lt;/code&gt; file in the root of the project with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[hooks]&lt;/span&gt;
&lt;span class="py"&gt;pre-commit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"cargo check &amp;amp;&amp;amp; cargo test &amp;amp;&amp;amp; cargo fmt &amp;amp;&amp;amp; git add . &amp;amp;&amp;amp; cargo clippy -- -D warnings"&lt;/span&gt;

&lt;span class="nn"&gt;[logging]&lt;/span&gt;
&lt;span class="py"&gt;verbose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't know the subtleties of the utility, and whether it's worth using it – whether it has any advantages or disadvantages over idiomatic creation of git hooks is up to you to decide.&lt;/p&gt;

</description>
      <category>git</category>
      <category>rust</category>
    </item>
    <item>
      <title>What we lack in C++</title>
      <dc:creator>Nikolai</dc:creator>
      <pubDate>Fri, 03 May 2024 12:29:18 +0000</pubDate>
      <link>https://dev.to/askepit/what-we-lack-in-c-1704</link>
      <guid>https://dev.to/askepit/what-we-lack-in-c-1704</guid>
      <description>&lt;p&gt;C++ has been evolving rapidly for the past decade and more. Nevertheless, in our codebases, there are still numerous helper files and classes that aim to fill the gaps in the language's standard library. How did we end up with these helper files, and when will this ever end?&lt;/p&gt;

&lt;h2&gt;
  
  
  Features that do not exist
&lt;/h2&gt;

&lt;p&gt;For over a decade, I've been professionally involved in C++ development. I entered the field in 2013, just when the C++ standardization committee got into gear and adopted the three-year release cycle for updated language standards. C++11 had already been released, introducing plenty of attractive innovations that significantly refreshed the language. However, not everyone had the luxury of using all these new features in their working code, and we had to stick to the dull C++03, longing for the new standard.&lt;/p&gt;

&lt;p&gt;Despite the diversity of new features introduced into the language, I observed the same recurring pattern from project to project: helper files, helper containers implementing the same things, filling the voids in the STL. I'm not even talking about niched structures and algorithms – more about things that are essential for comfortably developing software in C++. I observe how different companies on various projects construct the same makeshift solutions just because they are natural and in demand. And STL has nothing to offer.&lt;/p&gt;

&lt;p&gt;In this article, I wanted to gather the most prominent examples of what I've seen and used in development. However, in the process of collecting all the absent features in C++, I unexpectedly discovered that some of them had been already covered by the new language standards, either fully or partially. Therefore, this article is more of a reflection and complains about what was missing for a long time but eventually made its way into the language, and what still remains absent in the standard. The article doesn't pretend to be anything pretentious; rather, it's just a chat about everyday C++.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: In this article, I may interchange concepts such as C++, STL, language, language standard, etc., as in the context of the article, it's not crucial, and the discussion revolves around "all of that stuff."&lt;/p&gt;

&lt;h2&gt;
  
  
  What was missing for a long time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;std::string::starts_with&lt;/code&gt;, &lt;code&gt;std::string::ends_with&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The phantom pain of every other C++ enthusiast. We had been waiting for these things for so long, and they took their sweet time getting to us. I bet you've seen something similar in the hidden corners of your project's codebase:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;These methods were introduced into the language only with C++20, which is still not accessible to everyone. But the fortunate ones can finally find the prefix and the suffix of a string. Both, in fact:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c++20"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;res1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c++"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;res2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;starts_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c#"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;res3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;res4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"27"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// false&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;std::optional&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;“This class has been in the language for ages now, grandpa, take your pills!" – you might say and you would be partially right because &lt;code&gt;std::optional&lt;/code&gt; has been with us since the C++17 standard, and everyone has become quite attached to it. However, here is more of my personal pain: in the early years of my career, I worked on a project with a C++03 restriction and used a custom &lt;code&gt;optional&lt;/code&gt; created by my colleague.&lt;/p&gt;

&lt;p&gt;Reading the code that implemented this custom &lt;code&gt;optional&lt;/code&gt; class was kinda thrilling for me. I was a junior back then, and it left an impression on me. Surely, everything there was quite simple and straightforward, but the emotions were as if I were reading STL source code itself.&lt;/p&gt;

&lt;p&gt;I'm glad that now I can confidently write something like this on almost any project:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"No result!"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;std::expected&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you're familiar with Rust, you know that the &lt;a href="https://doc.rust-lang.org/std/option/enum.Option.html" rel="noopener noreferrer"&gt;&lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt; class has a best companion — the &lt;a href="https://doc.rust-lang.org/std/result/enum.Result.html#" rel="noopener noreferrer"&gt;&lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;&lt;/a&gt; class. They are closely related, and each has a bunch of methods that convert one into the other.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt; is equivalent to &lt;code&gt;optional&amp;lt;T&amp;gt;&lt;/code&gt; in C++, &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; needs some clarification. It's somewhat like &lt;code&gt;optional&amp;lt;T&amp;gt;&lt;/code&gt;, but the absence of a result is interpreted as an error of type &lt;code&gt;E&lt;/code&gt;. That is, an object of the &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; class can be in two states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ok state: The object contains a valid value of type &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Error state: The object holds an error of type &lt;code&gt;E&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can ask the object in which state it is and retrieve its content: either a value or an error.&lt;/p&gt;

&lt;p&gt;For a C++ programmer, this class might seem exotic, but in Rust, it holds great significance since the language lacks exceptions, and handling exceptional situations is made through returning error codes. In 99% of cases, this is done by returning a &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, during my time with C++, I exclusively participated in projects where exceptions were forbidden for various reasons. In this context, C++ becomes similar to Rust in terms of error handling.&lt;/p&gt;

&lt;p&gt;I envied Rust for having such a nifty thing in a language library. C++ deserved a similar weapon. And yes, I wrote an equivalent of &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; for C++. The class had the dubious name &lt;code&gt;Maybe&amp;lt;T, E&amp;gt;&lt;/code&gt;, which could mislead a Haskell programmer (in Haskell, &lt;code&gt;Maybe&lt;/code&gt; is analogous to &lt;code&gt;optional&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But recently, I discovered that the C++ Standardization Committee has approved the &lt;a href="https://en.cppreference.com/w/cpp/utility/expected" rel="noopener noreferrer"&gt;&lt;code&gt;std::expected&amp;lt;T, E&amp;gt;&lt;/code&gt;&lt;/a&gt; class in the C++23 standard. MSVC has even &lt;a href="https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170" rel="noopener noreferrer"&gt;implemented it&lt;/a&gt; in VS 2022 17.3, and it is available under the &lt;a href="https://learn.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version?view=msvc-170" rel="noopener noreferrer"&gt;&lt;code&gt;/std:c++latest&lt;/code&gt;&lt;/a&gt; compiler option. The name is even better than Result or Maybe, in my opinion.&lt;/p&gt;

&lt;p&gt;To appreciate the class in action, let's look at code that parses a human-readable chess address into coordinates that are easier to manage within a chess engine. For example, for &lt;code&gt;"a3"&lt;/code&gt; it should yield coordinates &lt;code&gt;[2; 0]&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ChessPosition&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// stored as [0; 7], represents [1; 8]&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// stored as [0; 7], represents [a; h]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParseError&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;InvalidAddressLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvalidRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvalidColumn&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="nf"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChessPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParseError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unexpected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseError&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;InvalidAddressLength&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unexpected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseError&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;InvalidColumn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unexpected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseError&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;InvalidRow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChessPosition&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"e2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// [1; 4]&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"e4"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// [3; 4]&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"g9"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// InvalidRow&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x3"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// InvalidColumn&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;res5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseChessPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"e25"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// InvalidAddressLength&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;std::bit_cast&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is something I have had a sick relationship with. I don't know why, but there were times when I needed to do some strange things like obtaining the bitwise representation of a &lt;code&gt;float&lt;/code&gt; number. Of course, in my junior days, I used to not be afraid of UB (Undefined Behavior) and used anything that just seemed to work, at least here and for now. So, what options do we have for performing not really safe casting from one type to another?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;reinterpret_cast&lt;/code&gt;, where would we be without it? It's so simple and tempting to write:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

  &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and not worry about anything. But it's UB;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Back to basics — C-style cast. It's the same as &lt;code&gt;reinterpret_cast&lt;/code&gt;, but even simpler to write:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

  &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the &lt;a href="https://en.wikipedia.org/wiki/Fast_inverse_square_root" rel="noopener noreferrer"&gt;developers of Quake III weren't afraid&lt;/a&gt;, why should we be? But... &lt;strong&gt;it's UB&lt;/strong&gt;;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The trick with &lt;code&gt;union&lt;/code&gt;:
```cpp
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;union {&lt;br&gt;
      float f;&lt;br&gt;
      uint32_t i;&lt;br&gt;
  } value32;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  The code itself is not UB, but the problem is that reading from a union field into which you haven't written anything before is also UB.

Nevertheless, I observed all these approaches in various types of deviations:

- Attempting to determine the sign of a `float` number by reading its most significant bit.
- Transforming a pointer into a number and back — hello embedded systems. I even saw an exotic case where an address was transformed into an ID.
- Mathematical tricks with the exponent or mantissa of a `float`.

"Why would anyone need the mantissa?" you ask? And I would answer: behold my ancient [GitHub project](https://github.com/AskePit/IEEE754Converter), where I’ve created a small IEEE 754 converter, just for fun. I did it a long time ago for self-educational purposes, and I also wanted to steal the design of the standard Windows 7 calculator and see how well I could replicate it :)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k3170abf7ocf963lr0sv.png)

Well, bitwise tricks sometimes become necessary for someone, somewhere.

The question is, how to trick your tricks safely? When I searched for the truth on StackOverflow, the answer was harsh but the only: "use `memcpy`." From same good old StackOverflow I stole a small snippet to use `memcpy` conveniently:

```cpp


template &amp;lt;class OUT, class IN&amp;gt;
inline OUT bit_cast(IN const&amp;amp; in)
{
    static_assert(sizeof(OUT) == sizeof(IN), "source and dest must be the same size");
    static_assert(std::is_trivially_copyable&amp;lt;OUT&amp;gt;::value, "destination type must be trivially copyable.");
    static_assert(std::is_trivially_copyable&amp;lt;IN&amp;gt;::value, "source type must be trivially copyable");

    OUT out;
    memcpy(&amp;amp;out, &amp;amp;in, sizeof(out));
    return out;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In C++20, they introduced &lt;a href="https://en.cppreference.com/w/cpp/numeric/bit_cast" rel="noopener noreferrer"&gt;&lt;code&gt;std::bit_cast&lt;/code&gt;&lt;/a&gt;, which does the same thing except that it's also &lt;code&gt;constexpr&lt;/code&gt; thanks to the magic that the standard obliged compilers to implement.&lt;/p&gt;

&lt;p&gt;Now we can touch the beautiful and make it not only beautiful but also correct from the language specification point of view:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nf"&gt;q_rsqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;threehalfs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bit_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;              &lt;span class="c1"&gt;// evil floating point bit-level hacking&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x5f3759df&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;               &lt;span class="c1"&gt;// what the heck?&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bit_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threehalfs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// 1st iteration&lt;/span&gt;
    &lt;span class="c1"&gt;// y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You're welcome, id Software.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's missing and may never be acquired at all
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Floating-Point Mathematics
&lt;/h3&gt;

&lt;p&gt;We all know that you can't just take two &lt;code&gt;float&lt;/code&gt; numbers and check if they are equal. &lt;code&gt;1.0&lt;/code&gt; and &lt;code&gt;0.999999999&lt;/code&gt; won't be equal to each other, even if they seem convincingly equal to you. There are no standard methods to solve this problem adequately in C++ — you have to manually compare the absolute difference of the numbers with some epsilon.&lt;/p&gt;

&lt;p&gt;Another thing that we can sometimes desire is rounding a number to a certain number of digits. We have &lt;code&gt;floor&lt;/code&gt;, &lt;code&gt;ceil&lt;/code&gt;, &lt;code&gt;round&lt;/code&gt;, but they all round to an integer. Therefore, you have to go to StackOverflow and take some ready-made solutions.&lt;/p&gt;

&lt;p&gt;In the end, your codebase is extended with helpers like these:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;almostEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;numeric_limits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;epsilon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;nearToZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;numeric_limits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;epsilon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;roundTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;digitsAfterPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;delim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;digitsAfterPoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;delim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;delim&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What else can be said — it’s not critical, but a bit sad.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;EnumArray&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Consider you have an enumeration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Grams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Meters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Liters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Items&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is a common scenario where you need a dictionary with an enum key, storing configuration or information about each enumeration element. I encounter such cases frequently in my work. The straightforward solution can be easily implemented using standard STL containers:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;unitNames&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Grams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"g"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Meters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"m"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Liters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"l"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pcs"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What can we note about this piece of code?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;std::unordered_map&lt;/code&gt;  is not the most trivial container. And it's not the most memory-efficient&lt;/li&gt;
&lt;li&gt;Dictionaries or configs like this can be quite common in a project, and in the vast majority of cases, they will be small in size. The average number of elements in an enumeration rarely exceeds a few dozen, and most often it's just a few. Hash tables such as &lt;code&gt;std::unordered_map&lt;/code&gt; or trees such as &lt;code&gt;std::map&lt;/code&gt; start to look like overkill;&lt;/li&gt;
&lt;li&gt;An enumeration is, essentially, a number. It is very tempting to consider it as a numeric index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This last point quickly leads us to the idea that we could create a container that interfaces like a dictionary but under the hood is a &lt;code&gt;std::array&lt;/code&gt;. A proxy-container. The indices of the array are the elements of our enumeration, and the array's data are the values of the "map".&lt;/p&gt;

&lt;p&gt;All that remains is to figure out how the array will know its size — i.e., how to count the number of elements in the enumeration. The simplest old-school method is to add a special element, Count, to the end of the enumeration. Let's stick with this method, as it's not particularly exotic—I often see it in codebases—so it's kinda ok to use it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Grams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Meters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Liters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="n"&gt;Count&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The implementation of the proxy-container itself is quite simple:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnumArray&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;EnumArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;initializer_list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_underlying&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The constructor with &lt;code&gt;std::initializer_list&lt;/code&gt; is necessary to allow constructing our config in the same way we formed &lt;code&gt;std::unordered_map&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;EnumArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;unitNames&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Grams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"g"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Meters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"m"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Liters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"l"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pcs"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;unitNames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Outputs "pcs"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The beauty of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use all the benefits of both &lt;code&gt;std::array&lt;/code&gt; and &lt;code&gt;std::unordered_map&lt;/code&gt;. The convenience of a dictionary interface combined with the speed and simplicity (in a good sense) of an array under the hood;&lt;/li&gt;
&lt;li&gt;Cache-friendly—data is stored sequentially in memory, in contrast to &lt;code&gt;std::unordered_map&lt;/code&gt; and &lt;code&gt;std::map&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;The size of the array is known at compile-time, and if we improve the container further, almost all its methods can be made &lt;code&gt;constexpr&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Limitations of this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mandatory &lt;code&gt;Count&lt;/code&gt; in the enumeration;&lt;/li&gt;
&lt;li&gt;The enumeration cannot have custom-typed values like:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

  &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;518&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;D&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Only the default order starting from zero;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory is allocated for &lt;em&gt;all elements&lt;/em&gt; of the enumeration in the array. If you fill the &lt;code&gt;EnumArray&lt;/code&gt; with only some values, the rest will contain default-constructed objects;&lt;/li&gt;
&lt;li&gt;Another limitation—type &lt;code&gt;T&lt;/code&gt; must be default-constructed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm usually okay with such limitations, so I typically use this container without any issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Early Return
&lt;/h3&gt;

&lt;p&gt;Let's take a look at a typical function with some boundary checks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;applySpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Spell&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"No spell"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Invalid spell"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isImmuneToSpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Immune to spell"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Spell already applied"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;applyEffects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getEffects&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Spell applied"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Is it familiar to you? Poor three lines at the bottom – that's the actual work of the method. The rest – checks to see if the work can be performed. It's a bit annoying. Especially if you're a fan of the Allman style, and your every curly brace loves to be alone.&lt;/p&gt;

&lt;p&gt;It would be nice to make it cleaner, without all that boilerplate. C++ has &lt;code&gt;assert&lt;/code&gt;, for example, which is kinda similar to what we're doing here – a check is performed on a certain condition, and if necessary, some measures are taken under the hood. Admittedly, &lt;code&gt;assert&lt;/code&gt; is simpler – it doesn't need to return anything. But nevertheless, we could construct something similar:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="cp"&gt;#define early_return(cond, ret)      \
    do {                             \
        if (static_cast&amp;lt;bool&amp;gt;(cond)) \
        {                            \
            return ret;              \
        }                            \
    } while (0)
&lt;/span&gt;
&lt;span class="cp"&gt;#define early_return_void(cond)      \
    do {                             \
        if (static_cast&amp;lt;bool&amp;gt;(cond)) \
        {                            \
            return;                  \
        }                            \
    } while (0)
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;FFFUUU, macros! Bjorn Stroustrup doesn't like macros. If he sends me a direct message asking for an apology, I'll understand, and I'll apologize. I'm not a big fan of C++ macros either.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nmrnx2ig800m6t2l1e7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nmrnx2ig800m6t2l1e7.png" alt="Bjarne Stroustrup really hates preprocessor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But yep, there are macros in the proposed code, even two. Actually, we can reduce them to one by using a variadic macro:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="cp"&gt;#define early_return(cond, ...)      \
    do {                             \
        if (static_cast&amp;lt;bool&amp;gt;(cond)) \
        {                            \
            return __VA_ARGS__;      \
        }                            \
    } while (0)
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There's only one macro left, but it's still a macro. And nope, the miracle will hardly happen: it can't be turned into a non-macro – as soon as we try to move it into a function, we lose the ability to influence the control flow of our current function. It's a pity, but that's the reality. But just look how we can rewrite our original example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;applySpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Spell&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"No spell"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Invalid spell"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isImmuneToSpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Immune to spell"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Spell already applied"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;applyEffects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getEffects&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Spell applied"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will work even if the function returns &lt;code&gt;void&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;applySpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Spell&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isImmuneToSpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;early_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;applyEffects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getEffects&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It's shorter, and I think it's generally better. If this feature were supported by the standard, it could be a language construct rather than a macro. Although, for the sake of justice and fun, I'll say that the C++ &lt;a href="https://en.cppreference.com/w/cpp/error/assert" rel="noopener noreferrer"&gt;&lt;code&gt;assert&lt;/code&gt;&lt;/a&gt; is also a macro.&lt;/p&gt;

&lt;p&gt;If you prefer the logical behavior of the &lt;code&gt;assert&lt;/code&gt; more – &lt;em&gt;assert the expected, trigger error otherwise&lt;/em&gt; – then we can simply invert the entire logic and name the macro according to the new behavior:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="cp"&gt;#define ensure_or_return(cond, ...)   \
    do {                              \
        if (!static_cast&amp;lt;bool&amp;gt;(cond)) \
        {                             \
            return __VA_ARGS__;       \
        }                             \
    } while (0)
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;applySpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Spell&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ensure_or_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ensure_or_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;ensure_or_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isImmuneToSpell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;ensure_or_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;appliedSpells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;applyEffects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getEffects&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The naming is probably bad, but you get the idea. And I would be satisfied to see either of these constructs in C++.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unordered Erase
&lt;/h3&gt;

&lt;p&gt;I suppose the most commonly used collection in C++ is &lt;code&gt;vector&lt;/code&gt;. And we all remember well that a vector is good at everything except inserting and deleting in the middle of the collection. This takes O(n) time, so every time I have to delete something from the middle of the vector, I feel a bit sad because the vector has to shift half of its content to the left.&lt;/p&gt;

&lt;p&gt;There is an idiomatic technique that can turn O(n) into O(1) at the cost of elements’ order violation. And if you are willing to pay this price, it is definitely more advantageous to use this simple trick:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1084&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// remove the number 1 from the vector&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; 
&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// get [17, -2, 1084, -11, 17, 40]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Whoa, what was that? First, we swapped the last element of the vector with the one marked for deletion, and then simply discarded the tail element from the vector. Both operations are ridiculously cheap. Simple and nice.&lt;/p&gt;

&lt;p&gt;It is not clear for me why the vector interface does not provide such a simple alternative to the regular erase method. &lt;a href="https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove" rel="noopener noreferrer"&gt;It exists&lt;/a&gt; in Rust, for instance.&lt;/p&gt;

&lt;p&gt;So, for now we should live with another helper function in our codebase:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;unorderedErase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Half of the article was nullified by C++ itself in the process of writing it because modern C++20 and C++23 standards covered about half of the desires described in this complaint book. And all in all, a wishlist from language users will never run out because as many people, as many wishes, and you can't fit them all into the standard library or the language itself.&lt;/p&gt;

&lt;p&gt;I tried to mention only those points that, in my humble opinion, seem to be less subjective and would be worthy of inclusion in the language standard. At least in my work, these features are more or less in demand on a daily basis. You may rightly have a different opinion on my list, and I, in turn, would be happy to read in the comments about your pain and the features you didn't get, to understand how language users would like to see the future of C++.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>stl</category>
    </item>
    <item>
      <title>Voronoi, Manhattan, random</title>
      <dc:creator>Nikolai</dc:creator>
      <pubDate>Fri, 26 Apr 2024 18:06:59 +0000</pubDate>
      <link>https://dev.to/askepit/voronoi-manhattan-random-2lkn</link>
      <guid>https://dev.to/askepit/voronoi-manhattan-random-2lkn</guid>
      <description>&lt;p&gt;This is a story about how to never quite finish a project, yet gain a ton of experience and have no regrets.&lt;/p&gt;

&lt;p&gt;So, we had one programmer, one artist, an absolute lack of understanding of the workflow, an unfamiliar game engine, and a desire to create something. If you're curious about the mixup of Voronoi diagrams, a special case of Minkowski distance, polygon transformations, procedural generation, and noise—all wrapped up in a beautifully stylized package—this is the right place for you to read.&lt;/p&gt;

&lt;p&gt;Caution: A plenty of images ahead!&lt;/p&gt;

&lt;h1&gt;
  
  
  How It All Began
&lt;/h1&gt;

&lt;p&gt;I am a C++ developer in a small game development studio. I have a friend, Ilya. He's an artist, illustrator, and designer with his cozy graphic design studio.&lt;/p&gt;

&lt;p&gt;At some point, Ilya knocked on my door and mentioned having a pool of artworks, sketches, and concepts that could be put to good use in a 2D indie game, and if I were interested, we could collaborate in our free time to create something interesting.&lt;/p&gt;

&lt;p&gt;I thought it was not a bad idea and accepted the proposal.&lt;/p&gt;

&lt;h1&gt;
  
  
  Artistic Style
&lt;/h1&gt;

&lt;p&gt;We decided that the essence of the game and its lore would be extracted from the visual content we chose as the basis for the game. After digging into Ilya's concepts, we selected this art style and game world:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Flv%2Fld%2Fbe%2Flvldbedobqesqnq_noyjqildnco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Flv%2Fld%2Fbe%2Flvldbedobqesqnq_noyjqildnco.png" alt="Concept Art"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More about the concept can be found in &lt;a href="https://www.ilyaboyko.com/work/rift-in-the-empire-2" rel="noopener noreferrer"&gt;this retrospective article&lt;/a&gt; by Ilya.&lt;/p&gt;

&lt;p&gt;We decided to start with a small prototype level, just to see how it turns out. The requirements for the level were minimal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flat level, side view, the main character moves from left to right.&lt;/li&gt;
&lt;li&gt;Several background layers creating a &lt;a href="https://en.wikipedia.org/wiki/Parallax" rel="noopener noreferrer"&gt;parallax effect&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Basic movement of the main character: walking, running, jumping, idle animation.&lt;/li&gt;
&lt;li&gt;Several platforms to jump onto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tasks were set, the goal was clear, but we still hadn't chosen a game engine.&lt;/p&gt;

&lt;h1&gt;
  
  
  In Search of a Game Engine
&lt;/h1&gt;

&lt;p&gt;For the project, I wanted to choose a simple 2D game engine that could handle complex tasks if needed. I wanted to be able to achieve the desired result without much hassle. This required the engine to have a simple scripting language which I could use for an easy gameplay features implementation without much difficulty. The presence of an editor was a strict requirement.&lt;/p&gt;

&lt;p&gt;On the other hand, I wanted the engine, if I liked it, to be usable for future projects. The next project's requirements and the need for any serious computations were unknown. Therefore, the engine needed to allow writing part of the functionality in a mature compiled language like C++ or Rust if necessary.&lt;/p&gt;

&lt;p&gt;Engines considered and rejected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.unrealengine.com/en-US" rel="noopener noreferrer"&gt;Unreal Engine&lt;/a&gt;. I'm familiar with Unreal, but it felt like crushing a fly with a steam-roller for our tasks. Also, UE4 is massive in size, and UE5 size is over &lt;del&gt;9000!&lt;/del&gt; a hundred gigabytes. I really didn't want to resort to it, although it was my backup option.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://unity.com/" rel="noopener noreferrer"&gt;Unity&lt;/a&gt;. Can't say much. It's the most popular choice for 2D game development. But somehow, my heart wasn't in writing in C#. Also, for some entirely subjective reason, I had a skeptical attitude towards the engine.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bevyengine.org/" rel="noopener noreferrer"&gt;Bevy&lt;/a&gt;. A very young engine where you need to write the game entirely in Rust—that was appealing. But fatal flaws overshadowed everything: no editor, the engine brutally enforces the ECS approach, and the game's architecture must literally bend to fit this paradigm. So, you won't migrate to another engine at all—you just throw away all the code and start from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By process of elimination, the dark horse of the game engine world was chosen—Godot. Yes, the same one that many Unity developers rushed to port to, angered by Unity's new pricing policy. I, however, started Godot exploration a year and a half before these events, so I wasn’t affected by that sudden hype. I even experienced a mini-migration from version 3 to 4, which happened to be almost seamless for me.&lt;/p&gt;

&lt;p&gt;I can say right away that I haven't been disappointed with the choice, and the engine has never let me down. What can I say about Godot over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has its own scripting language, &lt;a href="https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html" rel="noopener noreferrer"&gt;GDScript&lt;/a&gt;, similar to Python. It's simple and convenient.&lt;/li&gt;
&lt;li&gt;As an alternative, you can code in C++ or C#. If desired, Godot has bindings for other languages, such as &lt;a href="https://github.com/godot-rust/gdext" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;. Going ahead—in the end, C++ came in handy and useful for the project.&lt;/li&gt;
&lt;li&gt;Godot is a simplicity itself. You literally take it and do it. No long documentation readings, no fuss. After the first basic &lt;a href="https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;, you just pick it up—and create the stuff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can I say something bad about Godot? Its logo is just awful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fu-%2Fot%2F9z%2Fu-ot9zns-1gkrhuucdnklw2mabg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fu-%2Fot%2F9z%2Fu-ot9zns-1gkrhuucdnklw2mabg.png" alt="Godot Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Prototype Level
&lt;/h1&gt;

&lt;p&gt;Since it has already been mentioned that development in Godot poses no difficulties, it's no surprise that a prototype level was implemented in a short time. It looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fl2%2Fli%2Frk%2Fl2lirk2ijrstjsg3z7mnzf_wvma.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fl2%2Fli%2Frk%2Fl2lirk2ijrstjsg3z7mnzf_wvma.jpeg" alt="Prototype Level"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entire level is quite long in size, so it’s difficult to show it in one picture, but here's a screenshot from the engine for you to assess:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fm2%2Fl2%2F2t%2Fm2l22t0vfwzmkhqpk_nulo7vyn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fm2%2Fl2%2F2t%2Fm2l22t0vfwzmkhqpk_nulo7vyn8.png" alt="Level Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The character could move through the level. There were platforms with collisions, swiftly moving parallax with five or six layers, and clouds drifted across the sky. All in all, it took me a couple of days—definitely less time than Ilya needed to draw all the content for the level.&lt;/p&gt;

&lt;p&gt;In general, we realized that we could more or less continue working in this vein. We started discussing where to go next and fleshing out the essence of the game. It was a long, agonizing process because neither of us was a game designer, and extracting gameplay mechanics, story, hero motivation, lore, etc., was a struggle.&lt;/p&gt;

&lt;p&gt;Eventually, during one of our meetings, Ilya uttered game-changing words: "Listen, I've been thinking, a side-scrolling platformer is somewhat dull—not much room for imagination and all. Let's create some randomly generated world with biomes, like in my favorite &lt;a href="https://store.steampowered.com/app/219740/Dont_Starve/" rel="noopener noreferrer"&gt;Don't Starve&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;This is where I’ve got a butt-squeezing tense because I quite understood how challenging it could be. I expressed all my concerns about the unpredictability of randomness to Ilya, the difficulty of dealing with it, and how the project would become significantly more complex. But Ilya replied, "Let's give it a try." I thought, why not, and agreed. And so, we began experiments.&lt;/p&gt;

&lt;h1&gt;
  
  
  How on Earth do I Generate Biomes?
&lt;/h1&gt;

&lt;p&gt;My exploration into how to generate random maps and biomes began with the fantastic article &lt;a href="http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/" rel="noopener noreferrer"&gt;Polygonal Map Generation for Games&lt;/a&gt; by Amit Patel, written in 2010, which has probably become a living classic. I've seen various people refer to it multiple times when facing a similar task. In fact, it’s not just an article; it's a whole conglomerate of articles by one author, gradually revealing all aspects of his work on this topic. The article is essentially about how to generate islands with biomes, rivers, roads, and make it look convincing and realistic. For example, here's a completely randomly generated and procedurally drawn island:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Frt%2F0a%2Fi7%2Frt0ai74mxs89l87vxh5hx9vxhs8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Frt%2F0a%2Fi7%2Frt0ai74mxs89l87vxh5hx9vxhs8.jpeg" alt="Randomly Generated Island"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was an excellent read; I still remember every bit of that article. I even made notes and summaries of it in my Obsidian, that's how much this work impressed me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F_m%2Fkx%2Fen%2F_mkxent-4r0zivo99usbbucgr70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F_m%2Fkx%2Fen%2F_mkxent-4r0zivo99usbbucgr70.png" alt="Obsidian Notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The article is so comprehensive that for our project, only the most basic ideas were sufficient, just the initial steps of the algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating random points on a 2D plane&lt;/li&gt;
&lt;li&gt;Constructing a Voronoi map based on these points&lt;/li&gt;
&lt;li&gt;Assigning a biome type to each cell of the Voronoi map&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else was too specialized, aiming to generate an image entirely procedurally without the need for an artist. What we needed was a simple biome stylization, where the artist would draw each biome’s textures, and we would simply apply them to the Voronoi map polygons. So, the article served mainly as an inspiring, motivational guide, giving a rough direction to follow, rather than a step-by-step guide of success.&lt;/p&gt;

&lt;p&gt;Additionally, I read about how Don't Starve developers generated their game’s world—I found an &lt;a href="https://dontstarve.fandom.com/wiki/World_Generation" rel="noopener noreferrer"&gt;article&lt;/a&gt; on the fandom-wiki for the game. It also mentioned that the starting point for their generation was a Voronoi map.&lt;/p&gt;

&lt;h1&gt;
  
  
  Voronoi Diagram
&lt;/h1&gt;

&lt;p&gt;I had heard about the concept of the Voronoi diagram, knowing that it divides a 2D space into regions. My knowledge ended there, so I went to &lt;a href="https://en.wikipedia.org/wiki/Voronoi_diagram" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt; to learn more. In short, the diagram looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3-%2Fuw%2Fig%2F3-uwig5opzdhzbhtizrih5trr3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3-%2Fuw%2Fig%2F3-uwig5opzdhzbhtizrih5trr3o.png" alt="Voronoi Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a 2D space divided into regions, and each region has a site inside it. The unique property of this diagram is that if you point to any location on this map, the region you end up in will be the one with the closest site to you among all the sites on the map. In other words, if you imagine the Voronoi diagram as a giant park and the site as public toilets, being in the red polygon means you’d better run to the toilet that belongs to that polygon—other WCs are guaranteed to be farther away. If you find yourself on the boundary of polygons, toss a coin and run to any of the toilets in the neighboring regions—distances to both toilets along the boundary are the same. If you are at the corner of a region, it's more challenging—you are equidistant to three or even four toilets at once.&lt;/p&gt;

&lt;p&gt;Well, you get the idea. The Voronoi diagram is often used in cartography and other applied algorithms where finding the nearest object on a plane is required. In games, it can be used as a universal algorithm for generating random polygons on a game map. All you need is to generate random points on the plane and build a map based on them. That was my plan, but I still needed to understand how to implement the Voronoi diagram algorithm.&lt;/p&gt;

&lt;p&gt;While reading the Wikipedia page my attention was captured by a picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ftt%2F1h%2Fpw%2Ftt1hpwbh7m124h_hfwaaibkhjkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ftt%2F1h%2Fpw%2Ftt1hpwbh7m124h_hfwaaibkhjkm.png" alt="Manhattan Distance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This got me seriously interested—look at the image on the right under the caption "Manhattan distance"—I literally understood at that moment that this is exactly what we need for our game. Look at these concepts, and you'll see it too:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fur%2Fg9%2Fop%2Furg9opfdkwrforaurzo6gsiewzk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fur%2Fg9%2Fop%2Furg9opfdkwrforaurzo6gsiewzk.jpeg" alt="Concepts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clear, straight-diagonal lines for biome boundaries—perfectly suited to our stylized art. It's like taking a regular Voronoi map and stylizing it precisely to Ilya's art. In short, I understood that I wanted the division of the game map into biomes to have that and only that shape.&lt;/p&gt;

&lt;h1&gt;
  
  
  Distances
&lt;/h1&gt;

&lt;p&gt;But how is such a variation of the diagram built, and what is this "Manhattan distance" thing? I went to Wikipedia again to find the answers. In short, the &lt;a href="https://en.wikipedia.org/wiki/Taxicab_geometry" rel="noopener noreferrer"&gt;Manhattan distance&lt;/a&gt; is an alternative way to calculate the distance between two points.&lt;/p&gt;

&lt;p&gt;How do we usually calculate the distance from point A to point B? We draw a straight line between the points and measure its length. This length is the distance between A and B. This is the &lt;em&gt;Euclidean distance&lt;/em&gt;, and its formula is well-known:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxwzdxmjmbj5z2hkay1i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxwzdxmjmbj5z2hkay1i.png" alt="Euclidian distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what if point A is you, and B is a public toilet in a city with square blocks? If you draw a straight line between A and B on the map, the line will go through buildings. Even if you're in a hurry, you won't break through all the buildings in your way. Google Maps or a navigator will give you a route of straight segments with some turns—left and right.&lt;/p&gt;

&lt;p&gt;Look at these three paths from one point to another:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F27%2Fxl%2Flq%2F27xllqm4er9pzb9drjkug1sofyg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F27%2Fxl%2Flq%2F27xllqm4er9pzb9drjkug1sofyg.jpeg" alt="Three Manhattan Distances of Equal Length"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All three paths are the &lt;em&gt;shortest&lt;/em&gt; paths from one point to another by Manhattan metric. And there are even more of these shortest paths. All these shortest paths have the same length. In the case of the points in the image, it's 12 units. This is the Manhattan distance. It is achieved by a large number of options but has a specific value that can be calculated by the formula:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e9gjw1i8m0kmw8adlkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e9gjw1i8m0kmw8adlkg.png" alt="Manhattan distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Manhattan distance is also called taxicab distance or L1 distance. It got the Manhattan name because the street layout of Manhattan has a pronounced block structure. Also, it's called taxicab distance because a taxi in Manhattan can only move along the streets, not through buildings, obviously. Also, Manhattan distances are how a rook moves on a chessboard.&lt;/p&gt;

&lt;p&gt;So, I figured out that depending on the metric we use to measure the distance, the Voronoi diagram would look different. And it turns out there are an infinite number of metrics. That is, there are an infinite number of ways to calculate distance? In general, yes, there's even a general formula called the &lt;a href="https://en.wikipedia.org/wiki/Minkowski_distance" rel="noopener noreferrer"&gt;Minkowski distance&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faby073we77q596yr1wan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faby073we77q596yr1wan.png" alt="Minkowski distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;where &lt;strong&gt;&lt;em&gt;p&lt;/em&gt;&lt;/strong&gt; is the so-called &lt;em&gt;order&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now, follow my hands: if you substitute &lt;strong&gt;&lt;em&gt;p=1&lt;/em&gt;&lt;/strong&gt; into the formula, you get the Manhattan distance formula; and if you substitute &lt;strong&gt;&lt;em&gt;p=2&lt;/em&gt;&lt;/strong&gt;, you get&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu46ya52v3diuih7tixiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu46ya52v3diuih7tixiu.png" alt="Minkowski order=2 distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which is essentially&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxwzdxmjmbj5z2hkay1i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxwzdxmjmbj5z2hkay1i.png" alt="Euclidian distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;i.e., Euclidean distance.&lt;/p&gt;

&lt;p&gt;Thus, the Manhattan distance is the Minkowski distance of the first order, and Euclidean distance is the Minkowski distance of the second order. We can increase the order to infinity. Literally—to &lt;strong&gt;&lt;em&gt;∞&lt;/em&gt;&lt;/strong&gt;. With &lt;strong&gt;&lt;em&gt;p=∞&lt;/em&gt;&lt;/strong&gt;, the formula degenerates into the so-called &lt;a href="https://en.wikipedia.org/wiki/Chebyshev_distance" rel="noopener noreferrer"&gt;Chebyshev distance&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqxnx2co4evguz9607dq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqxnx2co4evguz9607dq.png" alt="Chebyshev distance formula"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, as a non-mathematician, I don't quite understand how &lt;strong&gt;&lt;em&gt;lim → ∞&lt;/em&gt;&lt;/strong&gt; turns this formula into &lt;strong&gt;&lt;em&gt;max&lt;/em&gt;&lt;/strong&gt;. If someone in the comments can explain this to me in a straightforward way, I would be very grateful.&lt;/p&gt;

&lt;p&gt;There is a high probability that I will want to use different metrics, so now I have a universal function for this in my arsenal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Euqlid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;default:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Euqlid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Manhattan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Chebyshev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or, if you know the metric at compile time, and it won't change at runtime, it's even better to make it like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpaceMetric&lt;/span&gt; &lt;span class="n"&gt;METRIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Euqlid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;distance_t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;METRIC&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Manhattan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;constexpr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;METRIC&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SpaceMetric&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Chebyshev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="c1"&gt;// SpaceMetric::Euqlid&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Bonus
&lt;/h4&gt;

&lt;p&gt;In the &lt;a href="https://en.wikipedia.org/wiki/Minkowski_distance" rel="noopener noreferrer"&gt;Wikipedia article&lt;/a&gt; on the Minkowski distance, there's an interesting thought experiment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbi%2Frz%2Fh6%2Fbirzh6jdwojf_832e3heysczpcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbi%2Frz%2Fh6%2Fbirzh6jdwojf_832e3heysczpcg.png" alt="Chessboard Distances"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It shows how the distance between two points differs for an ant, a king, and a rook on a chessboard. The ant moves with Euclidean distances, and its distance will be equal to the classical hypotenuse formula for legs of lengths 4 and 3; i.e., the ant will cover the distance in 5 units. The king moves with Chebyshev metric, so he can cheat—his diagonal moves are equal to horizontal and vertical ones, so he will reach the finish in 4 steps. The rook moves with our beloved Manhattan metric and closes the top three, reaching the finish in 7 steps.&lt;/p&gt;
&lt;h1&gt;
  
  
  Naive Implementation
&lt;/h1&gt;

&lt;p&gt;First of all, there is the simplest and most primitive algorithm for building a Voronoi diagram with &lt;em&gt;any&lt;/em&gt; metric. It involves iterating over &lt;strong&gt;every&lt;/strong&gt; pixel in your 2D space and comparing the distance from that pixel to &lt;strong&gt;every&lt;/strong&gt; point (or toilets, if you will) in that space. When we find the point closest to the pixel, we assume that the pixel belongs to the polygon with this point, and we color that pixel accordingly.&lt;/p&gt;

&lt;p&gt;This approach can be used to easily generate a Voronoi diagram with taxicab distances (i.e., using Manhattan distances). So, to quickly assess the Voronoi map in action, I &lt;a href="https://github.com/AskePit/VoronoiTestGodot/tree/main" rel="noopener noreferrer"&gt;implemented&lt;/a&gt; this algorithm directly in GDScript in Godot to interactively explore maps with different metrics. Disregarding all the details, the pure algorithm code looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;min_dist&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;9999999.0&lt;/span&gt;
        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;belonged_site&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;site_idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;site_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;min_dist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;min_dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;
                &lt;span class="n"&gt;belonged_site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;site_idx&lt;/span&gt;

        &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sites_colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;belonged_site&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;draw_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Below are Voronoi maps for the same set of ten points but built using different metrics.&lt;/p&gt;

&lt;p&gt;Euclidean. Classic Voronoi map:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Frz%2Fmh%2Fbk%2Frzmhbk-btlyfx1ytgpv1ajfvrw0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Frz%2Fmh%2Fbk%2Frzmhbk-btlyfx1ytgpv1ajfvrw0.jpeg" alt="Euclidean. Classic Voronoi map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Manhattan. Looks as cool as I imagined:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffj%2Foi%2Fqw%2Ffjoiqwbpphzagpemacn2rpgtnnu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffj%2Foi%2Fqw%2Ffjoiqwbpphzagpemacn2rpgtnnu.jpeg" alt="Manhattan. Looks as cool as I imagined"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chebyshev:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fhd%2F3_%2Fdn%2Fhd3_dn6hhrtaab8msy5eqh9rwag.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fhd%2F3_%2Fdn%2Fhd3_dn6hhrtaab8msy5eqh9rwag.jpeg" alt="Chebyshev"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Chebyshev map looks similar to the Manhattan map, but there is a tendency towards greater diagonalization of the regions. In my opinion, these are biomes with too specific shapes for our game.&lt;/p&gt;

&lt;p&gt;Map with Minkowski order &lt;strong&gt;&lt;em&gt;p=1.5&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbu%2Fxz%2F6u%2Fbuxz6uboovbx6cijlzd0vuu2vh8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbu%2Fxz%2F6u%2Fbuxz6uboovbx6cijlzd0vuu2vh8.jpeg" alt="Map with Minkowski order p=1.5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In fact, this is an averaging of Euclidean and Manhattan maps. The boundaries cease to consist of straight lines and turn into curves. Such a Voronoi map could be useful, especially if you need stylization with soft rounded contours. Moreover, you can experiment with &lt;strong&gt;&lt;em&gt;p&lt;/em&gt;&lt;/strong&gt; to achieve the level of curvature that suits you.&lt;/p&gt;

&lt;p&gt;But be cautious! You may end up with something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3_%2Fve%2Frm%2F3_vermamrq0ysoreez1gnqv4m8m.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3_%2Fve%2Frm%2F3_vermamrq0ysoreez1gnqv4m8m.jpeg" alt="p=0.5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, if we go to a very small order of &lt;strong&gt;&lt;em&gt;p&lt;/em&gt;&lt;/strong&gt;, space begins to distort significantly, and the map starts to take on a surrealistic weird appearance.&lt;/p&gt;

&lt;p&gt;All in all, with such a primitive algorithm, I was able to play around with different types of Voronoi maps much as I wanted. And I’ve just become even more convinced in my desire to use the version with taxicab distances. But maybe we could use the algorithm we just used for our game implementation? Nope. It is not viable and has a number of fatal drawbacks, and it out of our consideration for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The necessity of discrete space.&lt;/strong&gt; The algorithm assumes that our space consists of a finite number of coordinates or pixels. However, this is not always the case. An adequate algorithm should operate with polygons and output, in the end, a list of polygons describing the Voronoi map—thus, we get the boundaries of the regions, and we can then manipulate them as we see fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can only fill regions with a solid color.&lt;/strong&gt; The algorithm does not draw the boundaries of the Voronoi regions, but just fills the regions with color. As a result, you cannot apply a texture to your regions or procedurally enhance them in any way—only a solid color fill without borders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; The algorithm has terrible performance: its complexity is &lt;strong&gt;&lt;em&gt;O(n²)&lt;/em&gt;&lt;/strong&gt;. And it is necessary to iterate over all existing coordinates in space, which greatly worsens the situation. For example, building a map of size 640x640 takes an average of 3.3 seconds, and 1024x1024—7-8 seconds on a PC designed for professional game development. This is horribly slow for such a primitive colorful picture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is another similar but more efficient algorithm called the &lt;a href="https://en.wikipedia.org/wiki/Jump_flooding_algorithm" rel="noopener noreferrer"&gt;Jump Flooding Algorithm&lt;/a&gt;, but we will not consider it either, as it also colors the map in parts, not building polygons.&lt;/p&gt;

&lt;h1&gt;
  
  
  In Search of the Right Algorithm
&lt;/h1&gt;

&lt;p&gt;And then I thought: alright, we just need to take and implement one of the &lt;em&gt;efficient&lt;/em&gt; Voronoi diagram algorithms—which have a sweet &lt;strong&gt;&lt;em&gt;O(n log n)&lt;/em&gt;&lt;/strong&gt; complexity and yield the set of polygon coordinates as a result. The only trick is to use a Taxicab distance instead of Euclidean one every time we need to calculate the distance, and we a done!&lt;/p&gt;

&lt;p&gt;Soon it turned out that this was a very naive plan because any of the algorithms was complex enough and not easy to modify in a desired manner. It wasn't possible to simply take and embed a differently measured distance from point to point. Or sometimes it was possible, but that was not nearly enough.&lt;/p&gt;

&lt;p&gt;For example, the algorithm for building a Voronoi map through &lt;a href="https://en.wikipedia.org/wiki/Delaunay_triangulation" rel="noopener noreferrer"&gt;Delaunay triangulation&lt;/a&gt; requires drawing circles and then connecting their centers. We connect the centers of the circles—voila, we get the Voronoi diagram. The question is: where are the distances there? Well, um, they are probably somewhere there, but not in such an explicit form as I assumed.&lt;/p&gt;

&lt;p&gt;Another example: &lt;a href="https://en.wikipedia.org/wiki/Fortune%27s_algorithm" rel="noopener noreferrer"&gt;Fortune's Algorithm&lt;/a&gt; builds the boundaries of the Voronoi polygons with help of parabolas. Parabolas, Carl! Where is the application of the distance function? It is applied there, but for indirect things. My easy-peazy plan will not work here again.&lt;/p&gt;

&lt;p&gt;At this point, I felt a bit down because I'm not a good mathematician, and I even don't digest these sweaty algorithms of analytical geometry very well. Not to mention modifying them for a fundamentally different type of distance.&lt;/p&gt;

&lt;p&gt;So, I decided to look at ready-made libraries and went to dig GitHub for a solution. Most of them were predictably adapted for regular Euclidean Voronoi maps without the ability to use alternative metrics and build a non-standard Voronoi map. Among them were good high-performance libraries, but I couldn't use them anyway. Maybe I was searching poorly or in a wrong place— I don't know. In the end, I came across the only one project implementing the Manhattan metric Voronoi map but it had a specific algorithm written in JavaScript. And with JavaScript, I had little to do in the paradigm of a Godot project. Such is the sadness.&lt;/p&gt;

&lt;p&gt;The more I searched, the more desperate I became. I obsessively roamed through GitHub. I googled some scientific articles, but I just couldn't understand them well. Out of desperation, I went to YouTube in the hope of finding some lecture or popular science video about the Voronoi diagram with the Manhattan metric. I filtered out so much content that ultimately didn't help me, and I was already bewildered.&lt;/p&gt;

&lt;p&gt;And then, quite unexpectedly, amid all the variety of dubious YouTube content, I stumbled upon a gem: a &lt;a href="https://www.youtube.com/watch?v=L_joQb12QSE" rel="noopener noreferrer"&gt;video&lt;/a&gt; that thoroughly describes the mathematics behind the Voronoi diagram and &lt;a href="https://en.wikipedia.org/wiki/Fortune%27s_algorithm" rel="noopener noreferrer"&gt;Fortune's Algorithm&lt;/a&gt; in particular. This video is so amazing that I recommend it to anyone interested in this topic—watch it from the beginning to the end. It clearly explains the nature of the algorithm, with an unexpected transition to 3D space to later return to 2D space and apply what was learned in 3D. It sounds like a cool plot twist. Even now, in the process of writing the article, I realized why I didn't find this video immediately: when I started searching for it the second time, for this article, I spent probably half a day to locate it again. The problem with the video is its title, "How Parabolas Can Help Describe Nature and Business | Fortune's Algorithm &lt;a href="https://www.youtube.com/hashtag/some2" rel="noopener noreferrer"&gt;#some2&lt;/a&gt;". Not a word about the Voronoi diagram, only a mention of Fortune's Algorithm at the very end. The author of the video, &lt;a href="https://www.youtube.com/@alexajoy8836" rel="noopener noreferrer"&gt;Alexa Joy&lt;/a&gt;, has an interesting situation with his channel—only 3 videos and 180 subscribers. The other two videos are not of such scale, which makes it even more surprising that he presented such a good material.&lt;/p&gt;

&lt;p&gt;So, in addition to the fact that the video itself turned out to be very fascinating, its &lt;a href="https://youtu.be/L_joQb12QSE?t=1316" rel="noopener noreferrer"&gt;third and final part&lt;/a&gt; talks about the Manhattan distance and its application to the Fortune's Algorithm. But first, let's look at the visualization of how this algorithm works with the Euclidean metric:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F0h%2Fxb%2Fdk%2F0hxbdkiccrbi3xbqwqvjrkv7dee.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F0h%2Fxb%2Fdk%2F0hxbdkiccrbi3xbqwqvjrkv7dee.gif" alt="Fortune's Algorithm in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following the horizontal line going down, parabolas are drawn in a clever manner, and the intersections of these parabolas outline the boundaries of the Voronoi regions. I won't dive now into the intricacies of the algorithm itself—it seems quite puzzling to me. What interests us is how the author of the video explained in an accessible way that the same parabolas can be used to draw the Voronoi diagram in the Manhattan metric. With only important modification—the parabola will not be Euclidean but represented in Manhattan space.&lt;/p&gt;

&lt;p&gt;How is this possible? Let's take a step back. How can we describe what a circle is? Well, it's a curve where all points have the same &lt;em&gt;distance&lt;/em&gt; to a special point—the center. I am, of course, hinting at the term "distance" in this definition. What if we try to build a shape with the same properties, but where distances are measured in Manhattan space? Wikipedia has an illustrative image of such a figure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fy2%2Fhv%2F5e%2Fy2hv5efsdpx-5knmsxvtpuhwriy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fy2%2Fhv%2F5e%2Fy2hv5efsdpx-5knmsxvtpuhwriy.png" alt="Circle in taxicab space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, it all depends on the size of the grid, or "city blocks". But if we imagine that the grid is infinitely fine, such a "circle" takes on the outlines of a diamond! Yes, that is a circle in taxicab space. Accordingly, in taxicab geometry, you can get other shapes. For example, a parabola becomes this weird thing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fo2%2Fc8%2Fys%2Fo2c8ys5-stpgjg9ksjhnsvzj4_u.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fo2%2Fc8%2Fys%2Fo2c8ys5-stpgjg9ksjhnsvzj4_u.jpeg" alt="Parabola in taxicab space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;L&lt;/em&gt;&lt;/strong&gt; here is not part of the parabola; it is its &lt;a href="https://en.wikipedia.org/wiki/Directrix" rel="noopener noreferrer"&gt;directrix&lt;/a&gt;. The main property of a parabola is the equality of the &lt;em&gt;distance&lt;/em&gt; from each point on the curve to the focus &lt;strong&gt;&lt;em&gt;P&lt;/em&gt;&lt;/strong&gt; and the &lt;em&gt;distance&lt;/em&gt; to the directrix &lt;strong&gt;&lt;em&gt;L&lt;/em&gt;&lt;/strong&gt;. Try taking any point &lt;em&gt;on the parabola&lt;/em&gt; and measuring its Manhattan distance (remember, it's like how a chess rook moves) first to the focus, then to the horizontal line. It will always be the same. Therefore, this figure is a taxicab space parabola.&lt;/p&gt;

&lt;p&gt;Now, let's look at the vivid animation from the video about Fortune's Algorithm, which builds the Voronoi diagram with taxicab parabolas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fn5%2F0v%2Fu-%2Fn50vu-zsmem-9e5wkxm_a_8rv6s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fn5%2F0v%2Fu-%2Fn50vu-zsmem-9e5wkxm_a_8rv6s.gif" alt="Fortune's Algorithm in taxicab soace in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! All that remained is to understand how to incorporate this concept into the classical Fortune's Algorithm. But since even the &lt;a href="https://en.wikipedia.org/wiki/Fortune%27s_algorithm#Pseudocode" rel="noopener noreferrer"&gt;pseudocode&lt;/a&gt; of the algorithm looks scary, not to mention its actual implementations in code, the task was complex and puzzling.&lt;/p&gt;

&lt;p&gt;I tried downloading various libraries implementing the classical Fortune's Algorithm and modifying them according to my new vision. But I did it quite clumsily, I would even say blindly, as I constantly crashed into the jaw-breaking mathematics and the impossibility of understanding how to reorient it on taxicab rails.&lt;/p&gt;

&lt;p&gt;To give you a better understanding, why it was so difficult, I'll say that the drifting parabolas in the Fortune's algorithm are just an idea, a concept. The final algorithm itself reworked and modified this concept so much that only some abstract steps remained, which effectively lead to the same result as you see in the gifs I showed above. So, it's not so easy to even find a parabola inside real algorithm's implementation.&lt;/p&gt;

&lt;p&gt;You can see my struggles in one of the drafts where I tried to manage non-Euclidean parabolas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F35%2Fvg%2Fbr%2F35vgbr69pnkrelrkdnzuejzd060.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F35%2Fvg%2Fbr%2F35vgbr69pnkrelrkdnzuejzd060.jpeg" alt="Difficult"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, I spent a lot of time on this.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Found Solution
&lt;/h1&gt;

&lt;p&gt;As you understand, in the end, I somehow managed to create the Voronoi diagram I needed. But how I did it will totally disappoint you.&lt;/p&gt;

&lt;p&gt;I did not manage to modify the Fortune's Algorithm. Yes, at some point, I abandoned this idea because a lot of time had passed, the game needed to be developed, and I had nothing to show to Ilya. I needed to take action instead of stagnating with something I poorly understood.&lt;/p&gt;

&lt;p&gt;So yes, you can just throw away the entire previous chapter. Why did I even make you read it only to disappoint you at the end? Well, there is a reason:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You experienced my journey and my pain.&lt;/li&gt;
&lt;li&gt;You might have learned as much interesting stuff as I did during this fascinating dive into a dead end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what did I do? As I mentioned earlier, I stumbled upon an &lt;a href="https://github.com/JDragovich/manhattan-voronoi" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; of the Voronoi diagram in taxicab space, written in JavaScript. I looked at it for a long time, admired it, ran the project, saw that the code worked. The author even has a &lt;a href="http://voronoi.joe-dragovich.co.uk.s3-website.eu-west-2.amazonaws.com/" rel="noopener noreferrer"&gt;demo page&lt;/a&gt; showing the result of his library.&lt;/p&gt;

&lt;p&gt;Moreover, the algorithm's code in fact was in one file and consisted of only 800 lines. So, I decided to simply rewrite this code in C++. I had this thought when I first encountered the project, but back then it seemed unworthy. Now I didn't care anymore :) Many thanks to &lt;a href="https://github.com/JDragovich" rel="noopener noreferrer"&gt;Joe Dragovich&lt;/a&gt; for his project.&lt;/p&gt;

&lt;p&gt;For those who is interested, the algorithm implemented by the project's author is a &lt;a href="https://www.researchgate.net/publication/220431260_Two-Dimensional_Voronoi_Diagrams_in_the_L" rel="noopener noreferrer"&gt;smart algorithm&lt;/a&gt; by &lt;a href="https://www.semanticscholar.org/author/D.-T.-Lee/1410164694" rel="noopener noreferrer"&gt;D. T. Lee&lt;/a&gt; and &lt;a href="https://www.semanticscholar.org/author/Chak-Kuen-Wong/1723116" rel="noopener noreferrer"&gt;Chak-Kuen Wong&lt;/a&gt;, which allows you to build a Voronoi map for any metric, including the Chebyshev metric &lt;strong&gt;&lt;em&gt;p=∞&lt;/em&gt;&lt;/strong&gt;. The repository's author implemented a special case for taxicab space (&lt;strong&gt;&lt;em&gt;p=1&lt;/em&gt;&lt;/strong&gt;), simply because, as he said, "This creates cells that have kinked edges and strange protrusions. In short, they just look cool!" My thoughts exactly.&lt;/p&gt;

&lt;p&gt;By the way, I tried to read the PDF with the original text of the scientific paper about this algorithm from 1980 and managed to understand almost everything, including all definitions, lemmas, and theorems, until the moment when the description of the algorithm itself began. It became somewhat incomprehensible, which I couldn't grasp. It's a pity, but just a little—because I had a ready implementation of the algorithm that I started rewriting in C++.&lt;/p&gt;

&lt;p&gt;Adapting the code to C++ was also an interesting experience from the perspective of the differences between the two languages. The project's author wrote the code in a functional style using &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt;, and similar constructs. It was interesting to see how such constructions look in modern C++ compared to JavaScript. Also, I had a freedom to use the latest C++ standard available (unlike almost all C++ programmers on their work projects), and I could enjoy the charms of C++20 and its &lt;a href="https://en.cppreference.com/w/cpp/ranges" rel="noopener noreferrer"&gt;&lt;code&gt;std::ranges&lt;/code&gt;&lt;/a&gt; library. Well, enjoy may not be the right word—soon it became clear that ranges in C++ are still raw, and they will remain in such condition for a long time. For example, you cannot replace such JS code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;with a C++ equivalent like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;because there is no &lt;code&gt;std::views::sort&lt;/code&gt; adapter, only &lt;a href="https://en.cppreference.com/w/cpp/algorithm/ranges/sort" rel="noopener noreferrer"&gt;&lt;code&gt;std::ranges::sort&lt;/code&gt;&lt;/a&gt;, which does not support piping &lt;code&gt;|&lt;/code&gt;. Ranges also do not support &lt;a href="https://en.cppreference.com/w/cpp/algorithm/accumulate" rel="noopener noreferrer"&gt;&lt;code&gt;accumulate&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://en.cppreference.com/w/cpp/algorithm/reduce" rel="noopener noreferrer"&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/a&gt;, and transforming a &lt;code&gt;view&lt;/code&gt; back into a container through &lt;code&gt;|&lt;/code&gt; is only available in &lt;a href="https://en.cppreference.com/w/cpp/ranges/to" rel="noopener noreferrer"&gt;C++23&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's another kekw—compare this two code snippets:&lt;/p&gt;

&lt;p&gt;JS code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// combine all the merge arrays&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mergeArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;initialBisector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;upStrokeArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;downStrokeArray&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;C++ code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// combine all the merge arrays&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BisectorRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;upStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;downStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emplace_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialBisector&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_move_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_move_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;mergeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_move_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_move_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downStrokeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Yes, in C++23, &lt;a href="https://en.cppreference.com/w/cpp/container/vector/append_range" rel="noopener noreferrer"&gt;&lt;code&gt;std::vector::append_range&lt;/code&gt;&lt;/a&gt; has arrived, and the code could look nicer with it, but even a C++ enthusiast with untied hands in 2022 could not afford it. You can suggest more readable and shorter variants of this code in the comments, I would appreciate that. The main condition for the suggested code is that there shouldn't be copying anywhere, and there should be minimal memory allocations.&lt;/p&gt;

&lt;p&gt;Well, in the meantime, I, once again, come to the sad conclusion that C++, my main working programming language, still cannot be called user-friendly and enjoyable to use. The latest released standards are taking it in a strange direction.&lt;/p&gt;

&lt;h1&gt;
  
  
  Integrating Code into Godot
&lt;/h1&gt;

&lt;p&gt;So, the C++ code was written and tested, functioning similarly to the original JavaScript. Now the question is: how to integrate this code into the game engine?&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, Godot provides the opportunity to write code in different languages, including C++. This can be done using a technology called &lt;a href="https://docs.godotengine.org/en/3.5/tutorials/scripting/gdnative/index.html" rel="noopener noreferrer"&gt;GDNative&lt;/a&gt; in Godot 3 and &lt;a href="https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/index.html" rel="noopener noreferrer"&gt;GDExtension&lt;/a&gt; in Godot 4. The basic principle of operation is the same for both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write C++ classes or functions using &lt;a href="https://github.com/godotengine/godot-cpp" rel="noopener noreferrer"&gt;C++ bindings&lt;/a&gt; for the Godot engine.&lt;/li&gt;
&lt;li&gt;Compile to obtain a DLL library.&lt;/li&gt;
&lt;li&gt;When the game or game editor is launched, the DLL library is loaded by the engine.&lt;/li&gt;
&lt;li&gt;Classes and functions written in C++ become available to the scene tree and GDScript.&lt;/li&gt;
&lt;li&gt;Use the interface of these classes and functions in GDScript, and they'll execute fast, performant native code hidden under the hood.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Integrating C++ code didn't pose any particular issues, and the Godot documentation provides good examples of the entire process, so we can just move on further.&lt;/p&gt;

&lt;h1&gt;
  
  
  Map Generation
&lt;/h1&gt;

&lt;p&gt;Now one of the key moments comes into scene. Now I had the ability to generate a Voronoi map in taxicab space. The process worked roughly as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Godot, I generated a certain number of random points.&lt;/li&gt;
&lt;li&gt;The points and parameters of the 2D canvas were passed to the native code.&lt;/li&gt;
&lt;li&gt;The native code provided me with ready-made polygons for the canvas.&lt;/li&gt;
&lt;li&gt;I just had to draw the polygons on the screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what I got in the end:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3a%2Fa9%2Fq_%2F3aa9q_npaurtx7-dcyzatiwi4pk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F3a%2Fa9%2Fq_%2F3aa9q_npaurtx7-dcyzatiwi4pk.jpeg" alt="Voronoi Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding more points generates more polygons:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F-9%2Fjy%2F0p%2F-9jy0prcbqgpanh5nhjtpq9ryq0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F-9%2Fjy%2F0p%2F-9jy0prcbqgpanh5nhjtpq9ryq0.jpeg" alt="More Polygons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can imagine that this is a huge world map divided into multiple biomes. By the way, I got an idea of how to implement stylized roads running across the entire map: generate another Voronoi map with a small number of regions and overlay it on the main level map. Here's how it could look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F-l%2Fmq%2Fqy%2F-lmqqyu9dxp0g1xk5il9r-nlstk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F-l%2Fmq%2Fqy%2F-lmqqyu9dxp0g1xk5il9r-nlstk.jpeg" alt="Overlayed Voronoi Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We overlaid a green Voronoi map with three regions on top of the main biome Voronoi map. You can imagine that the entire map is walkable, and the green lines represent the main well-trodden paths, that provide speed bonuses or lead us to key points of interest on the map.&lt;/p&gt;

&lt;p&gt;At this point, everything still looks schematic and not much like a game map. It's time to clean up unnecessary elements and add various decorations. It's worth noting that during these modifications, the Voronoi map will lose its properties, but for our purposes, it doesn't matter. The Voronoi map was only needed for the initial generation of our beautiful polygons. After that, we are free to do whatever we want with these polygons.&lt;/p&gt;

&lt;p&gt;What bothers us in the current version of the map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The map is rectangular. Instead we want an island with irregular edges.&lt;/li&gt;
&lt;li&gt;We want to differentiate the biomes, at least with colors, and preferably with textures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simplest way to turn a square map into an island is to remove all the outer biomes that formed the perimeter of the map. Then the remaining biomes will form the silhouette of the island with irregular edges. Let's stick to this method for now. Each biome will be colored with a random color, resulting in the following picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F2n%2Ffj%2Fk3%2F2nfjk3zo9jhpe6lumahnodjs8j8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F2n%2Ffj%2Fk3%2F2nfjk3zo9jhpe6lumahnodjs8j8.jpeg" alt="Colored Biomes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like an island indeed. However, the roads are broken. Even if we ignore the fact that the roads are now floating in the air (we can algorithmically deal with this), we encounter logistical and common-sense problems. Look, for example, at the khaki-colored peninsula in the upper right corner of the map. Do you see that small piece of the road, unconnected to other paths on the map (imagine that we have already eliminated road sections hanging in the air), starting at the edge and immediately ends? This is the reveal of the unstable nature of &lt;em&gt;random&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We decided to temporarily set aside the road issue with Ilya and focus exclusively on the biomes and refining them to a more complete state. But for the future, I prepared a completely different road generation algorithm that would take information about points of interest/attraction on the map and build a sophisticated road graph in such a way that points of interest either sit on the road or the road passes directly through them. However, this, in turn, requires generating points of interest on the map, which is a different story... As you can see, one thing leads to another, and it can turn into an endless narrative. This is precisely why we've decided to finish with the biomes first and not to spread ourselves thin.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating Game Biomes
&lt;/h1&gt;

&lt;p&gt;Our plan for the game world was ambitious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We needed to create 4 different types of maps: forest, dungeons, infernal rift, and mountainous terrain.&lt;/li&gt;
&lt;li&gt;Each map would be divided into biomes, with 3-4 variations of biomes on each map.&lt;/li&gt;
&lt;li&gt;Each biome would have its own set of items and props. For example, a forest biome on a forest map should have many trees and mushrooms; while on a rocky biome, you might randomly find a sword stuck in the ground.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ilya drew concepts showing how each map should ideally look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Feb%2Fft%2Fcn%2Febftcn1_3foiqlfty42koryfrzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Feb%2Fft%2Fcn%2Febftcn1_3foiqlfty42koryfrzg.png" alt="Concepts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a closer look at the forest map so you can see the details:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F6q%2Fbt%2Fea%2F6qbteacoo6f8jusxbimjcdy49ck.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F6q%2Fbt%2Fea%2F6qbteacoo6f8jusxbimjcdy49ck.jpeg" alt="Forest Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was the reference I had to aim for. While generating everything randomly, it would be impossible to achieve an exact match in terms of the harmony of composition and artistic subtleties, but I could try to get close to this image.&lt;/p&gt;

&lt;p&gt;I was provided with textures for each biome type, as well as some items to scatter on the map. I was blessed and given the green light, so I started transforming schematic polygons into beautiful biomes.&lt;/p&gt;

&lt;p&gt;While waiting for the necessary artistic assets, I managed to integrate the game's polygonal level with our character, whom I simply transferred from our side-scrolling prototype level. I removed gravity and jumping, taught the character to move not only left and right but also up and down, and the character started to cheerfully walk over the polygons.&lt;/p&gt;

&lt;p&gt;Then, instead of a solid color fill, I applied textures from Ilya onto the polygons, and the image started to take on a more game-like appearance:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fzs%2F65%2F85%2Fzs6585ltoa1qongul1azct-fsbw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fzs%2F65%2F85%2Fzs6585ltoa1qongul1azct-fsbw.jpeg" alt="Textured Biomes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The lifeless polygons immediately felt like earth with grass and soil—a magical transformation.&lt;/p&gt;

&lt;p&gt;Notice the rough borders of the biomes. I wrote a shader that draws a blobby thing and applied it to the lines of the polygons. In Godot, you can apply a shader to any visible object on the scene—it's very convenient.&lt;/p&gt;

&lt;p&gt;In addition to textures, I had items for different maps that needed to be randomly scattered throughout the world. Ilya's instructions were like, "&lt;em&gt;Well, on the grassy biome, we need to generate trees and mushrooms, and on the rocky one, you might randomly encounter a sword stuck in the ground.&lt;/em&gt;" Okay, let's scatter them around; it sounds simple and harmless, doesn't it? I implemented a primitive algorithm that generated some quantity of something in random places within each polygon, depending on the biome type. This is what the forest biome looked like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fjk%2Fyn%2Faf%2Fjkynafomlz-wdjcifxzrkupg3wa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fjk%2Fyn%2Faf%2Fjkynafomlz-wdjcifxzrkupg3wa.png" alt="Forest Biome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmm, okay, a bit too many swords and stone heads, but overall, it's fine, and the picture looks lively. However, if lots of trees and mushrooms look good, things were sadder on other levels. Here, for example, is the dungeon map at that time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffb%2Fcx%2Fqe%2Ffbcxqe8cktwgitmtisoigtqzzww.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffb%2Fcx%2Fqe%2Ffbcxqe8cktwgitmtisoigtqzzww.jpeg" alt="Dungeon Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Ilya saw this, he was like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ns4adkqh7q7zcin7oj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ns4adkqh7q7zcin7oj.jpg" alt="Ilya's Reaction"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, I personally did nothing; it's just &lt;em&gt;random&lt;/em&gt;. Even when Ilya was strongly urging me to abruptly change course towards a generated map with biomes, I was already wary of such problems at that time and even tried to warn Ilya. Because it could turn out that a significant part of development would go towards dealing with overly random randomness that's hard to control. But to understand how cool random is, you need to see it with your own eyes and feel all the inconveniences on your own skin.&lt;/p&gt;

&lt;p&gt;We will win the random, but later. For now, we decided to dive deeper into the visual details of the biomes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Perfecting the Visuals of Biomes
&lt;/h1&gt;

&lt;p&gt;Ilya gave me an intermediate instruction—achieve a map that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fhn%2Fq7%2Fgd%2Fhnq7gdjuun2eatfly6cxmy17ws8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fhn%2Fq7%2Fgd%2Fhnq7gdjuun2eatfly6cxmy17ws8.png" alt="Desired Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The list of requirements included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The borders between biomes should look as if covered with colorful grass strands.&lt;/li&gt;
&lt;li&gt;The island's perimeter should have a special border.&lt;/li&gt;
&lt;li&gt;The island should have a "thickness" in the form of a stylized downward slope.&lt;/li&gt;
&lt;li&gt;Adjacent biomes should not be identical—there shouldn't be two grassy biomes neighboring each other with a strange useless border. You can refer back to the dreadful screenshot of the dungeon map I showed earlier to see how two tile-like biomes neighbor each other—it looks wrong and unnatural.&lt;/li&gt;
&lt;li&gt;The random placement of objects on the map should be "normal" and visually pleasing.&lt;/li&gt;
&lt;li&gt;I'll jump ahead and mention another problem that surfaced during the process, requiring a solution: sometimes, the Voronoi diagram generated polygons with extremely short edges, meaning two neighboring points of a polygon were so close that the distance between them approached just a few pixels. This resulted in unpleasant visual artifacts, which I'll show later. I'll just say for now that these points needed to be somehow fixed—either by removing one of the points or by somehow turning two points into one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, there was quite a list. Individually, those tasks introduced small visual changes to the biomes, but together, they made a significant difference between a set of flat polygons with stretched textures and a harmoniously perceived map with biomes.&lt;/p&gt;

&lt;p&gt;Let's go through each of these tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Borders Between Biomes
&lt;/h2&gt;

&lt;p&gt;Ilya provided me with an image of a grass strand:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fgl%2Fwl%2Fc8%2Fglwlc8joqcfsaso-f0qrawqrm4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fgl%2Fwl%2Fc8%2Fglwlc8joqcfsaso-f0qrawqrm4k.png" alt="Grass Strand"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and asked me to make sure all biome junctions were covered with it. Each strand should have a slightly different color and a random rotation. This wasn't difficult—I just needed to write a new shader and perform the mentioned manipulations with the strand. When applying the shader to the border, the shader tiles its execution along the entire length of the line, resulting in the following picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Flj%2Flr%2Fvn%2Fljlrvnlijdcxjywdiu6x5nyz3-a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Flj%2Flr%2Fvn%2Fljlrvnlijdcxjywdiu6x5nyz3-a.png" alt="Biome Borders"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dealing with biome junctions is an extensive topic, where various solutions of different complexity can be used. However, we won't dive into that topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Island Perimeter
&lt;/h2&gt;

&lt;p&gt;Or, to be more precise, the perimeters of &lt;em&gt;islands&lt;/em&gt;, since how we de-squared the world map has its consequences. As a reminder, we get an island-like silhouette by removing edge and corner biomes. Meanwhile, the generated Voronoi diagram may have such a tricky configuration of biomes that when we remove unnecessary polygons, we get not one island but two or more. For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F09%2Flv%2Fwr%2F09lvwrxmvrk4jc-6gqp9rnhaloo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F09%2Flv%2Fwr%2F09lvwrxmvrk4jc-6gqp9rnhaloo.png" alt="Main Island and Smaller Island"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We didn't decide what to do with these detached islands in the future, so they remained in the game.&lt;/p&gt;

&lt;p&gt;The algorithm for finding islands is straightforward: we iterate through all biome polygons and try to merge them with neighbors. We keep merging until we're left with a set of large polygons that have no neighbors, and there's nothing left to merge them with. These are our final islands. We just need to outline their perimeters with a stylized stripe, and the task is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thickness Slice
&lt;/h2&gt;

&lt;p&gt;This one turned out to be quite straightforward, mainly because of my laziness. Look at how it looks in theory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fu4%2F-h%2F3h%2Fu4-h3hw2jzopzkjcqjc1tn1gl1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fu4%2F-h%2F3h%2Fu4-h3hw2jzopzkjcqjc1tn1gl1y.png" alt="Thickness Slice"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bold lines represent the world map, the solid thin lines represent the visible thickness slice, and the dashed thin lines represent the invisible thickness slice. The slice consists of quadrilaterals constructed as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From two neighboring points on the map perimeter, we draw vertical segments downward with a constant height &lt;strong&gt;&lt;em&gt;h&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We connect these vertical segments with two more segments to form a quadrilateral.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, we only want to draw the visible parts of the slice, and we don't want to draw the invisible parts. L — logic. I wanted to come up with an algorithm that would calculate the intersection of the map polygon with the slice polygons to determine whether a specific segment of the slice needed to be drawn or if it was invisible. However, during the enumeration of different map forms, I quickly encountered difficult cases:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fev%2Fx1%2F2a%2Fevx12ajgy0sbibertahpxk2tank.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fev%2Fx1%2F2a%2Fevx12ajgy0sbibertahpxk2tank.png" alt="Ambiguous Case"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, look at how the red segment of the slice should be &lt;em&gt;partially&lt;/em&gt; drawn because it is half-hidden behind the map and half-visible. I really didn't want to calculate all this tedious stuff, so I decided to go for the dumb and easy solution: I draw &lt;em&gt;all&lt;/em&gt; slice primitives within the engine, but by placing them on a z-layer behind the map, so more than a half of the slice polygons are simply hiding from our eyes. But they still &lt;em&gt;exist&lt;/em&gt; and probably consume some negligible game resources.&lt;/p&gt;

&lt;p&gt;Here's how the result turned out when looking at the map from a zoomed-out view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fco%2F7x%2Fzc%2Fco7xzcgtqdgvmysbffa1gs5gzmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fco%2F7x%2Fzc%2Fco7xzcgtqdgvmysbffa1gs5gzmo.png" alt="Map with Thickness"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The world map now resembles a carved board, which both I and Ilya quite liked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Point Manipulations
&lt;/h2&gt;

&lt;p&gt;I've already mentioned the issue with points being too close on the map. They caused unpleasant things, as illustrated below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F34%2Fff%2Fcy%2F34ffcyv36wpvp-kudxj9jqwlp7g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F34%2Fff%2Fcy%2F34ffcyv36wpvp-kudxj9jqwlp7g.jpeg" alt="Close Points"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While these points might not be critical within the map, they noticeably affect the thickness slice.&lt;/p&gt;

&lt;p&gt;What can we do about this? We need to move or remove undesired points from the polygons. While this may sound harmless at first glance, careful consideration reveals that actually it's a gateway to the hell of tricky algorithms.&lt;/p&gt;

&lt;p&gt;Expressing further thought won't be easy, so let's periodically look at these esoteric diagrams:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F5n%2Fgj%2Ftj%2F5ngjtjxsnkgneqevdidbidzf2ru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F5n%2Fgj%2Ftj%2F5ngjtjxsnkgneqevdidbidzf2ru.png" alt="Esoteric Diagrams"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, diagram &lt;strong&gt;&lt;em&gt;a&lt;/em&gt;&lt;/strong&gt; shows a map with five polygons. It's not necessarily a Voronoi map, or more likely, it's &lt;em&gt;not&lt;/em&gt; a Voronoi map, but that doesn't matter—we can forget about the Voronoi map for the rest of the article. Now we are dealing purely with polygons which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are neighbors. They "stick" together, forming a seamless space filled with biomes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cannot&lt;/strong&gt; have gaps between neighboring polygons; otherwise, it's not a map but rather a mess. You can look at diagram &lt;strong&gt;&lt;em&gt;d&lt;/em&gt;&lt;/strong&gt; to understand what I mean: the dark area represents the forbidden gap in space. Well, if we want, we can later create these holes in the map intentionally, but not for now—at this stage, gaping holes in space should not be present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's imagine that we want to move one of the points on the map, as shown in &lt;strong&gt;&lt;em&gt;b&lt;/em&gt;&lt;/strong&gt;. Remember that in our memory, the map is represented as a collection of independent polygons. Some polygons share edges—completely or partially, some polygons share points. However, each polygon is described in isolation and is self-sufficient. In diagram &lt;strong&gt;&lt;em&gt;c&lt;/em&gt;&lt;/strong&gt;, we slightly spread out all polygons in space to clearly see all their edges.&lt;/p&gt;

&lt;p&gt;Also, in diagram &lt;strong&gt;&lt;em&gt;c&lt;/em&gt;&lt;/strong&gt;, it becomes apparent that we can't just take and move one point of a specific polygon and consider the task done. Otherwise, we inevitably end up with diagram &lt;strong&gt;&lt;em&gt;d&lt;/em&gt;&lt;/strong&gt;, where the map is broken. The point was moved for the polygon 1, but the same point was shared with the polygon 2, and it also needed to be moved. So, if we carefully keep track of common points and move them all together, will the problem be solved? &lt;em&gt;No.&lt;/em&gt; This is clearly seen with polygon 5. While it technically does not have the same point, the point we want to move lies &lt;em&gt;on one of the edges&lt;/em&gt; of polygon 5. Therefore, polygon 5 implicitly contains this point.&lt;/p&gt;

&lt;p&gt;And that's a problem. How do we move a point that &lt;em&gt;doesn't exist&lt;/em&gt; on a polygon? It needs to be created, and then everything needs to be moved together. The task becomes quite tough. Moreover, this is just one specific task with points on the map. What if we need to delete points or edges of polygons on the map or smartly move the boundaries of one biome? All these tasks will go through the same pain and all that dances around damned points.&lt;/p&gt;

&lt;p&gt;After much thinking, I came up with idea: what if we deviate from the concept of a polygons set and turn the entire map into a graph? So that there is a unified space with points and edges, as in diagram &lt;strong&gt;&lt;em&gt;e&lt;/em&gt;&lt;/strong&gt;, and there is no polygon neighbors anymore. The idea sounded good for the task with points, but bad for everything else: polygons were much more suitable for drawing the map. Besides, the map in Godot was drawn as a set of polygons onto which a texture was applied.&lt;/p&gt;

&lt;p&gt;It became clear that it's more profitable to have &lt;em&gt;both representations&lt;/em&gt; of the map simultaneously: as a set of polygons and as a graph. In C++, I created a class that represents the given map as a graph and allows some manipulations with it. And then, when all desired manipulations are performed, it enables creating a new fresh polygonal representation of the map for a further use in an engine.&lt;/p&gt;

&lt;p&gt;This way, I was able to obtain diagram &lt;strong&gt;&lt;em&gt;e&lt;/em&gt;&lt;/strong&gt; and move points as I desired. For example, turning diagram &lt;strong&gt;&lt;em&gt;e&lt;/em&gt;&lt;/strong&gt; into diagram &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt;. Let's take a closer look at &lt;strong&gt;&lt;em&gt;f&lt;/em&gt;&lt;/strong&gt;: the diagram has colored points. Red points are redundant. Removing them from the graph won't change anything. So, we remove them—redundant information is not needed. Green points, on the other hand, are kinda strange—they are needed by polygons 1, 2, 3, and 4 but are redundant for the polygon 5. Therefore, when converting the graph back into polygons, we should remove them, but only from polygon 5. But they are needed in the graph representation, so they stay there untouched. Finally, when we convert the graph back to polygons, we arrive at the final result in diagram &lt;strong&gt;&lt;em&gt;h&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The point is moved, there are no gaps, everything is in place. Moreover, we can always turn the map back into a graph, modify it somehow, and then reassemble the map into new modified polygons. So the approach turned out to be flexible and good, and our problem—close points—disappeared as an issue after I easily eliminated them in the graph representation of the map:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fzm%2Fwi%2Fn9%2Fzmwin95p7bh_lpl8zsmifgawi4i.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fzm%2Fwi%2Fn9%2Fzmwin95p7bh_lpl8zsmifgawi4i.jpeg" alt="Final Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Biomes Coloring
&lt;/h2&gt;

&lt;p&gt;We had to merge adjacent polygons if they belonged to the same biome type. In principle, the procedure is not complicated: you remove the neighboring border of two polygons and merge them into one large polygon.&lt;/p&gt;

&lt;p&gt;However, I didn't want to merge anything unnecessarily because it comes with risks. Initially, I randomly assigned each polygon a certain biome type. Often, the &lt;em&gt;unpredictable randomness&lt;/em&gt; clustered large areas of the same biome together, and after merging, you could observe how vast areas of the map became homogeneous behemoth biomes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fz9%2Fex%2Fkn%2Fz9exkn8afxedg-qoyfjz1ueat1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fz9%2Fex%2Fkn%2Fz9exkn8afxedg-qoyfjz1ueat1o.png" alt="Random Biomes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It killed the fun, broke the map's ecosystem, and spoiled its aesthetics and appearance. It was necessary to distribute biome types to polygons in a more neat way.&lt;/p&gt;

&lt;p&gt;Essentially, it all boiled down to the problem of &lt;a href="https://en.wikipedia.org/wiki/Four_color_theorem" rel="noopener noreferrer"&gt;map coloring&lt;/a&gt;. However, the four-color theorem makes it clear that, in general, you can't color a map with &lt;em&gt;three&lt;/em&gt; colors in such a way that neighbors are unique. It requires at least four colors or more. Thus, our maps with 3-5 types of biomes had no opportunity for a foolproof and sensible coloring. All that was left was to try and color the map with as much diversity among neighbors as it really possible within circumstances.&lt;/p&gt;

&lt;p&gt;I asked for help from ChatGPT for an appropriate algorithm. It suggested a simple and straightforward solution based on a heuristic like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Color ourselves.&lt;/li&gt;
&lt;li&gt;Color uncolored neighbors, trying not to repeat biomes.&lt;/li&gt;
&lt;li&gt;If, at some point, we get stuck and neighbors are duplicated, we can try to roll back one step and assign a different color to the previous polygon, then attempt to recolor all its neighbors.&lt;/li&gt;
&lt;li&gt;If desired, the number of rollbacks can be increased if you can afford to store more temporary information.&lt;/li&gt;
&lt;li&gt;Repeat until finished.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ChatGPT has provided me with code, which seemed to work, which is generally not guaranteed with ChatGPT—it was quite the little win. Of course, sometimes the map ended up with identical neighbors. In that case, we simply had to merge them, but these were isolated cases that did not harm the overall appearance of the generated map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normal Random
&lt;/h2&gt;

&lt;p&gt;Here is where the real "fun" begins because the concept of "normal random" is vague and subject to discussion. I wanted more precise formulations from Ilya—something expressed in exact numbers. However, it wasn't simple because while we might have a rough mental image of how trees should be placed on the edge of a forest, translating that into numerical parameters isn't straightforward.&lt;/p&gt;

&lt;p&gt;We settled on creating tables for each map that described the distribution of items in each biome. For example, here's a table for a forest map:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7l9yyme8bur279t55fj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7l9yyme8bur279t55fj.png" alt="Distributions table for a forest map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, it's in layman's terms, vague, without formulas or an abundance of numbers, but it was a starting point. With this information, I found it easier to come up with ways to generate various items according to my preferences and understanding.&lt;/p&gt;

&lt;p&gt;I won't force you to scrutinize the table seriously and understand every detail. For our further discussion, it's enough to know that the distribution of items on the map is divided into two fundamentally different approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Individual items generation.&lt;/strong&gt; A certain quantity of items should be generated for the entire biome (sometimes even for the entire map), sometimes within an acceptable range, and sometimes with specific individual conditions. For example, generating one sword stuck in the ground for the entire map with a 50% chance of appearing in either the stone or earth biome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Item clusters generation.&lt;/strong&gt; This concerns the density of item distribution on a biome and the nature of this distribution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the first type of generation is straightforward—you just take and generate items according to the rules dictated by the item—generating the second type of items was unclear for me. I had to thinking hard again.&lt;/p&gt;

&lt;p&gt;We will consider cluster generation using forest as an example, as it is the most illustrative example. If we master the generation of forests, groves, and clearings with different characteristics, we essentially master cluster generation thoroughly, as a realistically (to the extent possible in a stylized 2D game) generated forest is, in my opinion, the most visually demanding stuff.&lt;/p&gt;

&lt;p&gt;The first thing that comes to mind for anyone who has ever developed games is &lt;a href="https://en.wikipedia.org/wiki/Perlin_noise" rel="noopener noreferrer"&gt;Perlin noise&lt;/a&gt;. It is used to generate various random 2D elements that look natural and smooth: clouds, special effects, patterns, and even entire maps and islands. While Perlin noise was not useful for the main map generation, as we saw, due to our fundamentally different approach with Voronoi, Manhattan, and the like, it is quite useful for generating forests.&lt;/p&gt;

&lt;p&gt;Perlin noise looks like a blurry ink blot in shades of gray:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fm4%2F1o%2F2j%2Fm41o2j-nrqz9dc_-gud40ks-4eq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fm4%2F1o%2F2j%2Fm41o2j-nrqz9dc_-gud40ks-4eq.png" alt="Perlin Noise"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perlin noise is an infinite canvas in 2D space. The image above shows only a small part of it. This infinite image is sufficient to cover the entire map if necessary. The nature of the noise can look entirely different if generated with different parameters.&lt;/p&gt;

&lt;p&gt;Let's say that absolutely black on this image is 0.0, and absolutely white is 1.0. Other pixels of the image lie in the range (0.0; 1.0). A typical way to work with these numbers is to turn this noise image into binary black-and-white, introducing a threshold and turning each pixel of Perlin noise into 0.0 where the noise value is below the threshold, and into 1.0 where the value is above or equal to the threshold. The image below shows binary versions of the previously shown Perlin noise with different threshold values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffj%2Fun%2Fyi%2Ffjunyiwjb5eoyhr9evwgh4c9bzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffj%2Fun%2Fyi%2Ffjunyiwjb5eoyhr9evwgh4c9bzg.png" alt="Applying Different Thresholds to Perlin Noise"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, imagine that where it's white, there should be a forest trees. At a threshold of 0.75, this would resemble rare clusters of tree groupings, while at 0.25, it would become an impassable forest with some rare clear spots.&lt;/p&gt;

&lt;p&gt;Sounds good, but there's a problem. In areas where it's white, where there should be a forest, how frequently should trees be planted? Definitely not with a density of one pixel, right? That would be absurd. I assure you in that, as a person who decided to perform a quick experiment and scatter trees based on the noise with a density of 10 pixels (not even 1!), just for fun. Just wait for ten damned minutes on a powerful PC with 60 GB of RAM occupied by the game process, and one biome with hyper-dense planting is ready to use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fvl%2Fb_%2Fc_%2Fvlb_c_iy0wg0exfpufyc5-ak3ka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fvl%2Fb_%2Fc_%2Fvlb_c_iy0wg0exfpufyc5-ak3ka.png" alt="OMG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ugly, slow, expensive, and meaningless. What to do then? There is a feeling that the noise doesn't provide all the information on how to carry out scattering. The capabilities of Perlin noise end here. The density of planting needs to be adjusted and calculated with additional solution.&lt;/p&gt;

&lt;p&gt;I needed a way to do what some game engines allow artists to do—&lt;a href="https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/Foliage/" rel="noopener noreferrer"&gt;paint objects onto terrain&lt;/a&gt;. You create a brushstroke, and objects are scattered on the terrain with a specified density. In my case I didn't need a brush, but I needed the principle itself.&lt;/p&gt;

&lt;p&gt;I went back to ChatGPT for advice, and it told me that if I needed to place objects seemingly randomly but with uniform density, with each object spaced approximately equally from others, then the Bridson algorithm would suit me. This algorithm is a variation of the well-known Poisson disk sampling algorithm. You can read about both algorithms in &lt;a href="https://sighack.com/post/poisson-disk-sampling-bridsons-algorithm" rel="noopener noreferrer"&gt;this excellent article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the end, I achieved a symbiosis of a Perlin noise, which determined the geometry and planting pattern, and the Bridson algorithm, which regulated the density of this planting.&lt;/p&gt;

&lt;p&gt;You can play with the settings of this mechanism endlessly; it is very flexible and produces completely different results.&lt;/p&gt;

&lt;p&gt;Forest with medium density, forming an arch path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F4c%2F7s%2F6g%2F4c7s6gnght2bp8rdui0szcoz8-i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2F4c%2F7s%2F6g%2F4c7s6gnght2bp8rdui0szcoz8-i.png" alt="Forest with medium density, forming an arch path"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Small dense clusters:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fh3%2F2w%2Fmh%2Fh32wmhk-vz9gsp_cejci2k2cjnm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fh3%2F2w%2Fmh%2Fh32wmhk-vz9gsp_cejci2k2cjnm.jpeg" alt="Small dense clusters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hyper-dense clusters:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fvq%2Fu4%2F8u%2Fvqu48uox1ylzxqxcjlduol9ov-4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fvq%2Fu4%2F8u%2Fvqu48uox1ylzxqxcjlduol9ov-4.jpeg" alt="Hyper-dense clusters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Evenly sparse forest:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fe6%2Fy1%2Fyh%2Fe6y1yhxngazdujrgt1htm5jl1qg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fe6%2Fy1%2Fyh%2Fe6y1yhxngazdujrgt1htm5jl1qg.jpeg" alt="Evenly sparse forest"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here's how we configured the distribution of trees and spikes on the mountain map—rare clusters of trees in bunches:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbb%2F86%2Fji%2Fbb86jiktlrdf75nj5nmk3gvtvwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fbb%2F86%2Fji%2Fbb86jiktlrdf75nj5nmk3gvtvwc.png" alt="Scattering on a mountain map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What Happened Next
&lt;/h1&gt;

&lt;p&gt;We had many plans ahead: map modifications, additional features. However, we decided to take a break and dig into other mechanics: inventory, crafting systems, and more.&lt;/p&gt;

&lt;p&gt;After some time, we realized that we took on too much and found it challenging and uninteresting. We were stuck in this project, and it began to feel like a second job, demanding a lot of time and providing minimal enjoyment. Therefore, we decided not to continue. Instead, we started working on another game, but that's a different story.&lt;/p&gt;

&lt;p&gt;That's how the article unexpectedly ends, unfortunately. Maybe the day will come, and we will return back to the project with fresh strengths and ideas.&lt;/p&gt;

&lt;h1&gt;
  
  
  Algorithms Recap
&lt;/h1&gt;

&lt;p&gt;Let's retrospect through all the steps to obtain our map with biomes. If you are reading this article because you are working on something similar and came here for ideas, this section will help you gather all the information dumped on you in the article.&lt;/p&gt;

&lt;p&gt;On the Godot side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set global map parameters: desired size, approximate number of biomes, types of biomes to be present on the map.&lt;/li&gt;
&lt;li&gt;Generate random points across the entire expected map area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, with the points in hand, we dive into C++ code, where we perform computationally expensive calculations for generating map polygons.&lt;/p&gt;

&lt;p&gt;In C++:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Based on points, create the Voronoi map.&lt;/li&gt;
&lt;li&gt;Obtain a list of polygons from the Voronoi map.&lt;/li&gt;
&lt;li&gt;Create a graph from the points for intermediate optimizations.&lt;/li&gt;
&lt;li&gt;Remove points that are too close on the graph.&lt;/li&gt;
&lt;li&gt;Transform the graph back into polygons.&lt;/li&gt;
&lt;li&gt;Calculate neighbors for each polygon.&lt;/li&gt;
&lt;li&gt;Assign a biome type to each polygon, trying to minimize the neighbouring of identical biomes.&lt;/li&gt;
&lt;li&gt;Merge polygons with identical biomes that are neighbors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting set of polygons is returned to GDScript, where we handle their visual representation.&lt;/p&gt;

&lt;p&gt;Back to Godot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render each polygon, texture it according to its biome type.&lt;/li&gt;
&lt;li&gt;Render polygon borders with a shader featuring grass.&lt;/li&gt;
&lt;li&gt;Identify all islands on the map.&lt;/li&gt;
&lt;li&gt;For islands, find their perimeter and draw each perimeter with a thick line.&lt;/li&gt;
&lt;li&gt;Render a thickness slice for each island.&lt;/li&gt;
&lt;li&gt;Generate collision for each island so the character cannot go beyond its boundaries.&lt;/li&gt;
&lt;li&gt;Populate each biome with foliage according to your density tables. Here, I must mention that for the points distribution using the Bridson algorithm, we again dive into C++ code to calculate the distribution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a bonus and a tribute to the project, let's return to my drafts as an evidence of my hard work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fj9%2Faq%2F9s%2Fj9aq9s1na_gj-a3g0ikzvmnxypc.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fj9%2Faq%2F9s%2Fj9aq9s1na_gj-a3g0ikzvmnxypc.jpeg" alt="It's hard 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Performance
&lt;/h1&gt;

&lt;p&gt;What about performance?—you may ask. Actually, it's very, very good. Here's a gif at the original playback speed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffz%2F5p%2Fd7%2Ffz5pd72yqsbfyudflhum4ylzscg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffz%2F5p%2Fd7%2Ffz5pd72yqsbfyudflhum4ylzscg.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated world has average dimensions of 20,000 by 20,000 pixels, and it is generated from scratch in an instant with a single button press. In the gif, I just repeatedly press the spacebar—faster and faster. If I wrote all the code in GDScript, I assure you the results would be much, much worse.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;Why was this article written at all?&lt;/p&gt;

&lt;p&gt;I think our experience could be helpful to someone—to those who just want to start making a game, those who have already begun it and are looking info towards random map generation or something alike. In the end, to those who want to know what tasks a programmer might face, what difficulties might arise, and how to solve or avoid them.&lt;/p&gt;

&lt;p&gt;To some extent, the article was needed for myself as well—to refresh, structure, and rethink the experience, code, and algorithms gained during development, which will undoubtedly be useful to me in the future.&lt;/p&gt;

&lt;p&gt;Once again, it emphasizes a well-known truth—even the simplest indie game is hard. A game with random generation is hard squared. Making games is not always fun. But in the process of their development, you gain experience that you can't get anywhere else. Even if the project fades or fails, your experience remains with you, and in the future, you can apply it to projects that lie ahead. Or write a retrospective article, as I did.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>gamedev</category>
      <category>math</category>
      <category>godot</category>
    </item>
  </channel>
</rss>
