<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://antikrem.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://antikrem.github.io/" rel="alternate" type="text/html" /><updated>2026-03-23T13:02:24+00:00</updated><id>https://antikrem.github.io/feed.xml</id><title type="html">Chally</title><subtitle>Programming and Maths</subtitle><entry><title type="html">Happy little unit tests</title><link href="https://antikrem.github.io/happy_path_unit_testing/" rel="alternate" type="text/html" title="Happy little unit tests" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://antikrem.github.io/happy_path_unit_testing</id><content type="html" xml:base="https://antikrem.github.io/happy_path_unit_testing/"><![CDATA[<p>Do unit tests make you happy? When they work, they make me ecstatic. For agentic coding, they let you fire and forget, knowing that as long as the unit tests pass, your existing code (probably) won’t be broken… Right?
<img src="/images/2026-03-23-happy_path_unit_testing/bob_ross_checkmarks.jpg" alt="Happy little unit tests" /></p>

<h1 id="to-fail-or-not-to-fail">To fail or not to fail</h1>
<p>At work we use a lot of common patterns. A lot of our classes look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EvenAndPositiveChecker</span><span class="p">(</span><span class="n">INumberRulesService</span> <span class="n">service</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="kt">int</span> <span class="k">value</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">service</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="k">value</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="n">service</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So your test cases will look like:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EvenAndPositiveCheckerTests</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">INumberRulesService</span> <span class="n">_rules</span><span class="p">;</span>
    <span class="k">private</span> <span class="n">EvenAndPositiveChecker</span> <span class="n">_sut</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Setup</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Setup</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span> <span class="p">=</span> <span class="n">Substitute</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">INumberRulesService</span><span class="p">&gt;();</span>
        <span class="n">_sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EvenAndPositiveChecker</span><span class="p">(</span><span class="n">_rules</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_OddNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="m">1</span><span class="p">).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_NegativeNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(-</span><span class="m">2</span><span class="p">).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(-</span><span class="m">2</span><span class="p">);</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>But wait… the tests pass, but they aren’t technically correct. We’re only ever proving one branch, because the substitute returns <code class="language-plaintext highlighter-rouge">false</code> by default for any call we haven’t set up, including <code class="language-plaintext highlighter-rouge">_rules.IsEven</code> in the second test. And it’s not very obvious from reading the test that there is a problem. We can introduce a bug like this, and the tests will still pass:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EvenAndPositiveChecker</span><span class="p">(</span><span class="n">INumberRulesService</span> <span class="n">service</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="kt">int</span> <span class="k">value</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">service</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="k">value</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">service</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="what-the-fix">What the fix?</h1>
<p>One approach is to add helpers that set up the green path for each service call.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EvenAndPositiveCheckerTests</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">INumberRulesService</span> <span class="n">_rules</span><span class="p">;</span>
    <span class="k">private</span> <span class="n">EvenAndPositiveChecker</span> <span class="n">_sut</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Setup</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Setup</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span> <span class="p">=</span> <span class="n">Substitute</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">INumberRulesService</span><span class="p">&gt;();</span>
        <span class="n">_sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EvenAndPositiveChecker</span><span class="p">(</span><span class="n">_rules</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_EvenAndPositive_ReturnsTrue</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">SetUpIsPositive</span><span class="p">();</span>
        <span class="nf">SetUpIsEven</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">True</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_OddNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">SetUpIsPositive</span><span class="p">();</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_NegativeNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">SetUpIsEven</span><span class="p">();</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">SetUpIsEven</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">SetUpIsPositive</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I’ve seen legacy code that does this, and it reeks of an author who wanted to be as precise as possible, regardless of the boilerplate it introduces. It does make it explicit how every service is set up for each test, but you end up with a lot of repeated code, and the tedious job of checking everything is configured and nothing is missed.</p>

<h1 id="a-modern-lazy-but-simple-solution">A modern (lazy but simple) solution</h1>
<p>I like a solution that’s less precise but simpler. We set up the green path in the setup, and each test mutates just enough to hit a sad path:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EvenAndPositiveCheckerTests</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">INumberRulesService</span> <span class="n">_rules</span><span class="p">;</span>
    <span class="k">private</span> <span class="n">EvenAndPositiveChecker</span> <span class="n">_sut</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Setup</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">SetupHappyPath</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span> <span class="p">=</span> <span class="n">Substitute</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">INumberRulesService</span><span class="p">&gt;();</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
        <span class="n">_sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EvenAndPositiveChecker</span><span class="p">(</span><span class="n">_rules</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_HappyPath_ReturnsTrue</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">True</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_OddNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsEven</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Test</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">IsEvenAndPositive_NegativeNumber_ReturnsFalse</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_rules</span><span class="p">.</span><span class="nf">IsPositive</span><span class="p">(</span><span class="n">Arg</span><span class="p">.</span><span class="n">Any</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;()).</span><span class="nf">Returns</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_sut</span><span class="p">.</span><span class="nf">IsEvenAndPositive</span><span class="p">(</span><span class="n">Some</span><span class="p">.</span><span class="nf">Int</span><span class="p">());</span>

        <span class="n">Assert</span><span class="p">.</span><span class="nf">False</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The lack of precision comes from reassigning the substitute. In NSubstitute, later <code class="language-plaintext highlighter-rouge">.Returns()</code> calls override earlier ones for the same argument. Not ideal, but the tradeoff is worth it for the simplicity.</p>

<p>Naming is also worth thinking about. I like calling the setup <code class="language-plaintext highlighter-rouge">SetupHappyPath</code> explicitly. It tells the reader what the default state is, so there are no surprises.</p>

<p>The example above is contrived, but a lot of services I write tend to look more like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">DatabaseSizeProvider</span> 
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span><span class="p">?</span> <span class="nf">GetSize</span><span class="p">(</span><span class="n">DatabaseCredentials</span> <span class="n">credentials</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">dbService</span><span class="p">.</span><span class="nf">CreateConnection</span><span class="p">(</span><span class="n">credentials</span><span class="p">)</span> <span class="k">is</span> <span class="n">Connection</span> <span class="n">connection</span>
            <span class="p">&amp;&amp;</span> <span class="n">sqlService</span><span class="p">.</span><span class="nf">CreateGetSizeCommand</span><span class="p">(</span><span class="n">connection</span><span class="p">)</span> <span class="k">is</span> <span class="n">Command</span> <span class="n">command</span>
            <span class="p">&amp;&amp;</span> <span class="n">queryExecutor</span><span class="p">.</span><span class="nf">ExecuteQuery</span><span class="p">(</span><span class="n">command</span><span class="p">)</span> <span class="k">is</span> <span class="n">ResultSet</span> <span class="n">results</span>
            <span class="p">&amp;&amp;</span> <span class="n">resultParser</span><span class="p">.</span><span class="nf">ParseResult</span><span class="p">(</span><span class="n">results</span><span class="p">)</span> <span class="k">is</span> <span class="kt">int</span> <span class="n">size</span>
            <span class="p">?</span> <span class="n">size</span>
            <span class="p">:</span> <span class="k">null</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I keep coming back to this pattern. It’s precise, elegant, and reads cleanly top to bottom, everything a class should be. Ironically, happy path first unit tests are none of these things. They lack precision because of all the reassigning of substitutes. They’re not elegant, they rely on state in the class. And they don’t read top to bottom, because they hide logic in the setup. And honestly, I’m happy for that. Good tests should be practical, implicit, and hide boilerplate. Write code you’re proud of. Write tests that work. They don’t have to be the same thing.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Do unit tests make you happy? When they work, they make me ecstatic. For agentic coding, they let you fire and forget, knowing that as long as the unit tests pass, your existing code (probably) won’t be broken… Right?]]></summary></entry><entry><title type="html">Hitboard - Emulating Arcade Controllers on Keyboard.</title><link href="https://antikrem.github.io/hitboard/" rel="alternate" type="text/html" title="Hitboard - Emulating Arcade Controllers on Keyboard." /><published>2021-06-28T00:00:00+00:00</published><updated>2021-06-28T00:00:00+00:00</updated><id>https://antikrem.github.io/hitboard</id><content type="html" xml:base="https://antikrem.github.io/hitboard/"><![CDATA[<p>If you want to improve your execution without buying a crazy expensive mix box, this might be for you. Hitboard emulates arcade controllers on your keyboard through keyboard hooks and a virtual DirectX controller. Create a profile to emulate an existing controller, and pull off some sick combos!</p>
<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/coolcombo.mp4" type="video/mp4" />  
</video>

<h2 id="usages">Usages</h2>

<p>Primarily, the benefit of Hitboard is customising SOCD resolution. Different controllers have different ways of handling this to varying degrees of customization. With Hitboard, both cardinal axes can have separate and fully customizable resolutions.</p>

<h2 id="socd">SOCD?</h2>

<p>Simultaneous opposing cardinal directions! Unlike physical controllers with sticks, keyboards can press opposite directions at the same time, i.e. left and right, or up and down. How this situation is handled is up to the game, and different games handle it in different ways. A lot of 2D fighters will pick which input came out last, so holding down and tapping up will let you jump straight out of crouch. In Tekken, it comes out as neutral, but it also ignores all other face inputs. For example, left, down, and right pressed at the same time will be a neutral input. Currently, people will buy a $250 mixbox, which comes with options letting them decide how the SOCD is resolved. But for those who don’t feel like shilling out the money…</p>

<h2 id="enter-hitboard">Enter Hitboard</h2>

<p><img src="/images/2021-06-28-hitboard/gui.png" alt="Graphical interface" /></p>

<p>This application will map a virtual controller to the keyboard, with some options on both how to handle SOCD and the activation criteria. It also comes with the option to create and save configs as JSON files, for easier management.</p>

<h2 id="applications">Applications</h2>

<p>Here’s a few things in Tekken that I’ve been appreciating:</p>

<h3 id="fast-dash">Fast Dash</h3>

<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/insatantdash.mp4" type="video/mp4" />  
</video>

<p>This can be done by holding left and tapping right. The tap will cause a neutral input. Rather than tapping the same button twice, that has to be done sequentially, the left and right tap can be done slightly offset, leading to a faster dash.</p>

<h3 id="wave-dash">Wave Dash</h3>

<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/wavedash.mp4" type="video/mp4" />  
</video>

<p>SOCD doesn’t help much here, but it is really nice wave dashing on a keyboard over a stick. Tekken might be one of the few times I prefer to play a game at home rather than the arcade.</p>

<h3 id="giants-swing-from-wave-dash">Giant’s Swing from Wave Dash</h3>

<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/giantsswing.mp4" type="video/mp4" />  
</video>

<p>Giant’s Swing requires a half-circle input. At the bottom of the circle, pressing left, down, and right will usually drop the Giant’s Swing by putting a neutral in, but with SOCD it makes the input a touch faster than usual.</p>

<h3 id="ewgf">EWGF</h3>

<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/ewgf.mp4" type="video/mp4" />  
</video>

<p>Another one that doesn’t get a lot of help from SOCD. I just love electrics.</p>

<h3 id="iwr-shining-wizard">iWR Shining Wizard</h3>

<video autoplay="autoplay" loop="loop" muted="" display="block">  
  <source src="https://antikrem.github.io/images/2021-06-28-hitboard/instantshiningwizard.mp4" type="video/mp4" />  
</video>

<p>My favorite move in Tekken! Essentially, chain two fast dashes into it. SOCD really comes into play here, since it goes from 3 very fast taps right into holding right and tapping left twice.</p>

<h2 id="project">Project</h2>

<p>Feel free to <a href="https://github.com/antikrem/fraps_frametime_analysis">download the release from the repo</a> and get some free rank.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[If you want to improve your execution without buying a crazy expensive mix box, this might be for you. Hitboard emulates arcade controllers on your keyboard through keyboard hooks and a virtual DirectX controller. Create a profile to emulate an existing controller, and pull off some sick combos!]]></summary></entry><entry><title type="html">Frame Time Analysis</title><link href="https://antikrem.github.io/frame_time_analysis/" rel="alternate" type="text/html" title="Frame Time Analysis" /><published>2021-01-01T00:00:00+00:00</published><updated>2021-01-01T00:00:00+00:00</updated><id>https://antikrem.github.io/frame_time_analysis</id><content type="html" xml:base="https://antikrem.github.io/frame_time_analysis/"><![CDATA[<p>Ever play a game that feels chunky, but the frame rate counter looks fine? It takes a single frame coming out a fraction of a second too late to get me to notice, but most frame rate monitors squash outlier frames to simplify output. But these dropped frames are probably the most important of them all:
<img src="/images/2021-01-01-frame_time_analysis/1.png" alt="1.png" /></p>

<p>Fraps is probably the better monitor for frame rates but it’s in-game output is heavily averaged and hides outliers. The csv output when running a benchmark (default <code class="language-plaintext highlighter-rouge">F11</code>) is very detailed, but difficult to easily parse. Therefore, I wrote a script to do some data analysis and plot graphs:</p>

<h2 id="usage">Usage:</h2>

<ol>
  <li><a href="https://fraps.com/download.php">Download fraps</a>.</li>
  <li>Run the benchmark tool and copy any number of frame time result files (in the form <code class="language-plaintext highlighter-rouge">* frametimes.csv</code>) to the same directory as the script.</li>
  <li>Execute the script, it will load and analyse all relevant csv files in the same directory.</li>
</ol>

<h2 id="dependencies">Dependencies:</h2>
<ul>
  <li>matplotlib</li>
  <li>pandas</li>
  <li>scipy</li>
</ul>

<h2 id="examples">Examples:</h2>

<h3 id="touhou-10">Touhou 10</h3>
<p>As a benchmark, I used Touhou 10, since it has a really stable framerate with v-sync:</p>

<p><img src="/images/2021-01-01-frame_time_analysis/2.png" alt="2.png" /></p>

<p>With an output of:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Analysis of th10 2021-01-01 18-20-55-38 frametimes.csv
Frame Time Average 16.673191570881226
Frame Time Standard Deviation 0.17137165234384277
Frames Per Second Average 59.98284730571625
Frames Per Second Standard Deviation 0.6164196631241836
FPS Percentiles:
01: 58.32177222060414 10: 59.343659130021884
99: 61.81883951574242 90: 60.59651225166108
</code></pre></div></div>
<p>Which reflects the stable gameplay, with no outlier frames. The stable fps really compliments the gameplay, where a single frame dropped can easily lead to a death.</p>

<h3 id="halo-3">Halo 3</h3>
<p>I also wanted to try out the port of Halo 3 on MCC for the pc. This is probably the best port out of the MCC, but it still doesn’t feel perfect in combat:</p>

<p><img src="/images/2021-01-01-frame_time_analysis/3.png" alt="3.png" /></p>

<p>The frame drops are noticeable in both combat and non-combat sections. This makes me think there’s some sort of loading going on in the background thats storage limited. But it could just be the usual spaghetti that’s keeping MCC running. The overall impact isn’t too bad in theory, since the percentiles are quite good:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Frame Time Average 5.382341668561036
Frame Time Standard Deviation 5.900677549318819
Frames Per Second Average 220.48527275079527
Frames Per Second Standard Deviation 73.69543615204748
FPS Percentiles:
01: 79.23299856778335 10: 138.45813195990996
99: 426.27931886219443 90: 322.6847370119227
</code></pre></div></div>
<p>And Halo 3 isn’t too stressful, so the drops aren’t too big of a problem. Still a pretty good port.</p>

<h3 id="tekken">Tekken</h3>
<p>I swear anytime I play Tekken on highest settings I always drop combos with correct inputs. Even when it only using 70% of my GPU with vsync and a constant 60 fps, and there’s no way I’m just bad at Tekken (maybe). The dropped frames I suspected are pretty evident:</p>

<p><img src="/images/2021-01-01-frame_time_analysis/4.png" alt="4.png" /></p>

<p>So my FADCs aren’t just subpar, just swallowed by dropped frames (some at least, I suspect I could also just be bad). Its pretty annoying to run games at very low settings just to avoid the one in a thousand dropped frames. One would expect a bit more love spent to optimise these aspects by developers, which leads to the original purpose of this script.</p>

<h2 id="motivation">Motivation</h2>
<p>The initial motive was to explain some of some chunky behaviour of my engine. The gameplay is really fun, with relatively high framerates, but the occasional frame drops are hard to ignore:</p>

<p><img src="/images/2021-01-01-frame_time_analysis/5.png" alt="5.png" /></p>

<p>The frame drops occur once every 10ms. Interestingly, the garbage collection is also on a 10ms timer. Initially I though the frame drops have to do with either the script queue being saturated when picking up powerups or a different tick rate between position updates and rendering. At this point, I’m pretty sure it’s the garbage collector locking all other threads when being run.</p>

<p>Unfortunately, I wrote the garbage collector to not lock other threads when reclaiming resources. This might be tricky to fix, since it will involve finding a tacit lock.</p>

<h2 id="conclusion">Conclusion</h2>
<p>Generally, I dislike reviews of video games that don’t give any performance metrics. And any performance metrics tend to be a mean. Some ports do suffer pretty badly from dropped frames, and it would be nice to get a bit of a warning for some example hardware.</p>

<p>On the other side of the coin, I dislike games that don’t try to optimise away frame drops, especially when its a bottle neck that could be avoided with a bit of threading, a relaxed lock or a smart design patern.</p>

<p>This script is released under the Unlicense, <a href="https://github.com/antikrem/fraps_frametime_analysis">so feel free to use and modify as much as desired</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Ever play a game that feels chunky, but the frame rate counter looks fine? It takes a single frame coming out a fraction of a second too late to get me to notice, but most frame rate monitors squash outlier frames to simplify output. But these dropped frames are probably the most important of them all:]]></summary></entry><entry><title type="html">Solving Two Body Intercept in 2D with Unknown Angle</title><link href="https://antikrem.github.io/Solving_Two_Body_Intercept_in_2D/" rel="alternate" type="text/html" title="Solving Two Body Intercept in 2D with Unknown Angle" /><published>2020-12-21T00:00:00+00:00</published><updated>2020-12-21T00:00:00+00:00</updated><id>https://antikrem.github.io/Solving_Two_Body_Intercept_in_2D</id><content type="html" xml:base="https://antikrem.github.io/Solving_Two_Body_Intercept_in_2D/"><![CDATA[<p>Interesting problem: given a starting position and a constant speed, compute the angle to intercept another object moving at a constant velocity. <img src="/images/2020-12-21-Solving_Two_Body_Intercept_in_2D/1.png" alt="_display_of_two_body_intercept" />
This is a common issue in a few places such as real time collision physics. Some other obvious examples come to mind as well, such as AI aiming in FPS and target leads in flight action games.</p>

