Friday, 26 August 2022

Web Tutorial: The Collision Detector

Video games, particularly of the side-scrolling shooter variety, all have collision detection as a mechanic. I've often run into needing to solve those problems. What I needed was a utility of some kind, to tell me when one object is sharing the same space as another object in a two-dimensional area.

And I have made just such a utility, using VueJS. The use of VueJS was to shorten development time; what really matters is that the formula I use to determine collision, is correct and can be visually proven to be correct.

In this context, one object can be said to have "collided" with another, if horizontally and vertically their coordinates intersect. I'll expound on that later, but for now, here's some code. The HTML includes one div with the id cdApp, a remote link to VueJS and the instantiation of the Vue object.

<html>
    <head>
        <title>Collision Detection Utility</title>

        <style>

        </style>
    </head>

    <body>
        <div id="cdApp">

        </div>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>

        <script>
            var app = new Vue
            (

            );
        </script>
    </body>
</html>


I'm going to go through the next few bits really fast, because they aren't all that important to the final product. Within the cdApp div, we have a few other divs. The classes are dashboard, notice and space. dashboard is to house all the controls we will need, notice is for the displaying of messages, and space is the visual representation of the two objects and their coordinates.
<div id="cdApp">
    <div class="dashboard">

    </div>

    <div class="notice">

    </div>

    <div class="space">

    </div>

</div>


In the styling, note that we have given all divs a red outline to provide visibility. cdApp is going to take up full width and height of the screen. The position property is set to absolute, and the top and left properties are 0.
<style>
    div { outline: 1px solid red;}

    #cdApp
    {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
    }

</style>


dashboard, notice and space all take up full width, but have varying heights. For notice, I have set text to be aligned center and given a top and bottom border. For space, I have set a translucent orange background.
<style>
    div { outline: 1px solid red;}

    #cdApp
    {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
    }

    .dashboard
    {
        position: relative;
        width: 100%;
        height: 25%;
    }

    .notice
    {
        position: relative;
        width: 100%;
        height: 3%;
        text-align: center;
        border-top: 1px solid black;
        border-bottom: 1px solid black;
    }

    .space
    {
        position: relative;
        width: 100%;
        height: 72%;
        background-color: rgba(255, 200, 0, 0.1);
    }

</style>


This is what I intend.




Now let us build the dashboard. There are basically two sets of controls - one for each object.
<div class="dashboard">
    <fieldset>
        <legend>Obj A</legend>
    </fieldset>

    <fieldset>
        <legend>Obj B</legend>
    </fieldset>

</div>


For neatness, we will style fieldsets by fixing widths and heights, floating left and making sure the display property is set to block.
.space
{
    position: relative;
    width: 100%;
    height: 72%;
    background-color: rgba(255, 200, 0, 0.1);
}

fieldset
{
    width: 20em;
    height: 10em;
    float: left;
    display: block;
}


Each fieldset will have four range inputs - for left margin, top margin, width and height. Note the values and attributes - these are going to reflect the initial values for the two objects.
<div class="dashboard">
    <fieldset>
        <legend>Obj A</legend>
        <br /><label>Obj A Left</label><input type="range" min="0" max="300" value="10" step="1">
        <br /><label>Obj A Top</label><input type="range" min="0" max="300" value="10" step="1">
        <br /><label>Obj A Width</label><input type="range" min="0" max="300" value="100" step="1">
        <br /><label>Obj A Height</label><input type="range" min="0" max="300" value="100" step="1">

    </fieldset>

    <fieldset>
        <legend>Obj B</legend>
        <br /><label>Obj B Left</label><input type="range" min="0" max="300" value="50" step="1">
        <br /><label>Obj B Top</label><input type="range" min="0" max="300" value="50" step="1">
        <br /><label>Obj B Width</label><input type="range" min="0" max="300" value="300" step="1">
        <br /><label>Obj B Height</label><input type="range" min="0" max="300" value="300" step="1">

    </fieldset>
</div>


And here are the controls. It doesn't look pretty, but it doesn't need to.




In this next div, add this text. This is supposed to be a visual indicator to tell you if collision has been achieved.
<div class="notice">
    H: |
    V: |
    Collision:

</div>


Not much to look at, but it'll do... for now.




For the final div, this is where your objects are visually represented. Add these divs. They will both be styled using obj, then objA and objB respectively. Do not bother refreshing your browser; you won't see anything because their heights and widths aren't even specified.
<div class="space">
    <div class="obj objA"></div>
    <div class="obj objB"></div>

