Monday 29 April 2019

The Thief Knot Analogy

Another ropework analogy comes forth! Today, we will examine the Reef Knot and its evil twin - the Thief Knot.

The Reef Knot is a somewhat adequate knot for joining two lines of equal thickness - if the anticipated strain isn't expected to be enormous. It's handy and can be done in a pinch, though, as I mentioned earlier, no seaman worth his salt will use it for supporting very heavy loads.

A Reef Knot

However, sometimes people make the mistake of tying it this way. In this form, it's called a Thief Knot.

A Thief Knot

See the difference? The ends are on opposite sides of the knot. Which in turn means that the strain is coming from diagonally opposite positions. In the event of strain upon the knot, it would very quickly collapse.

The above happens when there is a lack of understanding as to how the knot is constructed and the focus is on the form rather than the function. Thus when someone looks at the Thief Knot without looking at the big picture, it would appear identical to the Reef Knot. But when the knot is put under pressure, that's when the mistake becomes apparent.

The Programming Parallel

Similarly, when writing code, sometimes what appears correct visually turns out to be logically incorrect when other things are taken into account. Let's use scope as an example. This is in JavaScript, but may hold true in other programming languages.

This code takes the variable, i, and every second, it increments i and displays the output in the console. You would actually substitute the code in the callback for something less trivial, but this has been deliberately kept simple for clarity.
function inc()
{
    var i = 0;

    console.log(i, " is the value of i");

    setInterval
    (
        function()
        {
            i++;
            console.log(i);
        },
        1000
    );
}

inc();

Pretty straightforward.

Now, let's see what happens if all that code is part of an object.
var obj =
{
    i: 0,
    inc: function() {
        console.log(this.i, " is the value of i");

        setInterval
        (
            function()
            {
                this.i++;
                console.log(this.i);
            },
            1000
        );
    }
}

obj.inc();


Aha! The first console statement runs just fine. The value of this.i is 0, and that's correct. But why does it fail in the setInterval() function?



Because while the code looks analogous to the first non-objectified example, there's a new wrench thrown in the works. Namely, this. In the main body of the inc() method, this.i would refer to the i property of the parent object, obj. So console.log(this.i) works just fine.

But once you place this.i in a callback, this no longer returns to obj. It still refers to its parent object, but now its parent object has changed. Its parent function is now the callback! Needless to say, this new piece of code wouldn't hold up at all.

The Knotty Conclusion

Scope is merely one example of how it can all go sideways if you take the same piece of code and expect it to work in some other context. The same way it will all go to shit if you blindly copy the form of the Reef Knot without understanding its function. It looks similar, but it performs drastically differently.

this has been a pleasure. Au revoir!
T___T

Friday 26 April 2019

FEAR: Forget Everything And Run

Good evening. Today, I want to talk about fear.

