<?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: Sebastian Nozzi</title>
    <description>The latest articles on DEV Community by Sebastian Nozzi (@sebnozzi).</description>
    <link>https://dev.to/sebnozzi</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%2F100638%2F96e1dd09-b85a-4d8b-aa3c-011a68a90cd6.jpg</url>
      <title>DEV Community: Sebastian Nozzi</title>
      <link>https://dev.to/sebnozzi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebnozzi"/>
    <language>en</language>
    <item>
      <title>Bad and good onboarding</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Fri, 26 Dec 2025 15:00:28 +0000</pubDate>
      <link>https://dev.to/sebnozzi/bad-and-good-onboarding-9bd</link>
      <guid>https://dev.to/sebnozzi/bad-and-good-onboarding-9bd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"The alternative to good design is always bad design. There is no such thing as no design." &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adam Judge, author of design books&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same way bad design is the alternative to good design, the alternative to good onboarding is &lt;strong&gt;bad onboarding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Bad onboarding processes happen not as a result of poor planning, but often because the process is &lt;strong&gt;neglected&lt;/strong&gt; altogether.&lt;/p&gt;

&lt;p&gt;The problem is, again, a matter of subjective perspective. The existing project members &lt;em&gt;are&lt;/em&gt; already onboarded, and especially the most senior ones have seen the project emerge from the beginning. They know all the details and intricacies inside and out. Additionally they have been immersed for a long time in everyday details and problems. Inevitably, they lose the perspective of the newcomer, of the one that stands before the system for the first time, and tries to figure out how everything fits together.&lt;/p&gt;

&lt;p&gt;It is not due to bad intentions, it is because they now are in a different position. Drastically different position from a newcomer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad Onboarding
&lt;/h2&gt;

&lt;p&gt;If "onboarding" as such is not considered as a necessary process, then it happens by accident. Newcomers are given some minimal details to get started and are asked to figure the rest out. Learning-by-doing. Or "learning-on-the-job". "Do tell if you get stuck" and "if something is missing from the (outdated and/or poorly written) documentation feel free to improve on it".&lt;/p&gt;

&lt;p&gt;Potential problems I see with these requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Newcomers don't know what they don't know. Often they do not know if something is not working because something is not working, or they did something wrong. Additionally, if a clear plan is missing, they don't know if they now know "enough".&lt;/li&gt;
&lt;li&gt;Newcomers often want to cause a good impression and prefer to solve their challenges on their own before asking for help (because the seniors are so important and seem to have better things to do).&lt;/li&gt;
&lt;li&gt;Newcomers might lack the insight and/or expertise to complete the documentation in a meaningful way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is an "onboarding" process that is erratic, accidental, full of traps and frustrations, and take longer than need to be.&lt;/p&gt;

&lt;p&gt;What would a good onboarding process look like?&lt;/p&gt;

&lt;h2&gt;
  
  
  Good Onboarding
&lt;/h2&gt;

&lt;p&gt;A good onboarding process, in my view, consists of a clear roadmap and is a mixture of good documentation and automation. My motto here goes: automation where you can, documentation where you must.&lt;/p&gt;

&lt;p&gt;First, the roadmap: it consists of a clear, finite, non open-ended, easy to understand, non-overwhelming list of things to do. &lt;/p&gt;

&lt;p&gt;The "things to achieve" consist of things to read or "do". &lt;/p&gt;

&lt;p&gt;The things to "do" can either be done automatically (preferred) or manually. If they are to be done manually, see point "reading".&lt;/p&gt;

&lt;p&gt;The things to "read" either give you insight about key aspects of the project (setup, architecture, codebase, etc.) or how to achieve things to "do" which could not be automated.&lt;/p&gt;

&lt;p&gt;But how to achieve "good onboarding" if everyone is so busy?&lt;/p&gt;

&lt;h2&gt;
  
  
  Achieving Good Onboarding
&lt;/h2&gt;

&lt;p&gt;First, it needs to be recognized as something necessary. Something that, if done right, will save the company real money (by having the newcomer produce results earlier instead of still struggling longer than necessary).&lt;/p&gt;

&lt;p&gt;Second, in my view it is a process that need to be "owned" by somebody in the team. It cannot be left to chance or the goodwill of the "group".&lt;/p&gt;

&lt;p&gt;Natural candidate for this is of course the project manager, but it can be delegated to a senior developer or technical lead.&lt;/p&gt;

&lt;p&gt;At each important feature development or architectural change (latest in a sprint-review) it needs to be discussed if there was an onboarding-relevant change. Then the onboarding documents and processes need to be revisited accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;If done iteratively, if owned, and if kept in check, this approach should minimize (ideally eliminate, but "minimize" is a good-enough outcome) onboarding friction.&lt;/p&gt;

&lt;p&gt;Newcomers to the project would feel empowered, welcomed and cared-for, and the momentum gained during the onboarding process would carry to the first feature developments.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>onboarding</category>
      <category>engineering</category>
      <category>culture</category>
    </item>
    <item>
      <title>Dreams of a Mini Micro machine</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Sat, 25 Oct 2025 10:11:58 +0000</pubDate>
      <link>https://dev.to/sebnozzi/dreams-of-a-mini-micro-machine-3igo</link>
      <guid>https://dev.to/sebnozzi/dreams-of-a-mini-micro-machine-3igo</guid>
      <description>&lt;p&gt;In my previous post I explained the reasons why I like Mini Micro so much, being (for me) the right combination between simplicity and power.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5u0x4qj8psqssscq9bu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5u0x4qj8psqssscq9bu6.png" alt="Platformer on Mini Micro" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But something still does not feel right when I code in Mini Micro. And it is not related to Mini Micro itself but rather to "everything else". And that while coding in Mini Micro &lt;em&gt;can&lt;/em&gt; be an immersive experience, especially when on "full-screen", my head still knows the truth: everything else &lt;strong&gt;still exists&lt;/strong&gt;. The distraction-filled complex apps and operating systems, with notifications, YouTube, tons of buttons, windows and what-not, is an Alt-Tab away. Sometimes it is very convenient (e.g. looking for information while coding, downloading some image I need for a project) but other times &lt;em&gt;knowing&lt;/em&gt; that these things are still there, very near, kills part of the experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fy5dktfz2fkbgn0goif0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fy5dktfz2fkbgn0goif0d.png" alt="Mini Micro and distracting applications" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is the same feeling I get when wanting to be in nature, walking from the streets into the near-by woods and pretending to be lost in nature, only to hear a loud helicopter passing by, or still hear the roar of the cars in a near-distant highway, or still see part of the city if there happens to be an opening between the trees. Not the same.&lt;/p&gt;

&lt;p&gt;You want to be "free", to get "away", but the escape is not real.&lt;/p&gt;

&lt;p&gt;That got me thinking: wouldn't it be great to have a machine where something Mini Micro (or something similar) would run exclusively? With no distraction, no other apps, windows, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fnzew1hxnek64hgwh94l7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnzew1hxnek64hgwh94l7.png" alt="Fenix neo-retro computer" width="768" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In my ideal world, Mini Micro would run on something like this ...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some consideration I came to the conclusion that the most practical way to do this would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have have a Linux installation (Mini Micro runs also on Linux)&lt;/li&gt;
&lt;li&gt;Have a dedicated user. Log-in automatically.&lt;/li&gt;
&lt;li&gt;Start Mini Micro in full-screen as an "X" application.&lt;/li&gt;
&lt;li&gt;No desktop-environment. No other apps.&lt;/li&gt;
&lt;li&gt;Nothing Alt-Tab could lead you to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recently I tried some of the steps necessary for this on an already existing Linux installation. I tried the "start Mini Micro full-screen" part.&lt;/p&gt;

&lt;p&gt;For that I created another user, logged in to the console, and tried to start Mini Micro directly with "startx". Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startx MiniMicro.x64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would start Mini Micro directly as an "X" app, without even a window-manager. But it would not work properly: I was not be able to type anything, and there was no mouse cursor!&lt;/p&gt;

&lt;p&gt;To this day I don't know why, but it seems that Mini Micro, which is based on Unity, is not so "X" friendly out of the box. Firefox worked "fine", but not so Mini Micro.&lt;/p&gt;

&lt;p&gt;While trying to find a solution to this I kept reading again and again that this kind of thing should be done through a window-manager, not directly. &lt;/p&gt;

&lt;p&gt;I was not entirely happy, I did not want to be able to Alt-Tab to anywhere! Not even a window-manager.&lt;/p&gt;

&lt;p&gt;Still, I decided to try. At least to see if it would work.&lt;/p&gt;

&lt;p&gt;I worked fine with openbox, but I was still able to alt-tab back to it. But at least I knew that I needed a window-manager to make keyboard and mouse-support work.&lt;/p&gt;

&lt;p&gt;Fortunately for me I came across a very minimalistic window-manager perfectly suited for my needs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/astier/xswm" rel="noopener noreferrer"&gt;https://github.com/astier/xswm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;xswm is a minimal stacking and non-reparenting window-manager for X with only one task. Open every window maximized. Zero configuration required. Due to its limited scope it is very minimal and performant (~550 SLOC). No built-in:&lt;/p&gt;

&lt;p&gt;Hotkeys&lt;br&gt;
Notifications&lt;br&gt;
Statusbar&lt;br&gt;
Window-Decorations&lt;br&gt;
Window-Switcher&lt;br&gt;
etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was like a godsend.&lt;/p&gt;

&lt;p&gt;It requires you to compile it yourself, but it is extremely simple. Just "make" and that's it (it requires "sudo make" for it to install to a system-wide location; the "libX11" headers and of course a C-compiler have to be installed).&lt;/p&gt;

&lt;p&gt;This simple window-manager would be started with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startx xswm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon starting it looks for an "autostart.sh" script in the location "$XDG_CONFIG_HOME/autostart.sh". Problem for me was that the "XDG_CONFIG_HOME" environment variable was not set.&lt;/p&gt;

&lt;p&gt;I created a launch script to set the variable and perform the "startx xswm" command. &lt;/p&gt;

&lt;p&gt;Now it worked! Keyboard, mouse, and nowhere to run to. No alt-tab, no windows menu, not even alt-ctrl-backspace working (which usually is used to kill your X session). I was happy.&lt;/p&gt;