</div>


Now for some VueJS!

Our intention is to take advantage of VueJS's two-way binding feature. Before that happens, we will need to specify some data and methods. First. use the el property to specify that VueJS will operate in the cdApp div. Then specify data, methods and created as properties. created is a callback which fires off when the page loads.
<script>
    var app = new Vue
    (
        {
            el: "#cdApp",
            data:
            {

            },
            methods:
            {

            },
            created: function()
            {

            }
        }

    );
</script>


In data, we declare v, h and collision. All of them are false by default.
data:
{
    v: false,
    h: false,
    collision: false

},


Then we have the objA and objB properties. Each is an object that has top, left, width and height properties. Note that the values for these properties correspond to the initial values we set for the controls!
data:
{
    v: false,
    h: false,
    collision: false,
    objA: { left: 10, top: 10, width: 100, height: 100},
    objB: { left: 50, top: 50, width: 300, height: 300}

},


Remember the divs we put in the div that has the CSS class space? Let's now specify styles for these divs. They will take their values from the objA and objB object properties.
<div class="space">
    <div class="obj objA" style="left: {{ objA.left }}px; top: {{ objA.top }}px; width: {{ objA.width }}px; height: {{ objA.height }}px;"></div>
    <div class="obj objB" style="left: {{ objB.left }}px; top: {{ objB.top }}px; width: {{ objB.width }}px; height: {{ objB.height }}px;"></div>
</div>


In the CSS, make sure obj has position property set to absolute. For objA, we have a blue outline and for objB, we have a green outline. This is to visually differentiate the two objects; the colors don't matter that much as long as they are both different.
.space
{
    position: relative;
    width: 100%;
    height: 72%;
    background-color: rgba(255, 200, 0, 0.1);
}

.obj
{
    position: absolute;
}

.objA
{
    outline: 1px solid blue;
}

.objB
{
    outline: 1px solid green;
}


fieldset
{
    width: 20em;
    height: 10em;
    float: left;
    display: block;
}


The plot thickens! Now you can see your objects.




Let us now use the v-model attribute and set it to the left property of the objA object. This leverages on VueJS's two-way binding. Thus, when the value of this input changes, the left property of  the objA object will change, and vice versa.
<fieldset>
    <legend>Obj A</legend>
    <br /><label>Obj A Left</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.left">
    <br /><label>Obj A Top</label><input type="range" min="0" max="300" value="10" step="1">
    <br /><label>Obj A Width</label><input type="range" min="0" max="300" value="100" step="1">
    <br /><label>Obj A Height</label><input type="range" min="0" max="300" value="100" step="1">
</fieldset>


Add this to reflect the value of the left property at any time.
<fieldset>
    <legend>Obj A</legend>
    <br /><label>Obj A Left</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.left"> {{ objA.left }}
    <br /><label>Obj A Top</label><input type="range" min="0" max="300" value="10" step="1">
    <br /><label>Obj A Width</label><input type="range" min="0" max="300" value="100" step="1">
    <br /><label>Obj A Height</label><input type="range" min="0" max="300" value="100" step="1">
</fieldset>


Now adjust the value of the first slider. The number should change! And notice that since we tied the left property of the objA object to the left property of the blue square, it moves when you change the value!




Do the same for all the other inputs. They should control the left, top, width and height properties of the objA and objB objects accordingly.
<fieldset>
    <legend>Obj A</legend>
    <br /><label>Obj A Left</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.left"> {{ objA.left }}
    <br /><label>Obj A Top</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.top"> {{ objA.top }}
    <br /><label>Obj A Width</label><input type="range" min="0" max="300" value="100" step="1" v-model="objA.width"> {{ objA.width }}
    <br /><label>Obj A Height</label><input type="range" min="0" max="300" value="100" step="1" v-model="objA.height"> {{ objA.height }}
</fieldset>

<fieldset>
    <legend>Obj B</legend>
    <br /><label>Obj B Left</label><input type="range" min="0" max="300" value="50" step="1" v-model="objB.left"> {{ objB.left }}
    <br /><label>Obj B Top</label><input type="range" min="0" max="300" value="50" step="1" v-model="objB.top"> {{ objB.top }}
    <br /><label>Obj B Width</label><input type="range" min="0" max="300" value="300" step="1" v-model="objB.width"> {{ objB.width }}
    <br /><label>Obj B Height</label><input type="range" min="0" max="300" value="300" step="1" v-model="objB.height"> {{ objB.height }}