I know it's not a very technical topic, but recently a reader had gone through my piece about the #LearnToCode hashtag, and commented to me that she could see I was really afraid of being laid off, due to my comments of sympathy for those who had lost their jobs. That couldn't be further from the truth (I'll explain why in a bit) and I suspect it was more a case of her projecting her own fears at work onto me.

Still, it got me thinking, which is always a good thing. And I consider it a topic worth exploring, especially in the context of a tech career.

Some backstory

Back in 1999, when I was twenty, I served on board two warships - RSS Brave in 1999 and RSS Fearless in 2000. This were the anti-submarine Fearless Class vessels, some of which are now defunct as of July last year, and comprised of twelve vessels. The first six ships in that class were RSS Fearless, RSS Brave, RSS Courageous, RSS Gallant, RSS Daring and RSS Dauntless. All these names were synonyms for bravery, which is what they aspire for soldiers, I guess. That, and the ability to follow orders. But pardon me, I digress...

Brave and Fearless

Even at that age, having served on the first two warships in the entire series, I understood the difference between these two words. They sound like they mean the same thing, but that is most decidedly not the case. Fearlessness is literally the absence of fear. Bravery is not the absence of fear, but rather the management of fear. Thus if one is literally fearless, bravery becomes irrelevant because there is no fear to manage.

And this brings me to...

The Management of Fear

What does fear stand for? We like to joke that it means Fuck Forget Everything And Run. But that's not management of fear. Running, or being paralyzed, are both natural instincts of fear. Managing fear is about overriding those instincts and channeling the energy generated from that fear, into productive action.

Let's face it - everyone fears something. Anyone who claims to be not afraid of anything is either a braggart or a child. But while it is natural - and sensible, I should add - to be afraid, some fears are more worth your time than others. Don't try not to be afraid. But try to reserve your fear quota for the right things. Fear needs to be useful. Being afraid of the inevitable (i.e, stuff you can't control), is silly. If our fear is in things that we can control, we can actually do something about it and, as mentioned earlier, channel that energy into productive action. Because fear, as it stands, is an excellent motivator.

The trick here is to closely examine what we think we're afraid of, and identify what we're actually afraid of.

Examples!

Let's examine a few common fears, and deconstruct them.

Interviewing. Some people I know express a certain nervousness before an interview. They're afraid of screwing up, or making an unfavorable impression. To that, I say - stop seeing it as an obstacle. Use The Look-ahead Strategy and take it as training. I've bungled my fair share of interviews (see my ill-fated interview with Mozat here). That's no excuse to stop trying. Besides, the interviewee has much to gain and absolutely nothing to lose. The interviewee doesn't have a job at the company. And if everything goes south, nothing changes. He or she still doesn't have a job at the company. But if things go right, it could result in an employment offer.

Even after having explained that, they aren't convinced. There's still a nagging fear somewhere even though they know logically, that fear is irrational. That fear isn't of interviews specifically - it's of rejection. Of being found to be not good enough. That fear is also irrational. When an interviewer rejects your application, it's rarely because you're not good enough, period. Rather, it's usually because you're not a good fit for whatever reason. You may be applying for the wrong job, sending off the wrong vibes or presenting yourself incorrectly. It's not the end of the world; in fact, it's a remarkable learning opportunity. See why I advocate practicing your interviewing skills using real interviews?

Also, if you really are not good enough, it's better that you find out during a low stakes interview rather than during a time when it could do a lot more damage.

I spent years in a desktop support job I hated partially because I was afraid of testing myself. I was afraid I wouldn't make it outside of my cage, which ironically had become my comfort zone. And the longer I put off moving on, the more my skillset stagnated. Now what I fear is getting stuck simply because I've grown too comfortable in my misery. I will never again allow that to happen.

Living in a cage.

Remember when I said "work is part of life"? You know what else is part of life? Failure. Rejection. The only time you stop failing is after you die. So unless you're planning to die in the near future, get on with the business of living. Fear of rejection is arguably more harmful than rejection itself. Get over it. You should aim to not fail, of course... but in the event that you do fail, learn from it.

Many years ago, when I asked my then-girlfriend out on that first date, I wasn't even considering the possibility of failure - in fact, I was convinced that rejection wasn't even a possibility, but an outright eventuality. I said "fuck it", and asked anyway, and she's now the wife. Maybe people should learn to say "fuck it", more often? Just sayin'.

Losing your job. That's one fear I've learned to lay to rest long ago. I promised in the first paragraph of this blogpost that I'd explain why. So here goes...

As a professional, some things are out of your control - market forces, economy, company funding and the like. It's not a question of whether not you're good enough to hang on to your job, but whether or not the company can afford to keep paying you. You could keep yourself as skilled and relevant as much as you want - that is still no guarantee against losing your job. But hey, guess what? Losing one's job is part and parcel of being a professional, the same way that failure is part of life. It's not an indictment of your capability, or lack thereof. Anyone who tells you that they've never been laid off, assuming they're telling you the truth, is probably really lucky, not that experienced, or simply has never taken any significant risks in their career choices.


If you're going to box, you can't be
afraid of getting punched in the face.

Professionals being afraid of losing their jobs is kind of like boxers being afraid to get punched in the face. Of course a boxer wants to avoid getting hit in the face because if that happens too often, he will lose the bout. But that doesn't mean he is afraid of it, otherwise he should not even be stepping into the ring in the first place. Likewise, as a professional, you should aim to hold on to your job... but don't be so afraid of losing your job that you forget to actually do your job. I've seen people react to the fear of losing their jobs, by playing petty office politics and constantly looking over their shoulders for metaphorical knives.

So yes, fear of losing your job is another irrelevant fear. Besides, nobody actually fears losing their job. In fact, I suspect many people would be quite happy to be jobless, if they had enough money to live comfortably on. What they really fear is having no income. I've mitigated that fear by living simply and maintaining a sum of money (twenty months of monthly expenditure), which I like to call my Fuck You Fund.

What I really fear is not losing my job, because I'm reasonably certain I could land another one fairly quickly, but the state of joblessness itself. I've seen people "take a break" which was supposed to be for a month or two, only to wind up jobless for six months or more. And that prospect terrifies me. For a long time, I've been a web developer. It's an integral part of my identity. What's a web developer without something to develop? And that is why I keep myself really busy when I'm between jobs - to ensure that I don't get too comfortable not having a job. The result is an awful lot of code in my GitHub account and my website.

Aging. As the years approach, there's a certain fear of growing old and dying. And the things you used to be able to handily do - physically exert yourself, eat copious amounts at buffets, party like there's no tomorrow - all take a massive hit. People fear losing what they once had. But this is inevitable. Aging is a process, and death comes to everyone. Joints start to creak. Fatigue comes more easily. Appetites wane. Wrinkles start to form, hair grows grey (and in some cases, falls off entirely) and waistlines thicken. It's all par for the course, and to be expected. Sometimes I look at photographs of myself ten years ago and compare them to how I look now, and marvel at how much I now resemble my father.


Fuck, that's old.

But that's just physical aging. You know what's way scarier? Mental aging.

When you say "mental aging", some people think of Parkinson's or Alzheimer's. That's pretty scary too, but not really in the scope of what I'm covering today. No, what I'm thinking of is more in the realm of attitude.

You ever encountered some older folks who just can't be taught anything? They hold certain antiquated, outdated ideas about the world which may have been relevant and even accurate decades ago. But now they're so divorced from the realities of today's world, utterly convinced that they have got it all figured out and obstinately refuse to even entertain the idea that younger people may know better than they do. They spend their time criticizing the younger generation and feeling superior simply for being born in the sixties or before.

As a software developer who's had to affix his entire career on the premise that change is the only constant, I am absolutely appalled by the idea that one day, my mind is going to grow like that - fixed and unmoving, stuck in the past. I'm afraid that the world will keep changing but my mind will refuse to accept it. Forget old folks - some of my generation are already starting to act like that. I used to find it irritating and pathetic... now I'm filled with anxiety about eventually becoming like that. It's the kind of thing that will creep up on you when you're feeling smug and complacent about being all progressive and shit, and next thing you know, you've become one of those annoying old farts who never shut up about how things were in their day.

How do I counter this? By learning. Learning about whatever I can get my grubby little hands on. It doesn't matter if it helps my career or enables me to make better arguments. The future belongs to people who can learn, unlearn and relearn. The point is to keep my head in constant learning mode. I'm getting on in years, and forgetting stuff is going to be a big part of it. That's fine. I can forget... but I cannot not learn.

That's all for now, I'm afraid...

See what I did there? Heh heh.

I guess most of my fears (getting too comfortable, having nothing to do, growing old and stubborn) mostly boil down to one thing - fear of complacency. The moment I allow myself to forget how little I really know about software development despite having done it for over a decade, the closer I get to repeating the mistakes of my misspent youth. And that I simply cannot have. It is an outcome too awful to contemplate.

But that fear is good. It keeps me honest and on track, and that's valuable.

Frightfully yours,
T___T

Monday 22 April 2019

On the new online laws in Singapore...

The proposal of new laws on the Internet stratosphere in sunny (lately, very sunny) Singapore, has been making the rounds. There are people talking about it - lawyers, journalists and activists mostly - and as a web professional I think I should attempt to take an interest in them, i.e, weigh in with my two cents. Though, as it turns out, I can muster only a modicum of interest, and hopefully by the end of this blogpost you'll see why.

Doxxing

The first law concerns doxxing. In case this is new to you, doxxing is the practice of publishing private information about an individual on the Internet without his or her express permission, with the intention to encourage violence or harassment towards this individual. The usual perpetrators being online vigilantes towards perceived deserving targets.

Soon, doxxing will be punishable via fines or jail time. And to that, I have only three words.

About damn time.

Online vigilantism has been a thorn in the side of civilized society in recent years, with aggressors such as SMRT Feedback and their delusions of heroism outing the likes of Jover Chew. While people like Chew most assuredly do not elicit any sympathy from me whatsoever, giving carte blanche to civilians to doxx people is a dangerous practice and should not be encouraged. People and their families have received death threats and worse, from anonymous sources after being doxxed. Worse, some of these are actually cases of mistaken identity!

No civilian should be given the right - legal, ethical or moral - to inflict this treatment on anyone.

Online lynching.

So yes - this proposed amendment to the Protection from Harassment Act gets my unequivocal support. The Internet's a troublesome enough place without lynch mobs and the rabble-rousers that stir them.

In fact, while we're at it, we should also do something about the self-righteous wankers who take pictures of people who offend them in any manner and post them on Social Media and instigate others to shame or pile on those people. While that's not technically doxxing, that's certainly facilitating it.

Fake News

This other one's a little dicey. It concerns the Government's ability to take down fake news.  In this proposed new Protection from Online Falsehoods and Manipulation Bill, the Government gets the authority to issue takedown orders of any post or article that contain what the Government considers false or misleading, to Internet service providers and social media platforms. Facebook and the like will not be able to hide behind their autonomy because they do have to abide by the laws of any nation they do business in.

See a problem with that? The Government decides what warrants a takedown order. In effect, if you put a toe out of line and publish something the Government considers objectionable, there's the possibility that the Government can pretty much fix you, just like that. That seems like an overreach. This has sparked an outcry among activists, and several members of the Government have since stepped up to explain that they're not clamping down on Freedom of Speech, and that criticism, opinion, satire and the like will not be touched by this law, and that they don't intend to abuse this law for their benefit. The thing is, assuming that I believe this current Government, there's no guarantee that future Governments will not abuse this. And sometimes, abuse does not even have to be intentional. All that's needed is for one party to believe that they are using the law as intended, and it's for the greater good, and the slippery slope beckons.

It's no skin off my back, personally. This blog doesn't deal in politics unless politics somehow crosses paths with Internet tech as is its occasional wont. And my readership isn't large enough to scare the incumbent into action. This is pretty much a solid a guarantee as any that I will remain unscathed by this new Bill; because publishing online falsehoods isn't really my style (or intent), and because my words simply don't carry that far. Succinctly put, I'm just not that important, or crazy.

Wish I cared... but I really don't.


But that's not why I find myself markedly apathetic towards this new piece of legislation, even though logically, just as a citizen, I should be concerned. It's more because I've seen what Freedom of Speech does for countries like the good ol' US of A. Batshit crazy Social Justice Warriors abound on Twitter and Facebook. My WhatsApp groups are filled with shared links to outrageously insane rhetoric treated like religious truth. Freedom of Speech is a nice concept and I truly wish people could handle it better. Unfortunately, the likes of The Real Singapore have, in recent times, ably demonstrated that Singaporeans aren't responsible enough to handle that kind of freedom, or smart enough not to be taken in by provocateurs.

What would I prefer - the kind of behavior that's becoming all too commonplace in USA, or a Government-controlled Internet space? Neither outcome is particularly appealing. Whether or not this Bill goes through, there's no result I'll be happy with. As such, I'm having trouble finding enough fucks to give.

In conclusion...

These proposed changes to the law are going to take place, no matter who screams and cries, or how loudly. Considering that other countries already have their own laws that lead to Internet censorship, it's really rather surprising that a country as supposedly draconian as Singapore has taken this long to join the crowd.

Sure, protest. Let it out. And if you really gotta do it online, do it now, while you can. Go sign those Internet petitions, make a bombastic Facebook post or something. Express your dismay and displeasure. Very soon, you may not be able to - legally, at least.

This is one God-(l)awful development,
T___T

Thursday 18 April 2019

Web Tutorial: Easter Bunny River Crossing Game (Part 4/4)

OK, guys! Welcome back for the final installment.

We're going to start off with the raft object now. When you click the boatman, the raft will move. So do this.
                    <div class="path">
                        <div id="raft">
                            <div class="placeholder" id="raftPassenger">

                            </div>
                            <div class="boatman" onclick="raft.move();"></div>
                        </div>
                    </div>


Next, modify the move() method of the raft object. It will work only if the game is started and not paused. So add the conditions in an If block.
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                       
                    }
                }
            };