<p>A casual google will find only <a href="https://www.codeproject.com/Articles/990452/Interception-of-Two-Moving-Objects-in-D-Space">one acceptable solution</a>. However, its a slightly over complicated trigonometric derivation. Also, the resulting angle will be relative to the vector from the source to destination, rather than absolute. 
A nicer solution can be done by simply solving the linear system derived from the finite difference model of the objects position.</p>

<h1 id="solution">Solution</h1>
<p>Consider an object with initial position \( \vec{p_0}={p_x, p_y} \) at constant speed \(s\) and unknown angle \(\theta\). The target begins at \(\vec{q_0}={q_x, q_y}\) with velocity \(\vec{v}={v_x, v_y}\). The intersect time will be</p>

<p>\[t^{*} =\frac{(2 j v_x + 2 k v_y)\pm \sqrt{(-2 j v_x - 2 k v_y)^2-4(s^2 - {v_x}^2 - {v_y}^2)(- j^2 - k^2)}}{2(s^2 - {v_x}^2 - {v_y}^2)} \]</p>

<p>With \(j = p_x-q_x\) and \(j = p_y-q_y\).</p>

<p>And the angle being:</p>

<p>\[\theta = \arctan{\frac{k+t^{*} v_y}{j+t^{*} v_x }}\]</p>