</fieldset>


Now the two objects should change shape and location when you change the values of the inputs!




Detecting Collision

The final thing we are going to do here, is calculate whether objA and objB have collided. For that, there are two components - the display and the calculation. The display is fairly straightforward. Just create the getCollision() method. The prop parameter is what's used to determine what data we examine. By default, return the string "No".
methods:
{
    getCollision: function(prop) {
        return "No";
    }

},


However, if the property in Vue's data is true, return "Yes".
methods:
{
    getCollision: function(prop) {
        if (this[prop]) return "Yes";
        return "No";
    }
},


In the HTML, add these calls to the getCollision() method.
<div class="notice">
    H: {{ getCollision('h') }} |
    V: {{ getCollision('v') }} |
    Collision: {{ getCollision('collision') }}
</div>


And now you see the strings "No", in the display. Even though the two objects are obviously collided. That's because all the data is false right now and we have no mechanism to change those values. That will be fixed with the introduction of detectCollision()!




First, create the method.
methods:
{
    getCollision: function(prop) {
        if (this[prop]) return "Yes";
        return "No";
    },
    detectCollision: function() {

    }

},


Here, we create the variables h, v and collided and set them to false. Then at the end, we set collided to true if both h and v are true.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (h && v) collided = true;

}


After that, we set the h, v and collided properties to have the same values as their counterparts in this method.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (h && v) collided = true;

    this.h = h;
    this.v = v;
    this.collision = collided;

}


This next part is for us to calculate h and v. h is the horizontal, and v is the vertical. collided can only be true when both h and v are true, which means objA and objB's horizontal and vertical coordinates both intersect.

So we check this. The left property of objA has to fall between the left property of objB and its rightmost corner (which is objB's left property plus its width property). If that is true, h is true.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (this.objA.left >= this.objB.left && this.objA.left <= this.objB.left + this.objB.width)  h = true;

    if (h && v) collided = true;

    this.h = h;
    this.v = v;
    this.collision = collided;
}


h can also be true if, conversely, the left property of objB falls between the left property of objA and its rightmost corner.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (this.objA.left >= this.objB.left && this.objA.left <= this.objB.left + this.objB.width)  h = true;
    if (this.objA.left <= this.objB.left && this.objA.left + this.objA.width >= this.objB.left) h = true;

    if (h && v) collided = true;

    this.h = h;
    this.v = v;
    this.collision = collided;
}


Now, for v. If the top property of objA falls between the top property of objB and its bottom (which is the top property of objB plus the height property of objB), then v is true.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (this.objA.left >= this.objB.left && this.objA.left <= this.objB.left + this.objB.width)  h = true;
    if (this.objA.left <= this.objB.left && this.objA.left + this.objA.width >= this.objB.left) h = true;

    if (this.objA.top >= this.objB.top && this.objA.top <= this.objB.top + this.objB.height) v = true;

    if (h && v) collided = true;

    this.h = h;
    this.v = v;
    this.collision = collided;
}


Also, if the top property of objB falls between the top property of objA and its bottom, then v is true.
detectCollision: function() {
    var collided = false;
    var h = false;
    var v = false;

    if (this.objA.left >= this.objB.left && this.objA.left <= this.objB.left + this.objB.width)  h = true;
    if (this.objA.left <= this.objB.left && this.objA.left + this.objA.width >= this.objB.left) h = true;

    if (this.objA.top >= this.objB.top && this.objA.top <= this.objB.top + this.objB.height) v = true;
    if (this.objA.top <= this.objB.top && this.objA.top + this.objA.height >= this.objB.top) v = true;

    if (h && v) collided = true;

    this.h = h;
    this.v = v;
    this.collision = collided;
}


Make sure detectCollision() is called upon page load.
created: function()
{
    this.detectCollision();
}


And also called whenever any of the input values change. Use the v-on:change attribute.
<fieldset>
    <legend>Obj A</legend>
    <br /><label>Obj A Left</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.left" v-on:change="detectCollision"> {{ objA.left }}
    <br /><label>Obj A Top</label><input type="range" min="0" max="300" value="10" step="1" v-model="objA.top" v-on:change="detectCollision"> {{ objA.top }}
    <br /><label>Obj A Width</label><input type="range" min="0" max="300" value="100" step="1" v-model="objA.width" v-on:change="detectCollision"> {{ objA.width }}
    <br /><label>Obj A Height</label><input type="range" min="0" max="300" value="100" step="1" v-model="objA.height" v-on:change="detectCollision"> {{ objA.height }}