Next, declare a variable, destination. The destination can only be "leftBank" or "rightBank". If the raft is currently at the left bank, then its destination must be the right bank. The reverse is also true.
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = (this.position == "leftBank" ? "rightBank" : "leftBank");                   
                    }
                }
            };


Next, get the raft and set it to a variable, objRaft. if the destination is "leftBank", then the marginLeft property should be 0%. If not, it should be 78%. You'll see why soon.
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = (this.position == "leftBank" ? "rightBank" : "leftBank");
                        var objRaft = document.getElementById("raft");

                        if (destination == "leftBank")
                        {
                            objRaft.style.marginLeft = "0%";
                        }
                        else
                        {
                            objRaft.style.marginLeft = "78%";
                        }                       
                    }
                }
            };


Then we pause the game.
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = (this.position == "leftBank" ? "rightBank" : "leftBank");
                        var objRaft = document.getElementById("raft");

                        if (destination == "leftBank")
                        {
                            objRaft.style.marginLeft = "0%";
                        }
                        else
                        {
                            objRaft.style.marginLeft = "78%";
                        }

                        game.paused = true;                       
                    }
                }
            };


And here, we use the setTimeout() function, with an interval of, say, one second. Set raft to the current object...
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = (this.position == "leftBank" ? "rightBank" : "leftBank");
                        var objRaft = document.getElementById("raft");

                        if (destination == "leftBank")
                        {
                            objRaft.style.marginLeft = "0%";
                        }
                        else
                        {
                            objRaft.style.marginLeft = "78%";
                        }

                        game.paused = true;

                        var raft = this;

                        setTimeout
                        (
                            function()
                            {

                            },
                            1000
                        );                       
                    }
                }
            };