&lt;p&gt;But a couple of things still bothered me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;startx was writing a lot of noise to the console&lt;/li&gt;
&lt;li&gt;In the X session, before Mini Micro was loaded (which took a couple of seconds) for some reason a "xterm" window would open. There the Mini Micro (or rather Unity) output / noise would be visible, and only &lt;em&gt;then&lt;/em&gt; Mini Micro would take over the uglyness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I redirected all output both from "startx" and the "autostart.sh" scripts to oblivion ("/dev/null"). Still, the maximized and undecorated, but sill present xterm window would open and be visible for some seconds.&lt;/p&gt;

&lt;p&gt;It seemed I had to live with it. But as the saying goes: when life gives you lemons, make lemonade. So, I adapted my autostart-script to write "Loading Mini Micro ...".&lt;/p&gt;

&lt;p&gt;Now the xterm window, and the delay, served a noble purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future work
&lt;/h2&gt;

&lt;p&gt;In the future I would like to have a dedicated Linux installation which would boot directly to Mini Micro (my experiment was tried in a parallel virtual console, the whole desktop-environment still living on tty7). I will try this first on an emulator before committing to real hardware.&lt;/p&gt;

&lt;p&gt;Getting rid / hiding the initial xterm window would also be great, if possible.&lt;/p&gt;

&lt;p&gt;If everything goes well I would like this setup to be reproducible for others. I would like to publish these steps. Not sure how yet. Vagrant? Image? Linux-distro? Instructions?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Anyway, I am now one step further pretending to have a machine where Mini Micro is THE operating system. My creativity-driven inner-child and simplicity-yearning adult are both happy.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>minimicro</category>
      <category>retro</category>
      <category>linux</category>
    </item>
    <item>
      <title>Why Mini Micro</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Sat, 25 Oct 2025 09:29:02 +0000</pubDate>
      <link>https://dev.to/sebnozzi/why-mini-micro-4a1o</link>
      <guid>https://dev.to/sebnozzi/why-mini-micro-4a1o</guid>
      <description>&lt;p&gt;As many people today I miss the simplicity of earlier times.&lt;/p&gt;

&lt;p&gt;True, many things are easier today, more accessible and more powerful. On the other hand, in some areas the price to pay is complexity. Or one could say: too many choices.&lt;/p&gt;

&lt;p&gt;The computing experience is no exception.&lt;/p&gt;

&lt;p&gt;In contrast to today's computers, computers in the 80's were refreshingly simple. You turned it on, and you were in the middle of a BASIC prompt, in which you could type in some program. Graphics were simpler. Games were simpler. Everything was simpler, but no less intriguing and "magical".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvjb6qad07lxfujv4gi3g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvjb6qad07lxfujv4gi3g.jpg" alt="C64 picture" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(image from &lt;a href="https://www.blendernation.com/2020/12/11/behind-the-scenes-commodore-64-nostalgia/" rel="noopener noreferrer"&gt;https://www.blendernation.com/2020/12/11/behind-the-scenes-commodore-64-nostalgia/&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The experience seemed more approachable and direct. The computer felt really "personal". It really felt like a "dialogue", an interaction, between two parts. Transparent. Without distractions.&lt;/p&gt;

&lt;p&gt;We should not fool ourselves however. While at that time it felt "magical" to print some strings (even colored ones) on the screen or, if I was lucky, be able to plot some lines or circles on the screen, the BASIC interpreters of that era were not particularly "powerful". There was a limit, both in terms of performance and capabilities, of what you could do in BASIC.&lt;/p&gt;

&lt;p&gt;Since I was too young and too unaware, I never got into assembly language in the 8-bit computers I had access to (Commodore 16, 64 and an MSX machine). I did not attempt making any serious program for a while until much later in Quick Basic. I remember coding a UFO-shooting game (you would shoot an invading flying saucer which would drop bombs on you) and a painting program. Fond memories.&lt;/p&gt;

&lt;p&gt;Time went by and I tried learning some "serious" languages, like C and C++. Later came HTML, PHP and Java. And later other languages like Ruby, Scala and Python. From DOS I moved (as most of us) to advanced versions of Windows (later to Mac OS and Linux). The world of computing and programming was becoming more powerful, but at the same time more complex, more distracting, and less direct and creative.&lt;/p&gt;

&lt;p&gt;Today it is of course possible make very simple games and animations using PyGame, any JavaScript game library, even game engines like Unity or Godot, or simply in Java (Swing, let's say, or any suitable library). There are a lot of choices, good choices, powerful choices. Too many to list here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fab79hfcugm60dn7ywc5r.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fab79hfcugm60dn7ywc5r.webp" alt="Using Godot" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Image from &lt;a href="https://www.gamingonlinux.com/2023/07/godot-engine-4-1-brings-a-detachable-script-editor-vulkan-pipeline-cache/" rel="noopener noreferrer"&gt;https://www.gamingonlinux.com/2023/07/godot-engine-4-1-brings-a-detachable-script-editor-vulkan-pipeline-cache/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still, the directness and simplicity of earlier days is completely gone.&lt;/p&gt;

&lt;p&gt;It seemed to me that you are either stuck in the powerful but complex languages and environments of today or go the nostalgic "retro" route of coding for retro-platforms. Which give you either the simple but underpowered BASIC interpreters of past decades, or the slightly more powerful but very complex and nuanced world of direct hardware access via assembly (which again is less direct because no sane person would code assembly directly on the host machine).&lt;/p&gt;

&lt;p&gt;If only there was an environment that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rescued the simplicity and directness of the past&lt;/li&gt;
&lt;li&gt;Offered powerful APIs and capabilities at your fingertips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I must not have been the only one feeling this way, and recognizing and unmet need. These environments somehow started emerging. They come in the form of "fantasy computers" or "fantasy consoles".&lt;/p&gt;

&lt;p&gt;After some searching I found the one I felt in love with: the  &lt;a href="https://miniscript.org/MiniMicro/#about" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbc4081bwr8fz6lkdnv7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbc4081bwr8fz6lkdnv7s.png" alt="Mini Micro logo" width="658" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which, I want to state publicly, I consider both a work of love and a work of art.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5u0x4qj8psqssscq9bu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5u0x4qj8psqssscq9bu6.png" alt="Platformer on Mini Micro" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mini Micro for me really rescues the directness and simplicity of earlier (8-bit-era) computers. You interact with it either by typing in commands at a prompt, even trying things out in its &lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;REPL&lt;/a&gt;) or writing your program in the built-in editor (one one program, one file at a time - I mention this as a nice feature and part of the "distraction free" philosophy).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fug4xojayqykz1sh0nnx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fug4xojayqykz1sh0nnx9.png" alt="Mini Micro initial screen" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the other hand it gives you "power" I could not have dreamt of in my young days having an 8-bit computer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A simple yet modern a powerful language. Not BASIC but &lt;a href="https://miniscript.org/" rel="noopener noreferrer"&gt;MiniScript&lt;/a&gt;. MiniScript is in an of itself a work of both art and love. It is what I call "a language that fits in your head". Yet powerful enough to write just about anything you can think of. It deserves its own articles, or series.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built-in editor with the usual features: copy-paste, find/replace, automatic indenting, syntax-highlighting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sprites. Unlimited in amount and size. Rotation, color-tinting and even pseudo-3D transformations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access to drawing primitives. Basic shapes, thickness, colors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A "tile" display like in 8-bit computers but more powerful (no limitations in size or amount of different tiles, for example)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Up to 8 different display "layers", which you can set-up as you want. Display-types can be: sprite, pixel, tile, text and solid-color.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modern sound capabilities. Playing of sampled and FM sounds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to share with others (major platforms and web).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I could go on and on. But you get the picture: simplicity, directness, lack-of-distraction experience of the past with modern capabilities.&lt;/p&gt;

&lt;p&gt;I spent many hours coding &lt;a href="https://github.com/sebnozzi?tab=repositories&amp;amp;q=topic%3Aminimicro&amp;amp;type=&amp;amp;language=&amp;amp;sort=stargazers" rel="noopener noreferrer"&gt;different things&lt;/a&gt; in Mini Micro and I could not be happier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqr4re6o1rewiatr5x9ca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqr4re6o1rewiatr5x9ca.png" alt="Mini Micro projects" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some of my Mini Micro creations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me it is the perfect distraction-free environment for exploring ideas, do "serious" or "casual" coding and, most important: having fun.&lt;/p&gt;

&lt;p&gt;Thanks for reading this far. If you feel like me and want to revive the simplicity of the past without sacrificing "power" I invite you to give &lt;a href="https://miniscript.org/MiniMicro/#about" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt; a try.&lt;/p&gt;

&lt;p&gt;Plus, the community is very welcoming and its creator is a great guy always willing to help.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>minimicro</category>
      <category>retro</category>
      <category>8bit</category>
      <category>pico8</category>
    </item>
    <item>
      <title>Movement-events on Mini Micro (part 1)</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Wed, 01 Oct 2025 22:46:14 +0000</pubDate>
      <link>https://dev.to/sebnozzi/movement-events-on-mini-micro-part-1-3gm7</link>
      <guid>https://dev.to/sebnozzi/movement-events-on-mini-micro-part-1-3gm7</guid>
      <description>&lt;p&gt;In this post I want to share with you different ways to check for (sprite) "movement" events in Mini Micro.&lt;/p&gt;

&lt;p&gt;This is partly inspired by Joe's &lt;a href="https://dev.to/joestrout/comment/2eodp"&gt;comment&lt;/a&gt; at my "Coin Collector" &lt;a href="https://dev.to/sebnozzi/coin-collector-1lh6"&gt;tutorial&lt;/a&gt;. He suggested to use the &lt;code&gt;key.axis&lt;/code&gt; function instead of checking for concrete key-codes (like for the arrow keys).&lt;/p&gt;

&lt;p&gt;First, I want to categorize the firing of "movement events" into two main types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Continuous firing&lt;/li&gt;
&lt;li&gt;Discrete firing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(I came up with these names, apologies if there are more known or accepted names out there).&lt;/p&gt;

&lt;p&gt;"Discrete firing" is when &lt;strong&gt;only one&lt;/strong&gt; movement event is fired when the user presses an arrow key. This will be discussed in a future post. For this post, let's focus on "continuous firing" ...&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous firing
&lt;/h2&gt;