</fieldset>

<fieldset>
    <legend>Obj B</legend>
    <br /><label>Obj B Left</label><input type="range" min="0" max="300" value="50" step="1" v-model="objB.left" v-on:change="detectCollision"> {{ objB.left }}
    <br /><label>Obj B Top</label><input type="range" min="0" max="300" value="50" step="1" v-model="objB.top" v-on:change="detectCollision"> {{ objB.top }}
    <br /><label>Obj B Width</label><input type="range" min="0" max="300" value="300" step="1" v-model="objB.width" v-on:change="detectCollision"> {{ objB.width }}
    <br /><label>Obj B Height</label><input type="range" min="0" max="300" value="300" step="1" v-model="objB.height" v-on:change="detectCollision"> {{ objB.height }}
</fieldset>


Now see, when you move the objects around, the display shows if h is true...




...or v is true...




...or both! In which case, collided is true!




I should also mention you'll want to turn the red outline off.
div { outline: 0px solid red;}


There you go.




Finally

This web tutorial wasn't pretty, and certainly has very limited mainstream use. But it can be a useful tool for testing collision.

Till our paths collide!
T___T

Saturday, 20 August 2022

Button and Input tags in HTML5

In HTML5, there are two tags that produce visually similar results. They are the button tag and the input tag with the type attribute set to a certain value - button, submit or reset.

Here are examples.

For the input tag, the type attribute is required if the tag is to be rendered as a button.
<input type="button" value="Example"/>




For the button tag, the type attribute is not required for it to render as a button. A value of submit is the default.
<button>Example</button>




Their use cases tend to overlap, but these are distinct tags and there are scenarios when one is more suitable than the other. First, let's take a look at all the possible values for the type attribute, which can apply to the button tag as well.

button - self explanatory. This will cause the input tag to appear as a button, but do nothing for the button tag.
submit - if the button or input tag is inside a form, clicking it will cause the form to submit.
reset - if the button or input tag is inside a form, clicking it will cause the form to reset.

And finally, we have the value image. This is only applicable for input tags, and the src attribute is required as well. The resultant button will have an image and act as a Submit button.

For this, we will use the image below.
1_0.jpg

<input type="image" src="http://www.teochewthunder.com/posts/2022/8/1_0.jpg"/>




For button tags, HTML is allowed between the opening and closing tags, so we could do this.
<button><img src="http://www.teochewthunder.com/posts/2022/8/1_0.jpg"></button>




Which is better?

As always, that really depends on context. In most contexts, the functionality of the input and button tags are interchangeable.

However, again, in most contexts, the button tag is semantically more obvious. And since we don't have to bother with Internet Explorer any more (the button tag had an issue there) we can just use the button tag for most cases. Also, remember that it is possible to embed HTML within the button tag. This makes it infinitely more useful from a design perspective. Sure, we could apply CSS on the input tag the same way as a button tag, but why complicate matters?

One use case for the input tag does stand out, though. Consider this code. In here, we dynamically change the type of the input tag upon clicking, which would not be possible for the button tag.
<input type="button" value="Click me for a magic trick!" onclick="this.type = (this.type == 'button' ? 'checkbox' : 'button')" />


Click on it, see what happens!


Cool parlor trick, eh? Unfortunately, that is also a very niche case... and quite frankly, plainly ridiculous.

Conclusion

The button tag is coolness exemplified, and with the advent of HTML5, on firm ground. There are still uses for the input tag, though perhaps not as a button anymore.

On to more pressing issues!
T___T

Saturday, 13 August 2022

Trail of the Catfish (Part 2/2)

It would be a full three weeks before I got back to this issue. Life had gotten very busy at the office. I was drowning in the workload. When I finally caught a break, my friend sent me a WhatsApp message to excitedly say that his girlfriend was due in Singapore in six hours. I was relieved to see that - at least there was going to be some live interaction now.

At the end of the workday, however, things had changed. He despondently told me that there had been a last-minute change in plans, and she was not coming over after all. I can't say I was too surprised at this news.

One week later...

There was more news. I learned that she had completely disappeared. According to my friend, she was no longer communicating with him.

Up in smoke.