<h1 id="derivation">Derivation</h1>
<p>To begin with, each objects position at time \(t\) will be:</p>

<p>\[\vec{p_t} = \vec{p_0}+\vec{v}t\]</p>

<p>\[\vec{q_t} = {q_x + s t \cos{\theta}, q_y+s t \sin{\theta}}\]</p>

<p>As the goal is to solve for \(p_t=q_t\) for some \(t=t^*\), the system of equations can be set up as follows:</p>

<p>\[q_x+t^{*} s \cos{\theta} = p_x+t^{*} v_x\]</p>

<p>\[q_y+t^{*} s \sin{\theta} = p_y+t^{*} v_y\]</p>

<p>Which can be rearranged as so:</p>

<p>\[\cos{\theta} = \frac{a+t^{*} v_x}{t^{*} s}\]</p>

<p>\[\sin{\theta} = \frac{b+t^{*} v_y}{t^{*} s}\]</p>

<p>With \(j = p_x-q_x\) and \(j = p_y-q_y\).</p>

<p>The unknown \(\theta\) can be removed by equating these expressions without loss of generality:</p>

<p>\[\arccos{ \bigg{(} \frac{j+t^{*} v_x}{t^{*} s} \bigg{)}} = \arcsin{ \bigg{(} \frac{k+t^{*} v_y}{t^{*} s} \bigg{)} } \]</p>