And once the interval of one second is reached, set the raft position, unpause the game, increment the moves property, and run the check() method! We'll be working on the check() method soon.

What this does is, every time the raft moves, it's counted as one move. We pause the game while the raft is moving so that clicks on the passengers and the raft won't affect anything. Of course, we'll update the raft position, and then the check() method ensures that if the fox is left alone with the EasterBunny or the Easter Bunny is left alone with the Easter egg, shit happens.
            var raft =
            {
                position: "leftBank",
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = (this.position == "leftBank" ? "rightBank" : "leftBank");
                        var objRaft = document.getElementById("raft");

                        if (destination == "leftBank")
                        {
                            objRaft.style.marginLeft = "0%";
                        }
                        else
                        {
                            objRaft.style.marginLeft = "78%";
                        }

                        game.paused = true;

                        var raft = this;

                        setTimeout
                        (
                            function()
                            {
                                raft.position = destination;
                                game.paused = false;
                                game.moves ++;
                                game.check();
                            },
                            1000
                        );                       
                    }
                }
            };


For the timeout to make sense, we add this to the raft styling.
            #raft
            {
                width: 80px;
                height: 5px;
                background-color: #440000;
                margin-top: 73%;
                margin-left: 0%;
                transition: all 1s;
            }


Reload, click the orange button, then click on the boatman. Does he move? Click again. Does he move back?


