blog/algorithms/recursion/karel/index.html

165 lines
33 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-algorithms docs-version-current docs-doc-page docs-doc-id-recursion/2022-11-29-karel/karel" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.1.1">
<title data-rh="true">Recursion and backtracking with Robot Karel | mf</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://blog.mfocko.xyz/algorithms/recursion/karel/"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-algorithms-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-algorithms-current"><meta data-rh="true" property="og:title" content="Recursion and backtracking with Robot Karel | mf"><meta data-rh="true" name="description" content="A problem with too many restrictions.
"><meta data-rh="true" property="og:description" content="A problem with too many restrictions.
"><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://blog.mfocko.xyz/algorithms/recursion/karel/"><link data-rh="true" rel="alternate" href="https://blog.mfocko.xyz/algorithms/recursion/karel/" hreflang="en"><link data-rh="true" rel="alternate" href="https://blog.mfocko.xyz/algorithms/recursion/karel/" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://0VXRFPR4QF-dsn.algolia.net" crossorigin="anonymous"><link rel="search" type="application/opensearchdescription+xml" title="mf" href="/opensearch.xml">
<link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" title="mf RSS Feed">
<link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="mf Atom Feed">
<link rel="alternate" type="application/json" href="/blog/feed.json" title="mf JSON Feed">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css" integrity="sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM" crossorigin="anonymous"><link rel="stylesheet" href="/assets/css/styles.cc45d56f.css">
<script src="/assets/js/runtime~main.99091760.js" defer="defer"></script>
<script src="/assets/js/main.1bf5eb42.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return localStorage.getItem("theme")}catch(t){}}();t(null!==e?e:"light")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><b class="navbar__title text--truncate">mf</b></a><div class="navbar__item dropdown dropdown--hoverable"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link">Additional FI MU materials</a><ul class="dropdown__menu"><li><a aria-current="page" class="dropdown__link dropdown__link--active" href="/algorithms/">Algorithms</a></li><li><a class="dropdown__link" href="/c/">C</a></li><li><a class="dropdown__link" href="/cpp/">C++</a></li></ul></div><a class="navbar__item navbar__link" href="/contributions/">Contributions</a><a class="navbar__item navbar__link" href="/talks/">Talks</a></div><div class="navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/blog/">Blog</a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live="polite"><svg viewBox="0 0 24 24" width="24" height="24" class="lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" class="darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.
<li><a href="/files/algorithms/recursion/karel-1.tar.gz" target="_blank" rel="noopener noreferrer">Sources</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="introduction">Introduction<a href="#introduction" class="hash-link" aria-label="Direct link to Introduction" title="Direct link to Introduction"></a></h2>
<p>In this exercise we will be working with a Robot Karel and with a »very« limited
resources. The point of this exercise is to show how powerful recursion and
backtracking can be even without anything else at your hand.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="your-environment-and-problem-description">Your environment and problem description<a href="#your-environment-and-problem-description" class="hash-link" aria-label="Direct link to Your environment and problem description" title="Direct link to Your environment and problem description"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="environment">Environment<a href="#environment" class="hash-link" aria-label="Direct link to Environment" title="Direct link to Environment"></a></h3>
<p>You are given a robot that is present in a maze and is looking for an exit. Maze
consists of different walls and exit is marked with a single so-called “beeper”.</p>
<p>Walking into a wall results in a permanent damage of the robot.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="interface">Interface<a href="#interface" class="hash-link" aria-label="Direct link to Interface" title="Direct link to Interface"></a></h3>
<p>You can control the robot using the following interface:</p>
<ul>
<li>actions ​­— you can use them to change the current state of the robot and its
surroundings<!-- -->
<ul>
<li><code>robot.step()</code> — moves robot one step further</li>
<li><code>robot.turn_left()</code> — turns robot 90-degrees counter-clockwise<!-- -->
<ul>
<li>notice that you are not given <code>turn_right</code> or <code>turn_around</code>, but feel free
to implement them yourself</li>
</ul>
</li>
<li><code>robot.pick_beeper()</code> and opposite operation <code>robot.put_beeper()</code> — that
allows you to either pick or put “beeper” from or onto the current position</li>
</ul>
</li>
<li>queries — you can use them to check the current state of the robot and its
surroundings<!-- -->
<ul>
<li><code>robot.beepers_present()</code> — to check if there are any beepers at the robot&#x27;s
current location</li>
<li><code>robot.left_is_clear()</code> — to check if you can step to the left<!-- -->
<ul>
<li>analogically for <code>front</code> and <code>right</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>caution</div><div class="admonitionContent_BuS1"><p>Helper functions / procedures are allowed. Return values are allowed.</p><p><strong>Variables are prohibited!</strong></p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="problem">Problem<a href="#problem" class="hash-link" aria-label="Direct link to Problem" title="Direct link to Problem"></a></h3>
<p>Your task is to decide whether there is an exit from the maze or not. You can see
an example of a maze here:</p>
<p><img decoding="async" loading="lazy" alt="Image of the maze" src="/assets/images/maze-a374d908bc9445061e15faeddc71641e.png" width="770" height="839" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="simple-problem-to-get-familiar-with-the-robot">Simple problem to get familiar with the robot<a href="#simple-problem-to-get-familiar-with-the-robot" class="hash-link" aria-label="Direct link to Simple problem to get familiar with the robot" title="Direct link to Simple problem to get familiar with the robot"></a></h2>
<p>If you feel completely lost after the previous description, let me start you off
with a simpler problem.</p>
<p>You are standing in front of the stairs, your task is to walk up the stairs.</p>
<p>You can see an example of such map here:</p>
<p><img decoding="async" loading="lazy" alt="Image of the stairs" src="/assets/images/stairs-5ee5d03905645aeb13eeaa7774451a64.png" width="1058" height="1161" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="brainstorm-the-idea">Brainstorm the idea<a href="#brainstorm-the-idea" class="hash-link" aria-label="Direct link to Brainstorm the idea" title="Direct link to Brainstorm the idea"></a></h2>
<p>As a first step write down any ideas and things that you have noticed or came to
your mind. Ideally:</p>
<ol>
<li>Write down a nested list of the problems</li>
<li>Write down list of problems that can happen</li>
<li>Write down <strong>anything</strong> you consider important to solving the problem</li>
</ol>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Example</div><div class="admonitionContent_BuS1"><p><strong>Problem</strong>: I want to find out whether the display on smartphone should rotate.</p><ul>
<li>nested list of problems<!-- -->
<ul>
<li>Check if display has been rotated<!-- -->
<ul>
<li>Read data from some sensor<!-- -->
<ul>
<li>From what sensor</li>
</ul>
</li>
<li>In what format are the data I have read?</li>
<li>How do I communicate with the sensor?</li>
<li>What is the meaning of the data that I got?</li>
<li>How can I process it?</li>
</ul>
</li>
</ul>
</li>
<li>any problems that can happen<!-- -->
<ul>
<li>What if the sensor doesn&#x27;t work?</li>
<li>What if the data doesn&#x27;t conform to the specification?</li>
<li>What if my formulas are wrong?</li>
</ul>
</li>
<li>anything important<!-- -->
<ul>
<li>I could probably use gyroscope.</li>
<li>I should probably look up the datasheet for that module.</li>
<li>I could write some tests to verify that my computations are correct.</li>
</ul>
</li>
</ul></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="rough-pseudocode">»Rough« pseudocode<a href="#rough-pseudocode" class="hash-link" aria-label="Direct link to »Rough« pseudocode" title="Direct link to »Rough« pseudocode"></a></h2>
<p>As a next step write a <strong>mock up</strong> of a pseudocode solving the problem, you are
allowed to use comments as placeholders for bigger chunks of code.</p>
<p>Those comments are also a very good hints for decomposition and short, but
descriptive, commnets (if they are short enough and you decide not to factor them
out to separate functions).</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>The smaller the function is, the easier it is to test it and argue about its
correctness.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="proper-pseudocode">»Proper« pseudocode<a href="#proper-pseudocode" class="hash-link" aria-label="Direct link to »Proper« pseudocode" title="Direct link to »Proper« pseudocode"></a></h2>
<p>If you are satisfied with the <em>»rough« pseudocode</em>, it&#x27;s time to convert it into
a proper one. Get rid of the uncertain pieces of functionality and replace them
with proper pseudocode, i.e. list of the things that should happen in its place.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="library">Library<a href="#library" class="hash-link" aria-label="Direct link to Library" title="Direct link to Library"></a></h2>
<p>If you got here, and you <strong>actually</strong> wrote down the pseudocode, you can try your
solution after downloading the sources linked at the beginning. If you download
the ZIP-file, you can there:</p>
<ul>
<li>
<p><code>generate_mazes.py</code> - that was used to generate the same maze with beepers in
different locations</p>
</li>
<li>
<p><code>karel_tk.py</code> - library which can run Karel given the his world</p>
<ul>
<li>documentation can be found <a href="https://www.fi.muni.cz/~xfocko/ib111/10/docs/" target="_blank" rel="noopener noreferrer">here</a></li>
<li>also requires Tk Python library to be installed (it should be included in
majority of Python installations)</li>
</ul>
</li>
<li>
<p><code>*.kw</code> - which represent multiple worlds for Karel I have prepared</p>
</li>
<li>
<p><code>skeleton.py</code> - skeleton for your solution, needs to be put in the same directory
as <code>karel_tk.py</code> and takes path to the world as a first argument, example usage:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">$ python3 skeleton.py stairs.kw</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li>of course, this file can be renamed ;)</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="solution">Solution<a href="#solution" class="hash-link" aria-label="Direct link to Solution" title="Direct link to Solution"></a></h2>
<p>Solution to this problem will be released as a second part, so that you can try
it out by yourself without any influence of “example solution”.</p>
<p>If you want to get any feedback, feel free to mail me your solution (including
all the steps that lead to your final solution, if you wish to get feedback on
those too).</p></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-tags-row row margin-bottom--sm"><div class="col"><b>Tags:</b><ul class="tags_jXut padding--none margin-left--sm"><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/python/">python</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/karel/">karel</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/recursion/">recursion</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/backtracking/">backtracking</a></li></ul></div></div><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://github.com/mfocko/blog/tree/main/algorithms/04-recursion/2022-11-29-karel/index.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_vwxv"><span class="theme-last-updated">Last updated<!-- --> on <b><time datetime="2022-11-29T00:00:00.000Z">Nov 29, 2022</time></b></span></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/algorithms/category/recursion/"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Recursion</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/algorithms/recursion/karel/solution/"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Solution to the problem</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#introduction" class="table-of-contents__link toc-highlight">Introduction</a></li><li><a href="#your-environment-and-problem-description" class="table-of-contents__link toc-highlight">Your environment and problem description</a><ul><li><a href="#environment" class="table-of-contents__link toc-highlight">Environment</a></li><li><a href="#interface" class="table-of-contents__link toc-highlight">Interface</a></li><li><a href="#problem" class="table-of-contents__link toc-highlight">Problem</a></li></ul></li><li><a href="#simple-problem-to-get-familiar-with-the-robot" class="table-of-contents__link toc-highlight">Simple problem to get familiar with the robot</a></li><li><a href="#brainstorm-the-idea" class="table-of-contents__link toc-highlight">Brainstorm the idea</a></li><li><a href="#rough-pseudocode" class="table-of-contents__link toc-highlight">»Rough« pseudocode</a></li><li><a href="#proper-pseudocode" class="table-of-contents__link toc-highlight">»Proper« pseudocode</a></li><li><a href="#library" class="table-of-contents__link toc-highlight">Library</a></li><li><a href="#solution" class="table-of-contents__link toc-highlight">Solution</a></li></ul></div></div></div></div></main></div></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Git</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/mfocko" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://gitlab.com/mfocko" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitLab<svg width="13.5" height="13.5" aria-hidden="true" v
</body>
</html>