<p>The trigonometric functions can be simplified out with the identity \( \sin{(\arccos{x})} = \sqrt{1-x^2} \):</p>

<p>\[\sqrt{ 1-\bigg{(}\frac{j+t^{*} v_x}{t^{*} s} \bigg{)}^2 } = \frac{k+t^{*} v_y}{t^{*} s} \]</p>

<p>\[ 1-\bigg{(}\frac{j+t^{*} v_x}{t^{*} s} \bigg{)}^2  = \bigg{(} \frac{k+t^{*} v_y}{t^{*} s} \bigg{)}^2 \]</p>

<p>Multiplying both sides by \({t^{*}}^2 s^2\):</p>

<p>\[{t^{*}}^2 s^2-(j+t^{*} v_x)^2  = (k+t^{*} v_y)^2 \]</p>

<p>\[{t^{*}}^2 s^2-j^2-2 j t^{*} v_x - {t^{*}}^2 {v_x}^2 = k^2 + 2 k t^{*} v_y + {t^{*}}^2{v_y}^2\]</p>

<p>\[{t^{*}}^2 (s^2 - {v_x}^2 - {v_y}^2) + t^{*}(-2 j v_x - 2 k v_y) + (- j^2 - k^2) = 0 \]</p>

<p>This gives a quadratic on \(t^{*}\), which can be solved with the quadratic formula:</p>