Now, as promised, let's work on the check() method of the game object. It's basically a series of If statements.

The first conditions to check - ensure that the fox isn't left alone with the Easter Bunny. So if fox's position property is the same as bunny's position property and the raft and egg's position properties aren't...
                check: function()
                {
                    if (fox.position == bunny.position && raft.position != fox.position && egg.position != fox.position)
                    {

                    }
                },


...run the showMessage() method of the game object, with the argument "fox". Then set started to false and paused to true. Which effectively means GAME OVER.
                check: function()
                {
                    if (fox.position == bunny.position && raft.position != fox.position && egg.position != fox.position)
                    {
                        this.showMessage("fox");
                        game.started = false;
                        game.paused = true;
                    }
                },


Now check if the Easter Bunny and the Easter egg are left alone, and do something similar.
                check: function()
                {
                    if (fox.position == bunny.position && raft.position != fox.position && egg.position != fox.position)
                    {
                        this.showMessage("fox");
                        game.started = false;
                        game.paused = true;
                    }

                    if (bunny.position == egg.position && raft.position != bunny.position && fox.position != bunny.position)
                    {
                        this.showMessage("bunny");
                        game.started = false;
                        game.paused = true;
                    }
                },


Next, check if the fox, bunny and egg all have their positions as "rightBank". If so, the game is won and we need to run the showMessage() method with the argument "win". It's still GAME OVER, so set the flags accordingly.
                check: function()
                {
                    if (fox.position == bunny.position && raft.position != fox.position && egg.position != fox.position)
                    {
                        this.showMessage("fox");
                        game.started = false;
                        game.paused = true;
                    }

                    if (bunny.position == egg.position && raft.position != bunny.position && fox.position != bunny.position)
                    {
                        this.showMessage("bunny");
                        game.started = false;
                        game.paused = true;
                    }

                    if (bunny.position == "rightBank" && egg.position == "rightBank" && fox.position == "rightBank")
                    {
                        this.showMessage("win");
                        game.started = false;
                        game.paused = true;
                    }
                },