My friend told me that the site he had been investing in, had suddenly gone down, and with it, his outlay of twenty thousand dollars. Well, I reasoned, at least he had been withdrawing his earnings regularly, right? Erm, right?!

Nope!

According to him, that would have made less sense than leaving the money there to continue rolling for him. So he'd lost everything in there, and when he tried asking for his ten thousand dollars back from his girlfriend to mitigate his losses (this really made me roll my eyes, by the way), she ghosted him.

With that in mind, my follow-up question was: if he hadn't been withdrawing the money from the site, where did he get the money to send to his girlfriend?

The answer made me facepalm really hard. He had taken the money from his own bank account. Because he had assumed that he would be able to withdraw the money from that site any time he wanted.

Wow. The sheer fucking recklessness of this made me see stars. How had that seemed like a good idea? Now he had not only lost the ten thousand he had sent, he had also lost the twenty thousand that was his initial investment. Thirty thousand in all - which, coincidentally, was about the sum I laid down as a deposit when I bought my own place back in 2014.

Evidence

Despite all that, my friend was adamant that what they had shared was real. That she had been real. And he would listen to nothing else.

That was when something clicked inside me. I took the initial image he had shown me and did a Google image search for this. What I found made my blood run cold. The image turned up several similar images of the same woman. It led me to a Weibo blog. This blog belonged to an influencer from Zhejiang in China. As a matter of fact, the very image she had sent him, was a duplicate of the one found on the blog, with one small change: the Weibo icon had been snipped off.

Before and after.

His girlfriend was a famous local celebrity in Zhejiang, who was already engaged to another man.

When I confronted my friend about this, he told me he wanted to drop the matter entirely, and asked me to stop talking about this to him. And, feeling that my point had been made, I saw no need to belabor it.

Lessons this taught me

Just because someone is older than me, does not make them smarter. Quite the contrary, they can be easier to fool precisely because they think they are immune to being taken for a ride. When considering if someone is capable of prudent decision-making, it helps to consider the context. My friend wasn't stupid normally, but in matters of romance, he has had woefully little experience. This clouded his judgment, and ultimately turned out to be his downfall.

Do I feel guilty for my lack of action? No. Undeniably, I prioritized my own shit over that of my friend's, precisely because I trusted him to be able to handle his own shit. We've all got our crosses to bear.

But I do feel ashamed. As a tech professional, doing that Google image search should have been the first thing that came to me - not almost a month after the fact.

And I feel embarrassed. Some catfisher in China probably now thinks that Singaporean men are so goddamn easy to fool - using pictures of a local celebrity, no less! All she (or maybe even he) really needed to do was sweet-talk some idiot on WeChat for a few months, with a five-digit figure payoff to show for it. Now, if only earning honest money were that easy.

(cat)fishing in troubled waters!
T___T

Thursday, 11 August 2022

Trail of the Catfish (Part 1/2)

Several dangers lurk amidst the glitzy facade of the webosphere, and one of these is catfishing. This is a scenario where one person masquerades as someone else to manipulate a user into doing something foolish - usually parting with money or information. I was unfamiliar with the term (but not the phenomenon) until a friend of mine got hit with a particularly bad case of it.

At the time, I was an agency-contracted software developer, considering further education, struggling with my new role as a husband. I was being besieged on multiple fronts - professional, academic and personal. I had my fingers in way too many pies as it was. And thus I did not deal with this as immediately and firmly as I might have. Also, strictly speaking, it wasn't my situation to deal with.

How it went down

Over dinner one evening, this friend of mine told me he was in love. He had met this woman online through WeChat, and she was now his girlfriend. When he showed me a picture, I was impressed. Cute, great figure. The only question was - why would she be interested in my friend? He wasn't ugly, but appearance-wise, he was no hunk. He was in his mid-forties, not particularly well-off, and I had never been under the impression that he was especially charming. Indeed, I had been laboring under the impression that he was the archetypical 40-year old virgin.

A pretty girl on camera.

Still, stranger things have happened. I was prepared to be happy for my friend. Why look a gift horse in the mouth, eh?

It was about to get stranger still, however. He told me he had never heard her voice "live", only through sound clips. And whenever he tried to video call her, she never picked up. But they spent several nights chatting away (via text and sound clips) into the wee hours of the morning, and he even serenaded her with his own singing several times.

So, I was supposed to believe that he hooked her with his singing voice? A lot less believable, but maybe there was something about my friend that I, as a heterosexual male, wasn't seeing.