<p>\[a = s^2 - {v_x}^2 - {v_y}^2 \]</p>

<p>\[b = -2 j v_x - 2 k v_y \]</p>

<p>\[c = - j^2 - k^2 \]</p>

<p>\[t^{*} =\frac{-b\pm \sqrt{b^2-4ac}}{2a} \]</p>

<h2 id="interpreting-t">Interpreting \(t^{*}\)</h2>
<p>The quadratic formula has two solutions. Each solution has four possible states (ignoring zero):</p>

<h4 id="negative">Negative</h4>
<p>This indicates that a collision, i.e. \(p_t=q_t\) would have been possible at an earlier time. Generally, at most 1 solution will be negative, especially when the source’s position lies almost perpendicular to the target’s velocity.</p>

<h4 id="non-real">Non-Real</h4>
<p>Such a solution is due to parameters not allowing a solution. An example is a target thats moving away from the source faster than \(s\). As expected, with impossible parameters both solutions will be non-real.</p>

<h4 id="undefined">Undefined</h4>
<p>When \(a = s^2 - {v_x}^2 - {v_y}^2 = 0\), there is a division by zero. Such a case occurs when both objects have the same speed. Outside of the degenerate case, a collision would not be possible, and solutions to the quadratic fomula will be undefined.</p>

<h4 id="positive">Positive</h4>
<p>A positive real solution is workable.</p>

<h3 id="choosing-solution">Choosing solution</h3>
<p>Negative and non-real solutions should be discarded. Given valid parameters, either one or two positive solutions will be generated. Two positive solutions occur when two angles exist that cause intercept.</p>

<p>In this case, generally just choose the smaller solution for consistency. For application (especially gameplay), choosing the faster collision is useful, as the target has less time to change velocity.</p>

<p>When no positive real solution is possible, the model is simply not solvable. No angle exists that can cause an intersection. In this case, using the direct angle to target is probably the most graceful backup, though exceptions and error codes might be more your style.</p>

<h2 id="solving-angle">Solving Angle</h2>
<p>Solving for \(\theta\) also comes from the system of equations:
\[t^{*} s  = \frac{j+t^{*} v_x}{\cos{\theta}}\]</p>