Now add a couple more conditions to the showMessage() method. Show different messages depending on whether messageType is "fox", "bunny" or "win". In the "win" scenario, we'll even display the number of moves made. How cool is that?
                check: function()
                {
                    if (fox.position == bunny.position && raft.position != fox.position && egg.position != fox.position)
                    {
                        this.showMessage("fox");
                        game.started = false;
                        game.paused = true;
                    }

                    if (bunny.position == egg.position && raft.position != bunny.position && fox.position != bunny.position)
                    {
                        this.showMessage("bunny");
                        game.started = false;
                        game.paused = true;
                    }

                    if (bunny.position == "rightBank" && egg.position == "rightBank" && fox.position == "rightBank")
                    {
                        this.showMessage("win");
                        game.started = false;
                        game.paused = true;
                    }
                },
                showMessage: function(messageType)
                {
                    var messageBox = document.getElementById("messageBox");
                    var button = document.getElementById("btnStart");

                    if (messageType == "title")
                    {
                        messageBox.innerHTML = "<h3>Easter Bunny River Crossing Game</h3>";
                        button.innerHTML = "Start";
                    }

                    if (messageType == "started")
                    {
                        messageBox.innerHTML = "<ol><li>The objective of this game is to get all three passengers across to the other bank.</li><li>The raft can hold only one passenger at a time.</li><li>The fox cannot be left alone with the Easter Bunny.</li><li>The Easter Bunny cannot be left alone with the egg.</li></ol>";
                        button.innerHTML = "Restart";
                    }

                    if (messageType == "fox")
                    {
                        messageBox.innerHTML = "The fox has eaten the Easter Bunny!";
                        button.innerHTML = "Restart";
                    }

                    if (messageType == "bunny")
                    {
                        messageBox.innerHTML = "The Easter Bunny has escaped with the egg!";
                        button.innerHTML = "Restart";
                    }

                    if (messageType == "win")
                    {
                        messageBox.innerHTML = "All three have crossed! You have completed this game in " + game.moves + " moves.";
                        button.innerHTML = "Restart";
                    }
                }


One final method!

Yep, that's the move() method of the passenger object. Without it, it's impossible to play. Again, stuff only happens if the game is started and not paused.
                move: function()
                {
                    if (game.started && !game.paused)
                    {

                    }
                }   


Declare a variable, destination, and make it undefined. Now, if the passenger's position is either on the left bank or right bank, then its destination can only be "raft".
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {

                        }
                    }
                }   


But only if the raft is at the same position! For example, if the fox is on the right bank and the raft is at the left bank, then the fox cannot move on the raft.
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }
                    }
                }   


If the passenger is currently on the raft, then its destination is, naturally, the raft's position. For example, if the fox is on the raft and the raft is at the left bank, then when the fox moves, its destination is the left bank.
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }
                    }
                }   


After all that, destination should be set. This If block is just to compensate for the off chance that it's still undefined, but it really shouldn't be. Anyway, within this If block, create an If-else block to check if the destination is "raft". If some other passenger is already on the raft...
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }

                        if (destination != undefined)
                        {
                            if (destination == "raft" && (fox.position == "raft" || bunny.position == "raft" || egg.position == "raft"))
                            {

                            }
                            else
                            {
                           
                            }                           
                        }
                    }
                }   