Of more concern was the fact that he had never interacted with her live. In this day and age of deepfake technology, even interacting live isn't such a big deal for authenticity anymore. But not even having that? Fishier than the River Nile. The words of my favorite comedian Bill Burr comes to mind.

"That's not a red flag; that's the fucking Soviet Union."


The Investment

As we spoke, my friend also revealed that his girlfriend (though I was having serious doubts about the veracity of that term by that point) had introduced him an investment site where he had already put in twenty thousand dollars of his own money, and according to him, he had already earned more than ten thousand off his initial investment. Now I'm no expert in that department, but that seemed like a decent return. Actually, it was positively too good to be true.

Investment site.

He wanted to send this woman ten thousand dollars of his earnings as a gesture of appreciation. This seemed like good news - at least he could draw out his earnings, right? He had already tried to send the money, and the bank had refused to facilitate this transfer because it fit the pattern of many online scams. Thus he was wondering if he could transfer me some funds so I could affect part of the transfer on his behalf. I declined, not because I was against him sending money - that was frankly none of my business - but because, in principle, I am deeply uncomfortable with anyone messing with my account. Eventually, later on, he finally managed to send the money, in three separate installments.

I had a look at the site. And then I Googled it. What came up was, well, more red flags. Apparently this site was being flagged for suspicious activity. When I pointed it out, my friend said that he was aware. That figured; he was a grown-ass man and he could do his own damn Google search, right?

My initial reaction

If you're anything resembling a normal person, reading this, your inbuilt danger alarm must be ringing like mad by now. There were way too many things about his story that stank. In fact, the entire story stank. It reeked like an open sewer. It sounded like my friend was getting in dangerously deep and needed a reality check.

But from whom would that reality check come? Me?

Don't stick your
hand into that fire!

In all honesty, I chose to deal with my own immediate problems and largely left it to my friend's common sense to help him navigate this potential minefield. After all, it wasn't like I had any personal experience with pursuing online romances - what did I know, really?

Sure, I could have said something. Anything. I could have pointed out how ridiculous all this sounded. But would I be pointing out anything he himself didn't realize and didn't want to admit to himself? Would I be saying anything that his mother and siblings had not already been saying? Why would he listen to me, if he was already ignoring their counsel? With that in mind, would talking actually accomplish anything, or would it just be talking for the sake of talking?

I'm a software developer. What kind of software developer does something for the sake of achieving nothing? A fucking useless one, that's what.

No. If I was going to say anything, I was going to have to do better than just talk. I was going to have to present evidence of some sort. Thus, I wished him the best of luck and went on my way. I did eventually discover evidence, but it was too little, too late.

Next

The fallout!

Wednesday, 3 August 2022

The Sheetbend-Bowline Analogy

Knots are a scientific marvel, and I say that with no irony whatsoever. They are capable of accomplishing so many different things - joining lines, forming loops, stopping, and hitching, among other things. And sometimes, when you look at different knots closely, you will find that they are actually astonishingly similar. Some of them may even be identical, but serve a different function!

One of the knots that we are examining today is the Sheetbend, which is a fairly common knot used to join two lines. This is the form it commonly takes.

From Animated Knots

The other knot we are going to examine is the Bowline, which is a knot used to form a loop. This is one of the most ubiquitous sailors' knots in existence today.

From Animated Knots

Now, if you zoom in on the Bowline, like so...

This resembles a Sheetbend.


...you'll notice that the Bowline is just about identical to the Sheetbend. In fact, one could even say that the Bowline is simply a Sheetbend that has been tied back upon its rope, to form a loop!

There's an equivalent in the world of programming. Ever heard of Linked Lists? The nodes in a linked list are basically made of two parts - the data, and a pointer to the next node. If there is no next node, the pointer is null.


A Linked List consisting
of two nodes

Just like a Sheetbend, connecting two different lines!

However, there is another type of Linked List, called a Circular Linked List. This is when the last node does not point to a null, but back to the first node.

A Circular Linked List
consisting of one node.

In the example above, that is a singular node Circular Linked List! Basically, a Circular Linked List with only one node.

When you take those parallels with the Sheetbend into account, would that resemble a Bowline? You know it does!

Finally

This was totally whimsical. But the parallels are uncanny. Granted, not everyone is a knot nerd and a computer geek like myself, so I'll understand if the analogy is lost.

Keeping you in the loop,
T___T