<p>\[t^{*} s = \frac{k+t^{*} v_y}{\sin{\theta} }\]</p>

<p>Which can be equated:</p>

<p>\[\frac{j+t^{*} v_x}{\cos{\theta}} = \frac{k+t^{*} v_y}{\sin{\theta} }\]</p>

<p>\[\frac{\sin{\theta}}{\cos{\theta}} = \frac{k+t^{*} v_y}{j+t^{*} v_x }\]</p>

<p>And recalling \(\tan{\theta}=\sin{\theta}/\cos{\theta}\):</p>

<p>\[\tan{\theta} = \frac{k+t^{*} v_y}{j+t^{*} v_x }\]</p>

<p>\[\theta = \arctan{\frac{k+t^{*} v_y}{j+t^{*} v_x }}\]</p>

<p>In execution, <code class="language-plaintext highlighter-rouge">atan2</code> would need to be used over simple <code class="language-plaintext highlighter-rouge">arctan</code> to avoid incorrect solutions due to the periodic behaviour of tan.</p>

<h1 id="implementation">Implementation</h1>
<p>An implementation was made in lua:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function solve_angle_to_moving_player(qx, qy, s, px, py, vx, vy)
    local j = px - qx;
    local k = py - qy;

    -- Solution is in the form of a quadratic
    local a = (vy^2 + vx^2 - s^2);
    local b = (2*j*vx + 2*k*vy);
    local c = (j^2 + k^2);

    local t0, t1 = math.solve_quadratic(a, b, c)

    -- Select smallest non negative solution
    local solutions = {math.strip_negatives(t0, t1)}
    local t_star = nil
    if #solutions &gt; 0 then
        t_star = math.min(unpack(solutions))
    else
        return nil;
    end

    local theta = 0

    -- If no solution, then get simple angle, else solve for theta
    if is_nil(t_star) then
        theta = get_angle_to(px, py, qx, qy)
    else
        theta = math.to_degrees(math.atan2((k + t_star * vy), (j + t_star * vx)))
    end

    return theta
end
</code></pre></div></div>
<p>This implementation will only return the closest solution, and returns <code class="language-plaintext highlighter-rouge">nil</code> on no solution.</p>

<h1 id="application">Application</h1>
<p>This was originally derived for a bullet pattern that predicts the player’s movement. The idea being this encourages quick reaction time, control over movement and understanding of mechanics to quickly change direction.</p>

<video autoplay="autoplay" loop="loop" muted="" display="block">
  <source src="https://antikrem.github.io/images/2020-12-21-Solving_Two_Body_Intercept_in_2D/two_body.mp4" type="video/mp4" />
</video>

<p>Its as fun as it looks. While I’m dodging some really fast bullets, since I have a lot of control over where they go with my movement, I can make sure I keep them directed far from me. This makes it deceptivly easy with some stratergy and control over positioning and movement, which is key in bullet hell games. Mixing in a few directly targeted bullets adds an extra level of fun, since those need to be dodged more cenventionally. Shifting between the three modes of movement (focus, regular and dash) gives best results, and this is some of the funner parts of most bullet hell games.</p>

<p>Overall, pretty cool. I’ll do an N-dimension generalisation soon, as soon as I can work it out.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Interesting problem: given a starting position and a constant speed, compute the angle to intercept another object moving at a constant velocity. This is a common issue in a few places such as real time collision physics. Some other obvious examples come to mind as well, such as AI aiming in FPS and target leads in flight action games.]]></summary></entry><entry><title type="html">Colourise Shader</title><link href="https://antikrem.github.io/Colourise/" rel="alternate" type="text/html" title="Colourise Shader" /><published>2020-12-17T00:00:00+00:00</published><updated>2020-12-17T00:00:00+00:00</updated><id>https://antikrem.github.io/Colourise</id><content type="html" xml:base="https://antikrem.github.io/Colourise/"><![CDATA[<p>A common required task is to apply a colourisation in a fragment shader, but all the online implementations are just plain awful. The top results from a google search will get either a <a href="https://gamedev.stackexchange.com/questions/75923/colorize-with-a-given-color-a-texture">multiplicative modulation</a> or some <a href="https://gist.github.com/baba-s/4a81861a8c963a68a862ada545b0100f">arbitary linear combination</a>. What I really want is that lovely GIMP colorise…
<img src="/images/2020-12-17-Colourise/1.png" alt="_config.yml" /></p>

<p>Notice how the white middle stays white with GIMP’s colourise. Strongly bright objects apear white, even if the output isn’t constant over the colour spectrum. A good example is the sun, which is white, despite having <a href="https://wtamu.edu/~cbaird/sq/2013/07/03/what-is-the-color-of-the-sun/">non-uniform output at different frequencies</a>. If I wanted to colourise a picture of the sun at midday, I would expect the brightest part to remain white.</p>

<p>I would also expect the brightness to stay the same across the image. The above colourise shaders darken the image. GIMP’s colourise preserves luminance, which is probably why it looks the best.</p>