... warn using an alert() function.
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }

                        if (destination != undefined)
                        {
                            if (destination == "raft" && (fox.position == "raft" || bunny.position == "raft" || egg.position == "raft"))
                            {
                                alert("Only one passenger is allowed!");
                            }
                            else
                            {
                               
                            }                       
                        }
                    }
                }


If not, begin by clearing the passenger from all other placeholders it might be in. If its current positon is "raft", then clear the raftPassenger div. If it isn't "raft", then it's either "leftBank" or "rightBank", and those placeholders should be cleared..
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }

                        if (destination != undefined)
                        {
                            if (destination == "raft" && (fox.position == "raft" || bunny.position == "raft" || egg.position == "raft"))
                            {
                                alert("Only one passenger is allowed!");
                            }
                            else
                            {
                                if (this.position == "raft")
                                {
                                    document.getElementById("raftPassenger").innerHTML = "";
                                }
                                else
                                {
                                    document.getElementById(this.position + "_" + this.id).innerHTML = "";
                                }                               
                            }                           
                        }
                    }
                }


Then run the render() method of the current object, putting in destination as an argument. Also, set the position property to destination.
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }

                        if (destination != undefined)
                        {
                            if (destination == "raft" && (fox.position == "raft" || bunny.position == "raft" || egg.position == "raft"))
                            {
                                alert("Only one passenger is allowed!");
                            }
                            else
                            {
                                if (this.position == "raft")
                                {
                                    document.getElementById("raftPassenger").innerHTML = "";
                                }
                                else
                                {
                                    document.getElementById(this.position + "_" + this.id).innerHTML = "";
                                }

                                this.render(destination);
                                this.position = destination;                               
                            }                           
                        }
                    }
                }


Finally, run the check() method of the game object. This will check for a victory condition, meaning, all three passengers on the right bank.
                move: function()
                {
                    if (game.started && !game.paused)
                    {
                        var destination = undefined;

                        if (this.position == "leftBank" || this.position == "rightBank")
                        {
                            if (this.position == raft.position)
                            {
                                destination = "raft";
                            }
                        }

                        if (this.position == "raft")
                        {
                            destination = raft.position;
                        }

                        if (destination != undefined)
                        {
                            if (destination == "raft" && (fox.position == "raft" || bunny.position == "raft" || egg.position == "raft"))
                            {
                                alert("Only one passenger is allowed!");
                            }
                            else
                            {
                                if (this.position == "raft")
                                {
                                    document.getElementById("raftPassenger").innerHTML = "";
                                }
                                else
                                {
                                    document.getElementById(this.position + "_" + this.id).innerHTML = "";
                                }

                                this.render(destination);
                                this.position = destination;                               
                            }

                            game.check();                           
                        }
                    }
                }


But the move() method will never fire off unless we do this...
        <div id="template_bunny" class="placeholder">
            <div class="bunny" onclick="bunny.move()">
                <div class="bunny_ears"></div>
                <div class="bunny_head"></div>
                <div class="bunny_body"></div>
            </div>
        </div>

        <br />

        <div id="template_fox" class="placeholder">
            <div class="fox" onclick="fox.move()">
                <div class="fox_ears"></div>
                <div class="fox_body"></div>
                <div class="fox_head"></div>
            </div>
        </div>

        <br />

        <div id="template_egg" class="placeholder">
            <div class="egg" onclick="egg.move()">
                <div class="egg_body"></div>
            </div>
        </div>


Enough yakking! Time to test! Start the game and click on the bunny. Does it move on the raft?


Now click on the fox. Does the warning message come up?


Click on the boatman. The bunny should be across the river now.


Click on the bunny again. Now it's on the right bank!


You'll need to test all the cases.




Of course, we still need to get rid of the ugly black lines.
            .placeholder
            {
                width: 40px;
                height: 50px;
                outline: 0px solid #000000;
            }


And make the templates invisible.
            #template_bunny, #template_egg, #template_fox
            {
                display: none;
            }


Final product!


Note

All this vanilla JavaScript isn't going to work on Internet Explorer and Safari, and right now I can't be arsed to jump through those hoops. If you really must get this to work on those browsers, my advice is - use jQuery. All the working has been laid out for you in vanilla JavaScript, so if you understood whatever was going on, it ought to be a piece of cake.


Do enjoy your Easter. game.check() back here again next week!
T___T