&lt;p&gt;In "continuous firing" the player's object keeps moving in one direction as long as the corresponding arrow-key (or joystick axis) is being pushed.&lt;/p&gt;

&lt;p&gt;The movement only stops when the key is released (or the joystick returns to neutral position).&lt;/p&gt;

&lt;p&gt;An example of one of my projects that I could bring up is the spaceship from my &lt;a href="https://github.com/sebnozzi/minimicro-lettershooter" rel="noopener noreferrer"&gt;"Letter Shooter"&lt;/a&gt; game. It moves with the arrow keys, and keeps moving when a key is being held down.&lt;/p&gt;

&lt;p&gt;A reduced / simplified form would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff1b9p2p8jn7hesqyrgw7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff1b9p2p8jn7hesqyrgw7.gif" alt="Spaceship moving" width="576" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, does one code continuous-firing of movement events in Mini Micro?&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrow-keys
&lt;/h2&gt;

&lt;p&gt;A first version, checking for arrow keys, could look like this:&lt;br&gt;
&lt;/p&gt;

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

while true
    if key.pressed("up") then print "^", ""
    if key.pressed("down") then print "V", ""
    if key.pressed("left") then print "&amp;lt;", ""
    if key.pressed("right") then print "&amp;gt;", ""
    wait 0.01
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(By the way, if you ever need to know the "names" of the keys available for the &lt;code&gt;key.pressed&lt;/code&gt; function, try &lt;code&gt;pprint key.keyNames&lt;/code&gt; on the console).&lt;/p&gt;

&lt;p&gt;Try it! When run, the code will print the corresponding "direction" characters as long as an arrow-key is pressed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv4uhpp2q4dob04z1zxgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv4uhpp2q4dob04z1zxgw.png" alt="Characters showing arrow-key-presses" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A short delay was introduced so that the screen is not filled-up too quickly with characters, making it difficult to see what's going on. Experiment with different values, replacing it with &lt;code&gt;yield&lt;/code&gt; or removing it entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the Spaceship
&lt;/h2&gt;

&lt;p&gt;Let's make the above example more interesting by actually adding the "spaceship" and moving it on the screen:&lt;br&gt;
&lt;/p&gt;

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

// Display 4 is our default sprite-display
sprDisp = display(4)

s = new Sprite
s.image = file.loadImage("/sys/pics/Fighter.png")
// Place on the center of the screen
s.x = 960 / 2
s.y = 640 / 2
// Make it face up, and smaller
s.rotation = 90
s.scale = 0.5

sprDisp.sprites.push s

// Velocity. Spaceship will move this amount of pixels
// for each "key-down" event.
v = 5

while true
    if key.pressed("up") then s.y += v
    if key.pressed("down") then s.y -= v
    if key.pressed("left") then s.x -= v
    if key.pressed("right") then s.x += v
    wait 0.01
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this works, but "only" supports arrow-keys. Personally, this is what I do in most of my projects. But one could generalize this by using the &lt;code&gt;key.axis&lt;/code&gt; function (thanks &lt;a href="https://dev.to/joestrout"&gt;Joe Strout&lt;/a&gt; for &lt;a href="https://dev.to/joestrout/comment/2eodp"&gt;pointing this out&lt;/a&gt;). This would support both arrow-keys and gamepads / joysticks with one codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;key.axis&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://miniscript.org/wiki/Key.axis" rel="noopener noreferrer"&gt;&lt;code&gt;key.axis&lt;/code&gt;&lt;/a&gt; function returns values between -1 and 1 (and typically 0) depending on the state of one of its "axis" (which can be "Horizontal" or "Vertical"). As mentioned, it reacts both to arrow keys and gamepads / joysticks.&lt;/p&gt;

&lt;p&gt;A re-worked while-loop with &lt;code&gt;key.axis&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while true
    if key.axis("Vertical") &amp;gt; 0 then s.y += v
    if key.axis("Vertical") &amp;lt; 0 then s.y -= v
    if key.axis("Horizontal") &amp;lt; 0 then s.x -= v
    if key.axis("Horizontal") &amp;gt; 0 then s.x += v
    wait 0.01
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Factor to velocity
&lt;/h2&gt;

&lt;p&gt;While trying things out for this post there is something I noticed. When exploring the returned values of &lt;code&gt;key.axis&lt;/code&gt;, it does not just return -1 or 1. Even when using arrow keys. It also returns values &lt;em&gt;in-between&lt;/em&gt; when the firing is "starting" to take place. As if "warming up". This nicely simulates a gamepad / joystick slowing leaving the neutral position while reaching one of the extremes of a direction (going all the way "left" or "up").&lt;/p&gt;

&lt;p&gt;This code snippet showcases this fact:&lt;br&gt;
&lt;/p&gt;

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

while true
    vAxis = key.axis("Vertical")
    hAxis = key.axis("Horizontal")
        // Only print if any of the values is not 0
    if vAxis or hAxis then 
        print "V:" + vAxis + " - H:" + hAxis
    end if
    wait 0.02
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Armed with this information, one could further adapt the spaceship-movement example to use the axis-values as "factors" (in a multiplication) to the velocity. And while we are at it, let's replace our &lt;code&gt;wait&lt;/code&gt; with a &lt;code&gt;yield&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our while-loop would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while true
    vAxis = key.axis("Vertical")
    hAxis = key.axis("Horizontal")
    s.x += hAxis * v
    s.y += vAxis * v
    yield
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how we don't need "ifs" anymore. Just take the current values, multiply and add to the current position (of course multiplying by 0 results in 0, and adding 0 to current coordinates does nothing).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhp1nhn0k6fowx3892c3a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhp1nhn0k6fowx3892c3a.gif" alt="Spaceship moving" width="576" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The change in movement is subtle. You should notice the space-ship slowly starting to move in one direction and the acquiring constant speed. Nice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This post showed how to detect movement-firing events "continuously" and also how to apply that information to moving a sprite.&lt;/p&gt;

&lt;p&gt;In a further post we will talk about "discrete" movement-events and see some applications.&lt;/p&gt;

&lt;p&gt;Have fun with Mini Micro!&lt;/p&gt;

</description>
      <category>minimicro</category>
      <category>miniscript</category>
      <category>gamedev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Codebase Onboarding Documentation</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Fri, 02 May 2025 21:53:57 +0000</pubDate>
      <link>https://dev.to/sebnozzi/codebase-onboarding-documentation-4e0d</link>
      <guid>https://dev.to/sebnozzi/codebase-onboarding-documentation-4e0d</guid>
      <description>&lt;p&gt;I've often faced the problem of getting familiar with existing big, complex, codebases.&lt;/p&gt;

&lt;p&gt;The size and complexity seem insurmountable, it is not clear how things work and are related to each other, one does not know where to start learning and getting clarity.&lt;/p&gt;

&lt;p&gt;Some projects have at best a README file, and maybe one or two additional files. Others have a Wiki, but often talking about conceptual aspects and therefor don't help so much in understanding the code itself.&lt;/p&gt;

&lt;p&gt;More often than not, code is poorly documented, if documented at all. Even if individual methods or classes &lt;em&gt;are&lt;/em&gt; documented, it does not always help in understanding the "big picture" and knowing how everything fits together.&lt;/p&gt;

&lt;p&gt;This situation, together with the accompanying frustration, lead me to look for solutions. One of them very extreme.&lt;/p&gt;

&lt;p&gt;Enter ...&lt;/p&gt;

&lt;h2&gt;
  
  
  Literate Programming
&lt;/h2&gt;

&lt;p&gt;What if we were doing the whole thing &lt;a href="https://youtu.be/Av0PQDVTP4A?si=4ZHazeVj8CFlM6-t&amp;amp;t=15" rel="noopener noreferrer"&gt;wrong&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;When I initially read about &lt;a href="http://www.literateprogramming.com/" rel="noopener noreferrer"&gt;literate programming&lt;/a&gt; I was hooked. I thought: this is it!&lt;/p&gt;

&lt;p&gt;For those unfamiliar with it, the idea of literate programming is that you don't start with code, which you then "document". &lt;/p&gt;

&lt;p&gt;You start with a "document" through which you explain your program, one code-snippet at a time. That document takes the form of a complex book, with pages and chapters. The code-snippets themselves, which are initially part of the document, are inter-related themselves.&lt;/p&gt;

&lt;p&gt;Then, you run a typical "literate programming" tool, which does two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It produces a beautiful, pleasant to read document (often as a PDF or a webpage, together with images, fonts, table of contents, links and so on).&lt;/li&gt;
&lt;li&gt;It assembles your final codebase from the inter-related snippets. After that, you are free to compile your code to produce your executable, or whatever deliverable your code produces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strength of this approach is that you, as the "book author" can decide what to explain &lt;em&gt;when&lt;/em&gt;. Our programming languages and frameworks often dictate how files and folders are to be structured in a codebase. But if you start with a document, you are free to introduce "files" and code-snippets in any order you want. &lt;/p&gt;

&lt;p&gt;I could talk more about this approach, but I will end this for now.&lt;/p&gt;