<h1 id="gimp-tribute-act">GIMP Tribute Act</h1>
<p>As GIMP is free and open-source software, instead of trying to back-engineer their colorise filter we can <del>steal</del> take inspiration from their algorithm. Specifically, 
<a href="https://github.com/GNOME/gimp/blob/master/app/operations/gimpoperationcolorize.c">gimpoperationcolorize.c</a> contains the implementation of <code class="language-plaintext highlighter-rouge">gimp_operation_colorize_process(...)</code> at line 222, with the relevent part being:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if (colorize-&gt;lightness &gt; 0)
  {
    lum = lum * (1.0 - colorize-&gt;lightness);

    lum += 1.0 - (1.0 - colorize-&gt;lightness);
  }
  else if (colorize-&gt;lightness &lt; 0)
  {
    lum = lum * (colorize-&gt;lightness + 1.0);
  }

  hsl.l = lum;

  gimp_hsl_to_rgb (&amp;hsl, &amp;rgb);
</code></pre></div></div>

<p>GIMP’s colourise take HSL rather than RGB for incoming colour, which has the added benefit of being easier for artists. Also, the ranges for the input HSL is not <code class="language-plaintext highlighter-rouge">(0-1, 0-1, 0-1)</code>. I would like the standard for all color values in shaders I right to be between 0 and 1, so that had to be modified.</p>

<p>In all seriousness, while being inspired by an algorithm used in a GPL Program and writing an implementation in a different language is a grey area, the resulting shader function is technically derived work. Thus, it would fall under GPLv3 and related usage restrictions.</p>

<h1 id="implementation">Implementation</h1>
<p>I wrote an <a href="https://www.shadertoy.com/view/wdKfDc">implementation in shader toy</a>, the important part is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vec3 colourise(vec3 hsl, vec3 texel) {
    float lum = dot(texel, vec3(0.2126, 0.7152, 0.0722));
    
    hsl.b = 2.0 * hsl.b - 1.0;
    
    if (hsl.b &gt; 0.0) {
    	lum = lum * (1.0 - hsl.b);
        lum += 1.0 - (1.0 - hsl.b);
    }
    else if (hsl.b &lt; 0.0) {
        lum = lum * (hsl.b + 1.0);
    }
    
    return hsl2rgb(vec3(hsl.rg, lum));
}
</code></pre></div></div>

<h1 id="application">Application</h1>
<p>And using a bullet asset, its possible to see how closely it matches GIMP with a hsl of (0.0, 0.75, 0.55):</p>

<p><img src="/images/2020-12-17-Colourise/2.png" alt="_config.yml" /></p>

<p>Doesn’t look great, but this is because the alpha in shader toy doesn’t work so good. The important thing is the colours, which look almost exact.</p>

<p>A better demonstration is in my engine. With a script to spawn some bullets with incrementing hues alongside some bloom and HDR, this looks like so:</p>

<p><img src="/images/2020-12-17-Colourise/3.gif" alt="_config.yml" /></p>

<p>Really nice. I can save dev time and texture atlas space by letting the shaders colourise in realtime. It also makes scripting easier, with colourisation being seperated from the assets.</p>

<h1 id="conclusion">Conclusion</h1>
<p>Preserving luminance makes this look better than other colourise algorithms. I recommend using this type of colourise over the usual on stack overflow.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A common required task is to apply a colourisation in a fragment shader, but all the online implementations are just plain awful. The top results from a google search will get either a multiplicative modulation or some arbitary linear combination. What I really want is that lovely GIMP colorise…]]></summary></entry><entry><title type="html">Simulating Bird-oid Objects</title><link href="https://antikrem.github.io/HPC_boids/" rel="alternate" type="text/html" title="Simulating Bird-oid Objects" /><published>2020-12-15T00:00:00+00:00</published><updated>2020-12-15T00:00:00+00:00</updated><id>https://antikrem.github.io/HPC_boids</id><content type="html" xml:base="https://antikrem.github.io/HPC_boids/"><![CDATA[<p>As a part of HPC, I has to do a big semester long project. Specifically, I would need to do some simulation, demonstrate issues with scalability and implement some parallelisation to achieve performance with large working sets. This project ended up being quite fun, with a nice combination of real time rendering, multithreaded algorithm optimisation and data analysis.
<img src="/images/2020-12-15-HPC_boids/1.gif" alt="_config.yml" />
It also helped that I got to run stuff on UQ’s fancy <a href="https://research.smp.uq.edu.au/computing/getafix.html">HPC clusters</a> with some cool visual output, quite fun indeed.</p>

<p>As infered from the above gif, my project was on <a href="https://www.red3d.com/cwr/boids/">boids</a>, which is a multiagent simulation that replicates the flocking of birds, fishes and other flocking creatures. This project came our nicer than I expected, with some novel additions on my end, so here are some highlights from my report:</p>

<h2 id="optimised-multithreaded-algorithm">Optimised Multithreaded Algorithm</h2>
<p>My first implementation of multithreading in psuedo-code looked something like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i = 0 to frame count

	make thread group
	
	for each relevant boid (managed by #pragma omp for)
		do boid step
	
	for each relevant boid (managed by #pragma omp for)
		do update
	
	close thread group
	
end for
</code></pre></div></div>

<p>Observe how the boidal update is split into <code class="language-plaintext highlighter-rouge">do boid step</code> and <code class="language-plaintext highlighter-rouge">do update</code>. The first updates individual boid’s velocities based on surrounding near neighbours, while the second uses each boids velocity to update its position. Splitting this into 2 steps allows a single lock between these steps, rather than a lock on each boid’s position access, neat.</p>

<p>For each frame of the simulation, I would create a thread group of <code class="language-plaintext highlighter-rouge">N</code> size, and OpenMP will manage allocating boids to each thread. After executing the boid rules and updating position, the thread group would be destroyed and a new one would be created for the next thread. A rather large improvement I made was creating a thread group for all the frames, and manually allocating which boids are allocated to each thread:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make thread group
calculate which boids are allocated to update
for i = 0 to frame count
	
	wait for other threads
	
	for each allocated boid
		do boid step
	
	wait for other threads	
	
	for each allocated boid
		do update
	
end for
close thread group
</code></pre></div></div>

<p>And testing was able to show improvement with 500,000 frames over 4 threads with a variable number of boids (measured in microseconds per frame):</p>

<table>
  <thead>
    <tr>
      <th>Boid Count</th>
      <th>20</th>
      <th>40</th>
      <th>60</th>
      <th>80</th>
      <th>100</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Old Time</td>
      <td>12</td>
      <td>28</td>
      <td>55</td>
      <td>89</td>
      <td>130</td>
    </tr>
    <tr>
      <td>Improved</td>
      <td>5</td>
      <td>18</td>
      <td>39</td>
      <td>68</td>
      <td>103</td>
    </tr>
  </tbody>
</table>

<p>Intrestingly, at larger counts with a frame count of 20, the same trend continues, implying my manual allocation is also a contributing factor to the improved performance.</p>

<table>
  <thead>
    <tr>
      <th>Boid Count</th>
      <th>2000</th>
      <th>4000</th>
      <th>6000</th>
      <th>8000</th>
      <th>10000</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Old Time</td>
      <td>72135</td>
      <td>286330</td>
      <td>643796</td>
      <td>1143673</td>
      <td>1786425</td>
    </tr>
    <tr>
      <td>Improved</td>
      <td>36116</td>
      <td>143167</td>
      <td>321982</td>
      <td>575807</td>
      <td>893276</td>
    </tr>
  </tbody>
</table>

<p>The important takeaway is to use thread pools over spawning a thread for each workload. Useful for game engines, with my latest using a unified thread pool over the old method of spawning new threads per sync point.</p>

<h2 id="deterministic-scattering">Deterministic Scattering</h2>

<p>The regular behaviour for boids can get pretty boring, with the simulation tending towards a single large group. Thus, some sort of scattering to break up groups is generally implemented, with my twist on the formula being deterministic scattering.</p>

<p><img src="/images/2020-12-15-HPC_boids/2.gif" alt="_config.yml" /></p>

<p>Scattering is actually deterministic, with each boid <code class="language-plaintext highlighter-rouge">b_i</code> being rotated by <code class="language-plaintext highlighter-rouge">360 * i/N</code>, where <code class="language-plaintext highlighter-rouge">N</code> is the total number of boids. This is better for two reasons:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">rand()</code> is not thread-safe, thus a lock would be required to avoid race conditions, reducing performance.</li>
  <li>Different order of <code class="language-plaintext highlighter-rouge">rand()</code> calls can result in non-deterministic output, even with a lock.</li>
</ul>

<p>This ended up with a deterministic, performant output, that basically looks random. In future, I think this sort of faux randomness would be interesting to implement. Some sort of array of precomputed random numbers, that are incremented along would be very interesting, especially with a lockless atomic integer incrementer.</p>

<h2 id="results">Results</h2>
<p>Thanks to all the efforts made to avoid locks and other inefficiencies, the final simulation was able to have almost perfect parallelisation.</p>

<p><img src="/images/2020-12-15-HPC_boids/3.png" alt="_config.yml" /></p>

<p>In fact, when performance is compared as a ratio to performance with a single core, it can be seen that the simulation scales almost perfectly.</p>

<p><img src="/images/2020-12-15-HPC_boids/4.png" alt="_config.yml" /></p>

<p>These graphs were also fun to make, with automated scripts really saving the day (and saving me an all-nighter collecting results). Overall, cosc3500 is a great course, and I do recommend it.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[As a part of HPC, I has to do a big semester long project. Specifically, I would need to do some simulation, demonstrate issues with scalability and implement some parallelisation to achieve performance with large working sets. This project ended up being quite fun, with a nice combination of real time rendering, multithreaded algorithm optimisation and data analysis. It also helped that I got to run stuff on UQ’s fancy HPC clusters with some cool visual output, quite fun indeed.]]></summary></entry></feed>