&lt;p&gt;Suffice to say that, while the approach seems to have many advantages, and be a good fit to my "onboarding problem", it does impose big sacrifices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One can kiss our familiar tool-integration (IDEs) goodbye&lt;/li&gt;
&lt;li&gt;Refactoring becomes much harder&lt;/li&gt;
&lt;li&gt;Code navigation becomes much harder&lt;/li&gt;
&lt;li&gt;Maintenance becomes harder / slower (maybe a good thing?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Realistically, I could not imagine this being the ultimate solution. I must admit that I never seriously tried it on a big project, and maybe I should. But the cost-benefit outcome did not seem quite right to me.&lt;/p&gt;

&lt;p&gt;Nevertheless, the spirit of the approach seemed good, and it contained good ideas and noble goals.&lt;/p&gt;

&lt;p&gt;What if there was an hybrid approach, or something inspired by it ...?&lt;/p&gt;

&lt;p&gt;I think I found an approach that might be just that ...&lt;/p&gt;

&lt;h2&gt;
  
  
  What about Wikis?
&lt;/h2&gt;

&lt;p&gt;Earlier I mentioned that some projects do contain Wikis.&lt;/p&gt;

&lt;p&gt;The nice thing about Wikis is that they are easy to use. Documents are "cheap". Creating new pages is easy. Editing existing pages is easy. Especially if one is using Markdown.&lt;/p&gt;

&lt;p&gt;But I didn't like the fact that most Wikis "live" separate from the codebase.&lt;/p&gt;

&lt;p&gt;What I wanted is to navigate a codebase, and have a series of documents, IN the codebase, telling me about important aspects of the code I was dealing with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local "Wikis"?
&lt;/h2&gt;

&lt;p&gt;At some point I became aware of a "trick" (is it really) that some open-source projects &lt;em&gt;sometimes&lt;/em&gt; use: interlinking of Markdown documents.&lt;/p&gt;

&lt;p&gt;Typical examples would be having a "README.md" file, and have it link to a "LICENCE.txt" file or a "Contributing.md" or "Installation.md" files, and so on ...&lt;/p&gt;

&lt;p&gt;The linking per-se is part of the equation, however. The viewing environment at hand is the one which has to honor the links, and make the navigation possible. Fortunately, both GitHub (the webpage) and &lt;del&gt;IDEs&lt;/del&gt; code editors like VSCode support this feature.&lt;/p&gt;

&lt;p&gt;Armed with this knowledge I had this idea: one could strategically put Markdown files in the appropriate places and have them linked. One could navigate them from within a code-editor (or repo viewer like GitHub) and they would provide context-sensitive meta-information. &lt;/p&gt;

&lt;p&gt;Think for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documenting the deployment process&lt;/li&gt;
&lt;li&gt;Documenting installation&lt;/li&gt;
&lt;li&gt;Documenting architecture&lt;/li&gt;
&lt;li&gt;Documenting packages / modules / subprojects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think it's a worthy idea. And for some projects I would use it as is. But I still was missing something lost from the "literate programming" approach.&lt;/p&gt;

&lt;p&gt;I was missing "beauty".&lt;/p&gt;

&lt;h2&gt;
  
  
  In search of Beauty Lost
&lt;/h2&gt;

&lt;p&gt;Let's go back in time to my experiments with "literate programming". &lt;/p&gt;

&lt;p&gt;Remember that I previously mentioned one of the outputs, apart from the resulting codebase, was "beautiful content"?&lt;/p&gt;

&lt;p&gt;But what do I mean by "beautiful"? What I mean is "more than just plain text". Think: different font styles, images, diagrams, colors, footnotes, admonitions, table-of-contents, etc. Things we are used to from (technical) books, documentation and webpages. Markdown (if rendered beyond its plain-text version) does support some of that, but not all ...&lt;/p&gt;

&lt;p&gt;When first conceived, the first "literate programming" tools used have LaTeX as its content-generation language. That is: the produced document was LaTeX-based, with all that it implies (personal summary: very powerful features, not so friendly to write, geared more towards print media, especially academic papers).&lt;/p&gt;

&lt;p&gt;But when exploring "literate programming", my idea of the final document was never a PDF or LaTeX file, but a webpage. More specifically a modern, navigable online documentation. That is: HTML based.&lt;/p&gt;

&lt;p&gt;One tool for producing HTML-based technical documentation is &lt;a href="https://www.sphinx-doc.org" rel="noopener noreferrer"&gt;Sphinx&lt;/a&gt;. It originates and is very widespread in the Python world, but can be used for whatever purpose one sees fit.&lt;/p&gt;

&lt;p&gt;Fortunately I found out that there have been "literate programming" extensions for Sphinx. &lt;/p&gt;

&lt;p&gt;That alone made me familiar with Sphinx as a document-authoring and generator tool. Remember: one writes Sphinx pages in "code" itself. The variants being &lt;a href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html" rel="noopener noreferrer"&gt;reStructuredText&lt;/a&gt; or &lt;a href="https://www.sphinx-doc.org/en/master/usage/markdown.html" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So there I was. One the one hand having me realization about the ability to interlink Markdown pages. On the other hand missing advanced features found in document-generators like Sphinx.&lt;/p&gt;

&lt;p&gt;Until I had an idea ... what if I combined the interlinked Markdown-pages approach with Sphinx-generated documentation ...?&lt;/p&gt;

&lt;h2&gt;
  
  
  "Embedded Doctree"
&lt;/h2&gt;

&lt;p&gt;For lack of a better name, I call this the "embedded Doctree" approach. Let me explain ...&lt;/p&gt;

&lt;p&gt;Through some trickery (which I am not going to go into detail right now) I managed to have a codebase be both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The project codebase, with its normal file structure&lt;/li&gt;
&lt;li&gt;A Sphinx project codebase, with its document pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code files and the documentation files are intermixed. They live in the same file-hierarchy.&lt;/p&gt;

&lt;p&gt;Thus, I can put Sphinx/Markdown files wherever I want, have them linked however I want, and they will produce a nice HTML-based technical page. The nice-to-read HTML-based documentation can be read and navigated on the browser (even be published somewhere).&lt;/p&gt;

&lt;p&gt;And on the other hand, Sphinx/Markdown files &lt;em&gt;are&lt;/em&gt; developer-friendly when exploring a codebase. They can still be viewed and edited as plain text and even still support the direct linking mentioned earlier (with some minor exceptions).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I think I found an interesting middle-ground between the  beautifully produced final-documents promised by the "literate programming" approach and useful, pragmatic, and IDE-friendly context-relevant local (document) files.&lt;/p&gt;

&lt;p&gt;With this approach one gets to keep using existing IDEs and the usual code-navigation, while having interlinked local in-depth explanations for vital aspects of a codebase - both as plain-text (Markdown) files and pleasant-to-read navigable online documentation.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>literateprogramming</category>
      <category>onboarding</category>
      <category>codebase</category>
    </item>
    <item>
      <title>Coin Collector Game</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Sat, 04 May 2024 14:11:51 +0000</pubDate>
      <link>https://dev.to/sebnozzi/coin-collector-1lh6</link>
      <guid>https://dev.to/sebnozzi/coin-collector-1lh6</guid>
      <description>&lt;p&gt;In this post we'll create a "coin collector" game for the &lt;a href="https://miniscript.org/MiniMicro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F18oye89g8gtll9g1yyc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F18oye89g8gtll9g1yyc0.png" alt="Coin collector game screenshot" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is taken from the book &lt;a href="https://www.dk.com/uk/book/9780241317792-computer-coding-python-games-for-kids/" rel="noopener noreferrer"&gt;Computer Coding Python Games for Kids&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;p&gt;The game works as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a fox and a coin on the screen.&lt;/li&gt;
&lt;li&gt;You move the fox with the arrow keys.&lt;/li&gt;
&lt;li&gt;When the fox collects the coin, the score is increased and a new coin is placed somewhere else on the screen.&lt;/li&gt;
&lt;li&gt;You have a certain amount of time to collect as many coins as possible.&lt;/li&gt;
&lt;li&gt;When the time is up the game is over and you are shown the final score.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the way, if you are already Mini Micro expert you might try implementing the game with these rules and then comparing with the implementation on this post! Otherwise, keep reading ...&lt;/p&gt;

&lt;h2&gt;
  
  
  Assets
&lt;/h2&gt;

&lt;p&gt;I'll be using the &lt;a href="https://www.dk.com/uk/information/the-python-games-resource-pack/" rel="noopener noreferrer"&gt;assets&lt;/a&gt; made available for readers of the book (which I borrowed from my local library). &lt;/p&gt;

&lt;p&gt;I didn't read anywhere that they could not be used for other languages other than Python. As I understand it, we'll be using these assets for personal / fair use - as they are freely available on the Internet.&lt;/p&gt;

&lt;p&gt;What I will &lt;em&gt;not&lt;/em&gt; be doing is re-publishing these assets somewhere else; nor claiming these to be my own. Neither should you. So I think we all should be fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;Download the assets file. &lt;/p&gt;

&lt;p&gt;Create a project folder and navigate there. Alternatively create a new "usr" folder and mount it.&lt;/p&gt;

&lt;p&gt;Put the two images (fox and coin) of the coin collector game in your project folder.&lt;/p&gt;

&lt;p&gt;Within Mini Micro, save an empty file "game.ms" on your project location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Placing the fox
&lt;/h2&gt;

&lt;p&gt;Let's start by loading the fox's image and placing it as a sprite on the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Fox Sprite

foxImg = file.loadImage("fox.png")

fox = new Sprite
fox.image = foxImg
fox.x = 200
fox.y = 200

// Game setup

clear

gfx.clear "#308A37"
sprd = display(4)

sprd.sprites.push fox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We created to "sections" to organize our code ("Fox Sprite" and "Game setup")&lt;/li&gt;
&lt;li&gt;We are making use of the &lt;a href="https://miniscript.org/wiki/Display" rel="noopener noreferrer"&gt;pre-defined&lt;/a&gt; &lt;a href="https://miniscript.org/wiki/SpriteDisplay" rel="noopener noreferrer"&gt;SpriteDisplay&lt;/a&gt; at slot 4&lt;/li&gt;
&lt;li&gt;We are making use of the &lt;a href="https://miniscript.org/wiki/Display" rel="noopener noreferrer"&gt;pre-defined&lt;/a&gt; &lt;a href="https://miniscript.org/wiki/PixelDisplay" rel="noopener noreferrer"&gt;PixelDisplay&lt;/a&gt; accessible via the global "gfx". We only use it to fill (&lt;a href="https://miniscript.org/wiki/PixelDisplay.clear" rel="noopener noreferrer"&gt;clear&lt;/a&gt;) it with a background color (same as in the original implementation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running this should show the fox on the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F6pk3qk4bfvuaah389tm9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6pk3qk4bfvuaah389tm9.png" alt="Fox sprite on the screen" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving the fox around
&lt;/h2&gt;

&lt;p&gt;Modify the fox-sprite block to add a "speed" property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fox = new Sprite
fox.image = foxImg
fox.speed = 10
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at the end of the program add the following while-loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Game Loop

while true

    if key.pressed("left") then
        fox.x -= fox.speed
    else if key.pressed("right") then
        fox.x += fox.speed
    else if key.pressed("up") then
        fox.y += fox.speed
    else if key.pressed("down") then
        fox.y -= fox.speed
    end if

    yield
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running the program the fox should now move with the arrow keys.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3ihby2ers76evwdpoj68.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3ihby2ers76evwdpoj68.gif" alt="Fox moving around" width="864" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(In order to keep this post short and the program simple we won't be checking if the fox leaves the screen. It's up to you to keep it inside!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing the coin
&lt;/h2&gt;

&lt;p&gt;Now it's turn to show the coin somewhere on the screen.&lt;/p&gt;

&lt;p&gt;Let's add this new section after the "Fox Sprite" one, before the "Game Setup":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Coin Sprite

coinImg = file.loadImage("coin.png")

coin = new Sprite
coin.image = coinImg
coin.x = 500
coin.y = 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we should not forget to add the coin sprite to the sprite-display. In the "Game Setup" section add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sprd.sprites.push coin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should give you a movable fox and a static coin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1bvtkspw3ekogncip2ou.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1bvtkspw3ekogncip2ou.png" alt="Fox and coin" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Collision detection
&lt;/h2&gt;

&lt;p&gt;As a next step we need to add &lt;a href="https://miniscript.org/wiki/Sprite.localBounds" rel="noopener noreferrer"&gt;local bounds&lt;/a&gt; so that &lt;a href="https://miniscript.org/wiki/Sprite.overlaps" rel="noopener noreferrer"&gt;collision detection&lt;/a&gt; works.&lt;/p&gt;

&lt;p&gt;First we add local bounds to the fox sprite. These lines could go right after assigning the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fox.localBounds = new Bounds
fox.localBounds.width = foxImg.width
fox.localBounds.height = foxImg.height
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same thing for the coin sprite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coin.localBounds = new Bounds
coin.localBounds.width = coinImg.width
coin.localBounds.height = coinImg.height
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test if collision detection works. Add this check inside the while-loop, before the "yield":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if fox.overlaps(coin) then
    print "Fox gets coin!"
end if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it out. You should see the text written many times (as the collision is detected many times per second).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbsa3kb58z9i3i7ubkzan.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbsa3kb58z9i3i7ubkzan.gif" alt="Fox gets the coin" width="864" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Placing the coin randomly
&lt;/h2&gt;

&lt;p&gt;Now, let's start fleshing out the proper game logic. Replace the above lines with these ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if fox.overlaps(coin) then
    coin.moveToRandomLocation
end if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We of course need to write this new method &lt;code&gt;moveToRandomLocation&lt;/code&gt; for the coin object. Add this to the "Coin Sprite" section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coin.moveToRandomLocation = function
    self.x = floor(rnd * 960)
    self.y = floor(rnd * 640)
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the usage of the "&lt;a href="https://miniscript.org/wiki/Rnd" rel="noopener noreferrer"&gt;rnd&lt;/a&gt;" and "&lt;a href="https://miniscript.org/wiki/Floor" rel="noopener noreferrer"&gt;floor&lt;/a&gt;" intrinsic functions.&lt;/p&gt;

&lt;p&gt;Try it out. You will see that except for the score and timer it looks like the game we want to have!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fu0f14d0kyz36v4z1fwh8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fu0f14d0kyz36v4z1fwh8.gif" alt="Coin at random locations" width="864" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Score
&lt;/h2&gt;

&lt;p&gt;Let's add a new section "Score" before "Game Setup". We will write a small object to take care of the score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Score

score = {}
score.value = 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For printing the score we will use the pre-allocated &lt;a href="https://miniscript.org/wiki/TextDisplay" rel="noopener noreferrer"&gt;TextDisplay&lt;/a&gt;. Because we will be updating the score text on the screen many times, we will also some way of deleting the old content.&lt;/p&gt;

&lt;p&gt;Let's start by creating a new section with these helper functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Text helper functions

eraseText = function(row,column,length)
    text.row = row
    text.column = column
    // Print "length" amount of spaces, with no "newline"
    print " " * length, ""
end function

printTextAtPosition = function(txt,row,column,txtColor)
    // Save current color and set color from parameter
    previousColor = text.color
    text.color = txtColor
    // Move to position and print text
    text.row = row
    text.column = column
    print txt
    // Restore previous color
    text.color = previousColor
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these helper functions we can easily implement the score-rendering. Add this method to the "Score" section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score.print = function
    eraseText 25, 5, "SCORE: 999999".len
    printTextAtPosition "SCORE: "+self.value, 25, 5, color.white
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we reserve an area for quite a big score number, which we'll probably never reach.&lt;/p&gt;

&lt;p&gt;Finally, add a first "score.print" call at the end of the "Game Setup" section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score.print

// Game Loop 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fze2a3lnh0gr9w7wps0an.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fze2a3lnh0gr9w7wps0an.png" alt="Initial score" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the score
&lt;/h2&gt;

&lt;p&gt;The score now appears on the screen, but is not is not yet updated when coins are collected. We will now change that.&lt;/p&gt;

&lt;p&gt;Let's add a method to increase and update the score on screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score.increase = function
    score.value += 10
    score.print
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course this alone is not enough. The method needs to be invoked when the fox collects a coin. Modify the corresponding if-block in the game-loop to read like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if fox.overlaps(coin) then
    coin.moveToRandomLocation
    score.increase
end if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2F4lwr8o4mfc3d4v1dlvad.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4lwr8o4mfc3d4v1dlvad.gif" alt="Coins increasing score" width="864" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying the countdown
&lt;/h2&gt;

&lt;p&gt;The fox can now collect coins at leisure ... but that's about to change. Now we'll add a timer to put some pressure.&lt;/p&gt;

&lt;p&gt;We will start slow and just showing a countdown on screen. &lt;/p&gt;

&lt;p&gt;Let's create a "Countdown" section right after the "Score" one, initially with these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Countdown

countdown = {}
// Countdown value in seconds
countdown.value = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a first step, let's write a "start" method with which we can start / initialize the countdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.start = function(initialValue)
    self.value = initialValue
    self.print
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accordingly we'll add the method to render the countdown text on screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.print = function
    eraseText 25, 50, "TIME: 9999".len
    printTextAtPosition "TIME: "+self.value, 25, 50, color.white
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, for reserving a printable area (erasing the previous text) we are choosing a very generous time value.&lt;/p&gt;

&lt;p&gt;Now let's add an invocation to this "start" step when setting up the game. In the "Game Setup" section add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.start 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to decide the amount of seconds which best work for you.&lt;/p&gt;

&lt;p&gt;If you try this out you should see the countdown being displayed on screen. But it does nothing yet. We'll change that in the next section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F48mgirfrsvj9qku678mo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F48mgirfrsvj9qku678mo.png" alt="Static countdown" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Counting down
&lt;/h2&gt;

&lt;p&gt;At this point we need to stop and think: how would the countdown logic work?&lt;/p&gt;

&lt;p&gt;We can do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The countdown starts with an initial value (of seconds)&lt;/li&gt;
&lt;li&gt;Inside the game-loop we'll call an "update" method on the countdown object&lt;/li&gt;
&lt;li&gt;The method will check how much time it elapsed since it has last decreased its value&lt;/li&gt;
&lt;li&gt;If more than one second elapsed, the countdown will decrease its value and register this new "last decrease timestamp".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strategy is clear, but some important pieces are missing. Besides the obvious "update" method we need to add a new property to keep track of "decrease events".&lt;/p&gt;

&lt;p&gt;Add this after the "value" property to the countdown object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.lastDecreaseTs = -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use some weird value like "-1" to make clear that it needs to be initialized. We will do just that now. Modify the "start" method to read like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.start = function(initialValue)
    self.value = initialValue
    self.lastDecreaseTs = time
    self.print
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By initializing it to the current timestamp we will have one full second before we need to decrease its value for the first time.&lt;/p&gt;

&lt;p&gt;Now we are in position to implement our countdown logic inside the "update" method. Add this method to the countdown object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.update = function
    currentTs = time
    elapsed = currentTs - self.lastDecreaseTs
    // A second elapsed since last check
    if elapsed &amp;gt; 1 then
        self.decrease
        self.lastDecreaseTs = currentTs
    end if
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It references a "decrease" method which we do not yet have. That method should decrease the value internally and update it on screen. Let's add it now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.decrease = function
    self.value -= 1
    if self.value &amp;lt; 0 then self.value = 0
    self.print
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we do not want negative numbers in our countdown, we add a corresponding check.&lt;/p&gt;

&lt;p&gt;Finally we need to update our game-loop to regularly call the "update" method. We can put that invocation right at the top of our while-loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while true

    countdown.update

    if ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you try it out you will see that our game is almost done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ft7e752lxoefgr76sbzew.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ft7e752lxoefgr76sbzew.gif" alt="Collecting coins with no limit" width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stopping the game
&lt;/h2&gt;

&lt;p&gt;If you play the game in its current state you will merrily be able to still collect coins even if the time is up. Time to change that.&lt;/p&gt;

&lt;p&gt;Let's add a small method to the countdown to indicate that it is finished:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;countdown.isFinished = function
    return self.value &amp;lt;= 0
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now let's add a check in the game loop. Right after decreasing the countdown we will add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if countdown.isFinished then break
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will effectively get us out of the while-loop when the countdown is done. As it is, the game just ends. You can of course see your final score on the screen.&lt;/p&gt;

&lt;p&gt;But we should be able to make it nicer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better ending
&lt;/h2&gt;

&lt;p&gt;First, let's add this function to our "Text helper functions" section which will allow us to print text centered on the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;printTextCentered = function(txt,row,txtColor)
    totalColumns = 68
    column = totalColumns / 2 - txt.len / 2
    printTextAtPosition txt,row,column,txtColor
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this let's print the final score and ask the user to play again or not. Add this outside (after) our game-loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Game ending

printTextCentered "FINAL SCORE: " + score.value, 16, color.white
printTextCentered "Do you want to play again? (y/n)", 14, color.white
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user should press either key "y" or key "n". Because the user will probably still fiercely holding an arrow key, we need to "consume" these until we detect any of the keys we want.&lt;/p&gt;

&lt;p&gt;Add this next to our section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while true
    k = key.get.lower
    if k == "y" then run
    if k == "n" then break
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user presses "y" the program will be run again.&lt;/p&gt;

&lt;p&gt;But if the user presses "n" this while-loop is exited and the program is over. Before that happens, let's add a short farewell message. Add this after this while-loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print
print "Bye!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you could say we are done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvivo5zwnqe9sqpyhuxay.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvivo5zwnqe9sqpyhuxay.gif" alt="Complete gameplay" width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try it out and have fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Glad you made it this far. Did you like this game tutorial? Did you learn something new? How many coins can you collect?  Let us know in the comments.&lt;/p&gt;

&lt;p&gt;Happy coding in Mini Micro!&lt;/p&gt;

</description>
      <category>minimicro</category>
      <category>miniscript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Mini Micro Web-Runner CLI</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Sat, 06 Jan 2024 00:32:38 +0000</pubDate>
      <link>https://dev.to/sebnozzi/mini-micro-web-runner-cli-268f</link>
      <guid>https://dev.to/sebnozzi/mini-micro-web-runner-cli-268f</guid>
      <description>&lt;p&gt;After some days of work I finished re-working the MMWR (Mini Micro Web-Runner, more details about this in another post) so that it is driven by two powerful and handy (Node.js-based) command-line tools ... &lt;/p&gt;

&lt;h2&gt;
  
  
  Serve
&lt;/h2&gt;

&lt;p&gt;The first one is &lt;code&gt;mmwr-serve&lt;/code&gt; ... which would be used when developing. One just navigates to one's Mini Micro project, issues the aforementioned command, and a local HTTP server is started which "serves" the project to be run on the browser. That's it. If one changes something in the code, just reload and the change should be there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fywchhm5koutmlbjdckou.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fywchhm5koutmlbjdckou.gif" alt="Using the serve tool" width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No additional "index.html", CSS or JavaScript files needed. The server tool takes care of all the details behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package
&lt;/h2&gt;

&lt;p&gt;The second one is &lt;code&gt;mmwr-package&lt;/code&gt; ... which one would use to package a Mini Micro project to deploy somewhere, for example &lt;a href="https://sebnozzi.itch.io" rel="noopener noreferrer"&gt;itch.io&lt;/a&gt;. Same thing: navigate to the Mini Micro project and issue the command. An Archive.zip file is produced with everything needed. Including a whole "sysdisk". More on this below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config File
&lt;/h2&gt;

&lt;p&gt;Both tools can make use of a &lt;code&gt;webrunner.config.json&lt;/code&gt; file if present. One can specify the HTML page title, one should specify the main ".ms" file of the project, and optionally additional files / folders.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "pageTitle": "Sliding Puzzle - Mini Micro Web Runner",
  "mainFile": "game.ms",
  "otherEntries": [
    "animation.ms",
    "game-images"
  ],
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sysdisk Entries
&lt;/h2&gt;

&lt;p&gt;One interesting aspect is that one can filter (out) "sysdisk" entries, making the end-product (Archive.zip) slicker than it would be, resulting in faster downloads (from itch.io) and thus quicker start-up times.&lt;/p&gt;

&lt;p&gt;Consider this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "pageTitle": "Mini Micro - LetterShooter (Web Runner)",
  "mainFile": "game.ms",
  "sysDisk": {
    "useOnly": [

      "/sys/pics/Heart.png",
      "/sys/pics/Fighter.png",

      "/sys/sounds/airburst.wav",
      "/sys/sounds/airburst.wav",
      "/sys/sounds/hit.wav",
      "/sys/sounds/ting.wav",
      "/sys/sounds/bling.wav",
      "/sys/sounds/fanfare.wav"
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we include only some pics and sounds from the "sysdisk", greatly reducing the final size from 13 Mb to 2.4 Mb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;This is the initial version of these tools. Some things might change. But in general this is the direction I want to take the MMWR. It should be both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A handy tool for local development&lt;/li&gt;
&lt;li&gt;A handy tool for sharing one's creations with others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As mentioned, the new CLI tools cover both these areas.&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>node</category>
    </item>
    <item>
      <title>Upcoming Global Day of Code Retreat</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Thu, 02 Nov 2023 23:05:16 +0000</pubDate>
      <link>https://dev.to/sebnozzi/upcoming-global-day-of-code-retreat-306h</link>
      <guid>https://dev.to/sebnozzi/upcoming-global-day-of-code-retreat-306h</guid>
      <description>&lt;p&gt;Just a quick reminder that the next &lt;a href="https://www.coderetreat.org/events/" rel="noopener noreferrer"&gt;Global Day of Code Retreat&lt;/a&gt; is about to take place next Saturday.&lt;/p&gt;

&lt;p&gt;From their website:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Coderetreats are free day-long, intensive practice events, focusing on the fundamentals of software development and design. By providing developers the opportunity to take part in focused practice, away from the pressures of "getting things done", the coderetreat format has proven itself to be a highly effective means of learning and nurturing software development skills.&lt;/p&gt;

&lt;p&gt;All over the world, people are coming together in small communities of practices to learn, explore and grow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After a COVID19 forced break, and personal reasons, I intend to participate in the one nearby.&lt;/p&gt;

&lt;p&gt;It's always nice to meet other developers, and it's inspiring to work on one's skills (both hard and soft skills).&lt;/p&gt;

</description>
      <category>gdcr</category>
      <category>gdcr23</category>
      <category>gdcr2023</category>
    </item>
    <item>
      <title>Combined Undo Actions</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Thu, 02 Nov 2023 20:37:37 +0000</pubDate>
      <link>https://dev.to/sebnozzi/multiple-undo-actions-356f</link>
      <guid>https://dev.to/sebnozzi/multiple-undo-actions-356f</guid>
      <description>&lt;p&gt;Recently I &lt;a href="https://discord.com/channels/646000428441534474/646000634222477313/1169702441814593606" rel="noopener noreferrer"&gt;quickly described&lt;/a&gt; how I implemented complex undo-actions in a &lt;a href="https://github.com/sebnozzi/minimicro-sokoban/" rel="noopener noreferrer"&gt;game I developed&lt;/a&gt;. That game is a &lt;a href="https://en.wikipedia.org/wiki/Sokoban" rel="noopener noreferrer"&gt;Sokoban&lt;/a&gt; clone, which I implemented in the &lt;a href="https://miniscript.org/wiki/Mini_Micro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt; neo-retro fantasy computer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkgb4oe4ayd4mupeifszu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkgb4oe4ayd4mupeifszu.png" alt="Game screenshot" width="692" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt;: the challenge of executing multiple small undo-actions was solved by combining many anonymous functions into a bigger one, finally pushing the latter into an undo-stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  A first approach
&lt;/h2&gt;

&lt;p&gt;A first naive approach could be like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the user makes a move&lt;/li&gt;
&lt;li&gt;Push the opposite move on a stack&lt;/li&gt;
&lt;li&gt;When the user wishes an "undo"&lt;/li&gt;
&lt;li&gt;Pop the stack and perform the popped operation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works "good enough" as long as we are just moving the worker. But it fails as soon as box-pushing is involved. For the reason alone that the approach above completely ignores boxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boxes and directions
&lt;/h2&gt;

&lt;p&gt;In addition to failing to consider boxes, the approach above fails to capture another additional detail: worker facing-directions. That is: the worker (in my implementation) does not always "look" in a fixed direction. Rather he turns left, right, up, down depending on where he's trying to go or push. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fq4dpgxovipa7nubea6tj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fq4dpgxovipa7nubea6tj.png" alt="Working facing different directions" width="794" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now we have two more aspects which should be "undone" when undoing a step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Box position (if this changed due to a push)&lt;/li&gt;
&lt;li&gt;Worker turning to a new direction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we see a single user-event (wanting to go "left" one step) can result in many things happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The worker turning to a new direction&lt;/li&gt;
&lt;li&gt;The worker changing position&lt;/li&gt;
&lt;li&gt;A box changing position&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Box state
&lt;/h2&gt;

&lt;p&gt;If we think possible outcomes of an action further, another very important change can happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A box changing its "state"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember, the goal of Sokoban is to "place" boxes in special "target" or "goal" tiles. A level is solved when all boxes are placed in such tiles.&lt;/p&gt;

&lt;p&gt;So a box can change from "unplaced" to "placed". And vice-versa (from "placed" to "unplaced", this is often temporarily needed for tactical reasons before the level is solved completely).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fajbd7kcojro87hkjnur8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fajbd7kcojro87hkjnur8.png" alt="Box states, placed / unplaced" width="259" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To recap, this would be the a complete list of things that can happen in a user "turn":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The worker turning to a new direction&lt;/li&gt;
&lt;li&gt;The worker changing position&lt;/li&gt;
&lt;li&gt;A box changing position&lt;/li&gt;
&lt;li&gt;A box changing state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Complex undo actions
&lt;/h2&gt;

&lt;p&gt;Intuitively, using an "undo" stack makes sense. But what would we push onto it, so that we can properly undo an user "turn"?&lt;/p&gt;

&lt;p&gt;Let's say a user "turn" results in these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turn worker to the "left"&lt;/li&gt;
&lt;li&gt;Move worker (from [3,2]) to [2,2]&lt;/li&gt;
&lt;li&gt;Change box position (from [2,2]) to [1,2]&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Would I want to push in the stack what happened and then figure out the opposite action? Or push the opposite action to begin with? I opted for the latter.&lt;/p&gt;

&lt;p&gt;So I would push this, in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change box position (from [1,2]) to [2,2]&lt;/li&gt;
&lt;li&gt;Move worker (from [2,2]) to [3,2]&lt;/li&gt;
&lt;li&gt;Turn worker to the "right"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, here is the implementation of moving an element (worker or box) and registering the opposite "undo" action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LevelSprite.moveTo = function(position)

  // Only do this if sprite already placed and the new
  // position is different than the current one.
  if self.position and self.position != position then

    previousPosition = obj.position
    previousX = obj.x
    previousY = obj.y

    // Register corresponding "undo" action ...
    // (Capture "self" so that it's "fixed" when executing)
    obj = self
    undoAction = function()
      obj.position = previousPosition
      obj.x = previousX
      obj.y = previousY
    end function
    // Note the function reference
    Actions.queue @undoAction

  end if
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I needed a way to "group" actions, so that when the user wants to undo his last keystroke all of the three are popped from the stack and executed. But not more! (the stack could well have previous undo-actions pushed into it).&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter transactions
&lt;/h2&gt;

&lt;p&gt;I solved the problem by grouping actions belonging to a "turn" and pushing them as-one into the undo-stack.&lt;/p&gt;

&lt;p&gt;That is, my undo-stack always has ONE entry per turn. Those three entries shown in the previous section are grouped into one and pushed into the stack.&lt;/p&gt;

&lt;p&gt;When the user wants to perform an undo, the composite action is popped and executed.&lt;/p&gt;

&lt;p&gt;But how do I group the smaller actions into a bigger one to begin with?&lt;/p&gt;

&lt;p&gt;I solved this by simulating "transactions".&lt;/p&gt;

&lt;p&gt;When the user presses a direction key, thus issuing a game event, a transaction is started in the "undo manager".&lt;/p&gt;

&lt;p&gt;The different parts of the code that change game-state are responsible of pushing their "undo actions" into a temporary (transaction) stack. For example the part that moves a box due to a push is responsible for registering the opposite move.&lt;/p&gt;

&lt;p&gt;When all game-state changing logic is executed, the transaction is "closed". Then the undo-manager groups all registered "undo actions" and makes one bigger single action, which is pushed in the undo-stack.&lt;/p&gt;

&lt;p&gt;In terms of code, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkerSprite.move = function(direction)
  Actions.beginTransaction

  self.rotateInDirection direction
  nextPosition = self.nextPositionInDirection(direction)

  objectAtNextPosition = LEVEL.getLevelObjectAt(nextPosition)
  objectAtNextPosition.move direction

  if LEVEL.hasFreeTileAt(nextPosition) then
    super.move direction
  end if

  Actions.endTransaction
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relevant parts are the &lt;code&gt;beginTransaction&lt;/code&gt; and &lt;code&gt;endTransaction&lt;/code&gt; in the &lt;code&gt;move&lt;/code&gt; method. The rest is the normal logic for a movement in a Sokoban level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions
&lt;/h2&gt;

&lt;p&gt;What are those undo-actions really?&lt;/p&gt;

&lt;p&gt;The actions, small and combined, are &lt;em&gt;anonymous functions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;After that, pressing undo is just a matter or popping the stack, and executing the top-most function (which returns the game state to one step before).&lt;/p&gt;

&lt;p&gt;For example in one transaction all of this could happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worker changes direction to the right&lt;/li&gt;
&lt;li&gt;Worker advances one position&lt;/li&gt;
&lt;li&gt;A box is pushed in direction "right"&lt;/li&gt;
&lt;li&gt;A box changes its "placed" state from "unplaced" to "placed" (green)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this would require ONE undo-action which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moves the worker one step to the left&lt;/li&gt;
&lt;li&gt;Moves the box one step to the left&lt;/li&gt;
&lt;li&gt;Rotates the worker to whichever direction it was facing before&lt;/li&gt;
&lt;li&gt;Sets the box to "unplaced"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And how to combine many function-references into one that calls them all? Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn = function()
  for qa in queuedActions
    qa()
  end for
end function
// Register composite action
self.actions.push @fn 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes place within &lt;code&gt;endTransaction&lt;/code&gt;. A new anonymous function that executes other anonymous functions stored in a list. Then pushed to a stack, ready to be retrieved and executed later.&lt;/p&gt;

&lt;p&gt;Going into more detail would blow up the length of this blog post. Readers so inclined can take a look directly at the &lt;a href="https://github.com/sebnozzi/minimicro-sokoban/blob/master/sokobanLevel.ms" rel="noopener noreferrer"&gt;source code&lt;/a&gt;. Questions are welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Undo-actions were modeled using anonymous small functions which would restore the game-state to a previous step. &lt;/p&gt;

&lt;p&gt;By using a "transaction" per user turn / action all relevant game-state changes could be registered and combined.&lt;/p&gt;

&lt;p&gt;The small anonymous functions were then combined into a bigger one, and pushed into the undo-stack. This makes the latter execution of an undo step trivial.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fztrl1fki2soqpslawzhz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fztrl1fki2soqpslawzhz.gif" alt="Undo in action" width="576" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>minimicro</category>
      <category>miniscript</category>
      <category>sokoban</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Maintainable Software Development</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Thu, 17 Aug 2023 13:35:34 +0000</pubDate>
      <link>https://dev.to/sebnozzi/maintainable-software-development-43ll</link>
      <guid>https://dev.to/sebnozzi/maintainable-software-development-43ll</guid>
      <description>&lt;p&gt;In the course of my time as a software developer I came to some realizations about how to write maintainable code in a professional setting. By this I mean: in long-term projects, usually for a customer, where maintainability is a key requirement. This in contrast to short-lived, personal, hobby projects where many of the requirements of a professional setting don't apply.&lt;/p&gt;

&lt;h1&gt;
  
  
  Layer-based Code Organization
&lt;/h1&gt;

&lt;p&gt;Something that I see happening over and over again in codebases (mine included) is the tendency to "code solutions" instead of "modelling the problem". &lt;/p&gt;

&lt;p&gt;By this I mean writing whatever code that solves the problem (makes the computer do what you intend it to do). Which is fine. Initially.&lt;/p&gt;

&lt;p&gt;The problem is that &lt;em&gt;meaning&lt;/em&gt; gets often lost in the process. Either partially or totally.&lt;/p&gt;

&lt;p&gt;This makes it very difficult to understand what the code was &lt;em&gt;about&lt;/em&gt; and adapt it to new requirements.&lt;/p&gt;

&lt;p&gt;An alternative might be to use code to &lt;em&gt;express&lt;/em&gt; the problem at hand. By coding and using the necessary "abstractions", a so-called "top-level" part of the codebase should be able to express the problem, while at the same instructing the computer to execute the solution.&lt;/p&gt;

&lt;p&gt;Below that theoretical "top-level" would come the next level, which solves &lt;em&gt;different&lt;/em&gt; problems (using the abstractions needed at &lt;strong&gt;that&lt;/strong&gt; level). That level would in turn rely upon abstractions one level below it. And so on.&lt;/p&gt;

&lt;p&gt;While this approach might need more effort and discipline it should pay long-term where projects are long-lived, involve many team members and maintainability is an issue.&lt;/p&gt;

&lt;h1&gt;
  
  
  De-Coupled Tests
&lt;/h1&gt;

&lt;p&gt;When firstly introduced the idea of writing "unit-tests" or pieces of code that "test" your "production" code seemed alien and even a waste of time.&lt;/p&gt;

&lt;p&gt;Decades later, practices like TDD are a well established standard. The professional projects that don't use some sort of automated testing are rather the exception.&lt;/p&gt;

&lt;p&gt;However, in many projects (mine included) I discovered an aspect of automated testing that turned automated-tests into a &lt;strong&gt;liability&lt;/strong&gt; rather than an asset. &lt;/p&gt;

&lt;p&gt;The more tests a codebase had (usually but not necessarily resulting in more coverage) the bigger this problem presented itself: the design of the codebase became more rigid.&lt;/p&gt;

&lt;p&gt;That is: code was increasingly &lt;em&gt;more&lt;/em&gt; difficult to change, not less. &lt;/p&gt;

&lt;p&gt;And that is because the way tests were written was by being tied directly to whatever design decisions happened to be present in the code being tested at that time.&lt;/p&gt;

&lt;p&gt;This creates high-coupling not within the production code (which the experts usually advocate against and focus their energy on) but between production code and &lt;em&gt;tests&lt;/em&gt; (which are supposed to be independent from production code and only be there to help you).&lt;/p&gt;

&lt;p&gt;As a result, the code-design would be increasingly unable to improve. Overall the whole codebase would grow in complexity. By not being able to re-design to better abstractions the codebase would be stuck with unsuitable design decisions and abstractions.&lt;/p&gt;

&lt;p&gt;The solution to this problem of course would be to &lt;em&gt;de-couple&lt;/em&gt; automated-tests from implementation details. Abstractions used in production code would &lt;em&gt;not&lt;/em&gt; appear in the test-code, but in a "bridge" / "adapter" layer. &lt;/p&gt;

&lt;p&gt;Instead the tests would be written using an &lt;strong&gt;internal DSL&lt;/strong&gt; (written only for in test-code; never in production). This would not only make tests easier to read, but allow production code to evolve 1) at all and 2) &lt;em&gt;faster&lt;/em&gt; by being independent of test-code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Updating the Documentation
&lt;/h1&gt;

&lt;p&gt;One particular area which is usually a second class citizen in software projects is ... apart from security: documentation.&lt;/p&gt;

&lt;p&gt;Often developers don't have time, are not given the time, or do not care (or are not told to care) about documentation.&lt;/p&gt;

&lt;p&gt;Until it's too late and one either has no documentation or fragmented, incomplete, inconsistent or outdated one.&lt;/p&gt;

&lt;p&gt;Because documentation does not "run" and is purely a "human" activity the solution in my opinion has to be a "human" one. But both technology and methodology can and should help.&lt;/p&gt;

&lt;p&gt;My proposal here is to make writing or updating the corresponding documentation a &lt;em&gt;requirement&lt;/em&gt; either at the pull-request level, or even better, at the issue level (reviewed by the customer).&lt;/p&gt;

&lt;p&gt;That is: whenever a feature changes, whenever the code is modified, if applicable, a documentation change is also required. The issue or PR is not considered complete until the documentation is reviewed to have been changed satisfactorily.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus: Security - Ownership approach
&lt;/h1&gt;

&lt;p&gt;And because I mentioned it in the section before, let's also talk about security.&lt;/p&gt;

&lt;p&gt;Security, maybe together with documentation, is an aspect that developers usually don't enjoy.&lt;/p&gt;

&lt;p&gt;I might expand on this on a future post, but I think the approach is to appoint a security "owner" and have this person be a required reviewer of all PRs. &lt;/p&gt;

&lt;h1&gt;
  
  
  Final words
&lt;/h1&gt;

&lt;p&gt;Hope these points here made motivated you to think about best-practices in a professional software-development setting.&lt;/p&gt;

&lt;p&gt;I hope to be able to expand on these thoughts in the future. &lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>programming</category>
      <category>coding</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Random numbers</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Sun, 12 Mar 2023 22:26:45 +0000</pubDate>
      <link>https://dev.to/sebnozzi/random-numbers-mini-script-lnj</link>
      <guid>https://dev.to/sebnozzi/random-numbers-mini-script-lnj</guid>
      <description>&lt;p&gt;In this blogpost we are going to take a look on how to produce random numbers within a certain range in MiniScript / Mini Micro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Foxqv8j156pr6hie7r9rq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Foxqv8j156pr6hie7r9rq.png" alt="Printing random numbers in Mini Micro" width="747" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;rnd&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;In MiniScript (and by extension Mini Micro) the way to get random numbers is by using the &lt;a href="https://miniscript.org/wiki/Rnd" rel="noopener noreferrer"&gt;&lt;code&gt;rnd&lt;/code&gt;&lt;/a&gt; intrinsic function.&lt;/p&gt;

&lt;p&gt;Calling this function gives you a floating-point random number between 0 and 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print rnd
0.147535
&amp;gt; print rnd
0.421682
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bigger range
&lt;/h2&gt;

&lt;p&gt;If we want a bigger range of random numbers all we have to do is multiply the result of &lt;code&gt;rnd&lt;/code&gt; by some other number. For example: if we want random numbers between 0 and 20 we evaluate &lt;code&gt;rnd * 20&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;&amp;gt; print rnd * 20
15.439491
&amp;gt; print rnd * 20
19.455438
&amp;gt; print rnd * 20
8.460014
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;floor&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;Often we need random integers (whole numbers). One way to convert a floating-point number to an integer is by calling another intrinsic function: &lt;a href="https://miniscript.org/wiki/Floor" rel="noopener noreferrer"&gt;&lt;code&gt;floor&lt;/code&gt;&lt;/a&gt;. Applying this function to a floating-point number will effectively strip it from the decimal digits, leaving only the "integer" part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print floor(0.14)
0
&amp;gt; print floor(42.9)
42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Situation so far
&lt;/h2&gt;

&lt;p&gt;Combining these three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;... calling &lt;code&gt;rnd&lt;/code&gt; for random numbers between 0 and 1&lt;/li&gt;
&lt;li&gt;... multiplying &lt;code&gt;rnd&lt;/code&gt; by a factor&lt;/li&gt;
&lt;li&gt;... applying &lt;code&gt;floor&lt;/code&gt; to the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;... will produce random integers between 0 and the desired factor.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print floor(rnd * 20)
13
&amp;gt; print floor(rnd * 20)
6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Numbers in any range
&lt;/h2&gt;

&lt;p&gt;What if we wanted to have random numbers for a certain range starting above 0?&lt;/p&gt;

&lt;p&gt;what we need to do is to sum some fixed number to the result. When doing so we are "shifting" the range of results, so we need to be careful about the end of the range, which is also shifted. We usually need to compensate for that by subtracting from the factor, which corrects the range-size.&lt;/p&gt;

&lt;p&gt;For example, let's say we want random numbers between 100 and 300.&lt;/p&gt;

&lt;p&gt;What is the solution?&lt;/p&gt;

&lt;p&gt;Maybe &lt;code&gt;floor(rnd * 300)&lt;/code&gt;? No, this would give us numbers from 0 to 300.&lt;/p&gt;

&lt;p&gt;Maybe &lt;code&gt;100 + floor(rnd * 300)&lt;/code&gt;? No. Because &lt;code&gt;floor(rnd * 300)&lt;/code&gt; gives us numbers from 0 to 300, adding 100 to it would give us numbers from 100 to &lt;em&gt;400&lt;/em&gt; (not what we want).Remember: the end-range is also shifted.&lt;/p&gt;

&lt;p&gt;Because the end-range is shifted, we need to compensate by subtracting from the factor (to correct the range size).&lt;/p&gt;

&lt;p&gt;The correct answer is general terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RANGE_SIZE = END_RANGE - START_RANGE
START_RANGE + floor(rnd * RANGE_SIZE)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in our case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 + floor(rnd * (300-100))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, simplified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 + floor(rnd * (200))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print 100 + floor(rnd * 200)
282
&amp;gt; print 100 + floor(rnd * 200)
102
&amp;gt; print 100 + floor(rnd * 200)
183
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;With this we learnt how to generate random whole-numbers (integers) in a range between two arbitrary numbers in Mini Script.&lt;/p&gt;

&lt;p&gt;In a future posts we will put this knowledge to use and have some fun with it.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>tutorial</category>
      <category>random</category>
    </item>
    <item>
      <title>Counting word lengths (map approach)</title>
      <dc:creator>Sebastian Nozzi</dc:creator>
      <pubDate>Wed, 26 Oct 2022 21:59:07 +0000</pubDate>
      <link>https://dev.to/sebnozzi/counting-word-lengths-map-approach-43p1</link>
      <guid>https://dev.to/sebnozzi/counting-word-lengths-map-approach-43p1</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/sebnozzi/most-common-word-length-e7e"&gt;a previous post&lt;/a&gt; we saw already how to solve the problem by using an array.&lt;/p&gt;

&lt;p&gt;Specifically we had a 12-length array, and each position was used to increase a counter according to the current word's length. We had to convert from word-length to array-index by subtracting 1 from the first number.&lt;/p&gt;

&lt;p&gt;This solution worked perfectly fine and given the constraint of only considering word-lengths up to 12, I would go this route.&lt;/p&gt;

&lt;p&gt;But it is worth looking at a map-based approach (in other languages "map" is known as "dictionary"). Some other problems are better solved with this approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;The complete array-based solution looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "listUtil"

words = file.readLines("/sys/data/englishWords.txt")

word_length_counters = [0] * 12

for word in words
    word_length = len(word)
    if word_length &amp;gt; 12 then continue
    counter_index = word_length - 1
    current_count = word_length_counters[counter_index]
    word_length_counters[counter_index] = current_count + 1
end for

max_count = word_length_counters.max
max_count_index = word_length_counters.indexOf(max_count)
max_word_length = max_count_index + 1

print "The most common word length is " + max_word_length
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, most of the code can remain the same. But some key changes need to be made.&lt;/p&gt;

&lt;h2&gt;
  
  
  First changes
&lt;/h2&gt;

&lt;p&gt;First, instead of storing the counters in an array we will use a map. It will be a generic empty map, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;word_length_counters = {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One advantage of using maps is that we can use "human" numbers as keys. That is: we can use directly the word-lenghts (which go from 1 to 12) without having to subtract 1 as we did for array indexes.&lt;/p&gt;

&lt;p&gt;In particular MiniScript allows you to use pretty much anything as map-indexes, which is very convenient. It even allows you to use numbers as keys - which we will be doing here.&lt;/p&gt;

&lt;p&gt;The first part of the for-loop remains the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for word in words
    word_length = len(word)
    if word_length &amp;gt; 12 then continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then it gets interesting. We don't need this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;counter_index = word_length - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can access the &lt;code&gt;current_count&lt;/code&gt; by &lt;code&gt;word_length&lt;/code&gt; as mentioned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current_count = word_length_counters[word_length]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And store it back, also using &lt;code&gt;word_length&lt;/code&gt; as the key of the map:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;word_length_counters[counter_index] = current_count + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Problem found
&lt;/h2&gt;

&lt;p&gt;Putting it all together, this is how the for-loop would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for word in words
    word_length = len(word)
    if word_length &amp;gt; 12 then continue
    current_count = word_length_counters[word_length]
    word_length_counters[word_length] = current_count + 1
end for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks ok, right? But what happens when you run it?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Runtime Error: Key Not Found: '1' not found in map [line 11]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is that? Problem is, the map is initially empty! So, the first time the "current_count" wants to be retrieved, nothing is found. We need to handle the case where the map does not yet have a counter for a given word-length.&lt;/p&gt;

&lt;p&gt;We need to ask: does this map have the key "word_length"? If not, add an entry for it with a 0. This will have the effect that retrieving the "current_count" in the next line will find something (a 0 value) to add 1 to.&lt;/p&gt;

&lt;h2&gt;
  
  
  First-time access
&lt;/h2&gt;

&lt;p&gt;How do we ask if a map has a certain "key"? In MiniScript this is solved at the "collection" level. That is: there is a method that is called the same and acts similarly for strings, lists and maps. That method is &lt;a href="https://miniscript.org/wiki/HasIndex" rel="noopener noreferrer"&gt;&lt;code&gt;hasIndex&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that in mind, this is the line we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if not word_length_counters.hasIndex(word_length) then word_length_counters[word_length] = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting that before the first access gives us then this (fixed) for-loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for word in words
    word_length = len(word)
    if word_length &amp;gt; 12 then continue
    if not word_length_counters.hasIndex(word_length) then word_length_counters[word_length] = 0
    current_count = word_length_counters[word_length]
    word_length_counters[word_length] = current_count + 1
end for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result-calculation
&lt;/h2&gt;

&lt;p&gt;Now is the time to adapt the result-calculation.&lt;/p&gt;

&lt;p&gt;In the array-based approach &lt;code&gt;word_length_counters&lt;/code&gt; already contained the word-lengths. But because we are using a map (which maps from word-length to word-counts) we need to look at the &lt;a href="https://miniscript.org/wiki/Values" rel="noopener noreferrer"&gt;&lt;em&gt;values&lt;/em&gt;&lt;/a&gt; of our map.&lt;/p&gt;

&lt;p&gt;The first line would thus change from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_count = word_length_counters.max
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_count = word_length_counters.values.max
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the keys of the map are already word-lengths, we don't need to convert from "index" to "word-length". Even if MiniScript is talking about "index", it really means "key" in the context of a map.&lt;/p&gt;

&lt;p&gt;Therefor the next lines can be simplified from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_count_index = word_length_counters.indexOf(max_count)
max_word_length = max_count_index + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_word_length = word_length_counters.indexOf(max_count)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final &lt;code&gt;print&lt;/code&gt; remains the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete solution
&lt;/h2&gt;

&lt;p&gt;Finally, the complete map-based solution looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "listUtil"

words = file.readLines("/sys/data/englishWords.txt")

word_length_counters = {}

for word in words
    word_length = len(word)
    if word_length &amp;gt; 12 then continue
    if not word_length_counters.hasIndex(word_length) then word_length_counters[word_length] = 0
    current_count = word_length_counters[word_length]
    word_length_counters[word_length] = current_count + 1
end for

max_count = word_length_counters.values.max
max_word_length = word_length_counters.indexOf(max_count)

print "The most common word length is " + max_word_length
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully it was clear how to use maps in general, and in particular in this case (interestingly, using numbers as keys).&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>challenge</category>
    </item>
  </channel>
</rss>
