Thursday 22 August 2019

Confidence is overrated, and here's why

Professionally, there are some stock phrases that, when uttered, give me pause. Be confident. It's all about confidence. It's how you carry yourself. How often have I heard all this? I submit that the people saying this, don't truly understand what confidence is. I say this not out of derision, but due to some things I've observed over the past decade.

The last person to say this to me was an ex-colleague. He was looking for a new job because his contract was about to expire, and shared his resume for my perusal. In it, he asked for a whopping five-figure salary and claimed to be experienced in microservices, APIs, DevOps and several technologies that I know for a fact we didn't use in the workplace. Of course, he could have learned all this on his own time. But implying professional experience in technologies one has only experimented with in a personal capacity, is fundamentally dishonest. You know what he told me while discussing his resume? "You need to be confident. Ask for what you deserve."

You see, there is a huge problem with that statement, in this particular context. Yes, having the audacity to tell such big whopping lies on your resume could be construed as confidence. But from where I sit, it reeks of desperation. This guy had spent the last seven years at his desk doing very little. And when the time came for him to leave the company, he found himself alarmingly out of touch with the needs of our industry. And lacking any other viable alternatives, he opted to lie on his resume. Do confident people need to lie? Do people who are secure in their abilities, need to paint this huge glorious picture of themselves that don't match the genuine article?

Building up the image.

And the sad part is, I've felt actual confidence... and this ain't it. My ex-colleague, if he gets hired at that salary, is going to spend his days looking over his shoulder. Brazening out a lie is not confidence - it's bravado, at best. And it certainly isn't clever.

I know because I've been in that position before. I spent six years in a desktop support job doing very little in the way of useful work, and I did not dare leave the company for fear of my inadequacy being exposed. But I didn't lie. I enrolled in a course and spent a year obtaining a Diploma. When I left the company, there were genuine credentials backing up my resume. Sure, they weren't grand, but they were authentic. I was an inexperienced developer with qualifications, selling myself as... an inexperienced developer with qualifications. I didn't have to be afraid of being found out. There was no falsehood to catch up to me.

Confidence is not about talking big...

...sometimes it's about talking small. And it's even less about showing others how awesome you think you are. When you don't have to constantly put up a front, things get easier. People don't have big expectations of you, and you don't feel any pressure to maintain that facade.

At work, I defer to people all the time, because even though they're younger, they're more qualified and I'm not shy about admitting it. Hell, I would admit it even if it wasn't true. They actually have a term for this: Tai-chi.

Redirecting the flow of attention.

One thing about deferring to others is, it takes the heat off you. Keeps you under the radar. There's no need to appear to be the smartest person in the room; it's not a goddamn competition.

"They can't stop you, if they don't see you coming." -  Izey Victoria Odiase 

Sometimes confidence includes being willing to let others think you're not confident. The most dangerous people are the kind who are willing to be underestimated. At some point, you're gonna have to decide - are you a silent threat, or a harmless balloon filled with hot air? I know what I'd rather be.

Not needing to prove shit

The need to prove yourself is damaging to the psyche in the long run, and sure as hell does nothing for actual confidence.

There's a meme going around the Internet. The picture below is just one of its many incarnations.



When someone says you can't do it, do it twice and take pictures!

Not gonna lie - ten years ago, that was me. I was young and eager to show that I could conquer anything that was thrown at me. That made me easy to manipulate... because I was hungry. I was eager to prove, to myself and others, that I could make it as a tech in this industry.

A decade later, it all seems so juvenile. Sure, be good enough to do it. Be good enough to do it twice, even. But why the need to "take pictures"? So you can rub it in the faces of those who can't do it? So you can prove you're better? That's not confidence. That's adolescent-level bullshit. If you really are as good as you say you are, there is no need for validation. Especially not of that sort.

In fact, I've come to realize that the people who repeatedly try to show me that they're confident, are almost certainly the least.

Elevating others

You've heard of the people who constantly put others down in order to look good at their expense, right? Same goes for those who make a big production of pointing out someone else's mistakes just so they can look good in comparison. Well, here's some news for you - it doesn't work. In fact, it stinks of insecurity.

If you want to appear confident, do the exact opposite. Praise people. Highlight their good points.

That's the "what". Now, for the "who".

Who you praise is just as important, if not more so. Don't praise people who are obviously in a position to do you favors - like a superior or a Director. That's merely bootlicking. Praise people who are at your level, or better still, lower. That projects confidence. It shows that you're secure enough in your place that you're not afraid to give others the credit.

Bullying others is not confidence.

Conversely, if you try to one-up someone obviously not above you, you're just a loser who needs to punch down to feel like a big man. That never looks good. People who need to win just for the sake of winning, are practically the dictionary definition of the word "pathetic".

Don't be that guy.

In conclusion

Understand this: most people's facades of ironclad confidence are pretty much bullshit anyway. Once you get past their fronting, you'll recognize their insecurities for what they are, and learn to deal with your own. Because you'll know that you're not alone in feeling like a drop of piss in an ocean.

Nobody's a hundred percent sure of themselves all the time, and that's perfectly OK. It's not a cut-and-dry, binary one-or-zero equation. No program starts out being completely functional, and no software developer is the finished article. Confidence and personal growth, much like debugging, is an iterative thing. It has to be earned. There is no instant formula.

With utmost confidence,
T___T

Sunday 18 August 2019

App Review: Sara Is Missing

Some apps are straightforward - start it up, get your stuff done, play a game maybe, and turn it off. Sara Is Missing breaks the mold with a twist - start up the app and it instantly transforms your phone into someone else's phone. From there, gameplay starts right away and you're tossed into a whirlwind of intrigue.



Sara Is Missing is a game by Kaigan Games that came out a couple years ago... and what a game it is. It's won international awards for sheer creativity. From the get-go, you're immersed in a mystery that progressively gets more sinister as the player gets deeper into the storyline. 

The Premise

You, the player, have picked up a damaged mobile phone and need to figure out who the owner is. A SIRI-like disembodied voice (named IRIS, heh heh) appears to help you figure this out as you trawl through the contents of the phone.



It soon becomes apparent that the owner of the phone (the titular Sara) is in mortal danger and only you can help her.

The Aesthetics

Not a big fan, to be honest. But the interface choices (colors, backgrounds) were apt considering the phone is supposed to belong to a certain young lady named Sara Young.


I mean, I wouldn't have chosen those colors for my own phone, and perhaps that's the point.

The Experience

If the makers of this app wanted the experience to be immersive, well, they definitely succeeded. Everything in this app pretty much accurately depicts the user interface of an actual phone. It's like you're holding the actual damaged phone in your hand as you navigate its contents. In fact, sometimes it's hard to figure out where the game ends and your mobile phone begins.




Also, this game tries hard to scare you by suddenly playing video clips and random phone events... and sometimes it works. If you're jumpy, play it when you're sitting down.

The Interface

This is pretty easy to figure out because the interface of the game is exactly like the contents of an actual mobile phone. You tap, drag and slide your way through an interface that poses no problems at all.




What I liked

Immersion. Once you get into it, it's easy to forget that the mobile phone in your hand is actually your own. It really feels like you're part of the game's universe. Achieving that level of immersion is a trick that doesn't always get pulled off successfully with most games.

Speaking of immersion, at the end of the game, there's a set of co-ordinates that will lead you to Janda Baik in Malaysia. Now that's a nice potential hook for a sequel!

Content. The video clips are kept short and the images are kept small. This means that the file size of the app is a lot smaller than an actual phone would take up. This is cleverly explained in-game as the contents of the phone being damaged and the files inaccessible.



Some of the puzzles are nice. There's a segment where you have to figure out Sara's password. Not too difficult, but still well done.



Sara Is Missing... S.I.M. That's pretty clever!


What I didn't

The story was very short. Most people will be able to complete this within an hour. The choices were sometimes not very interesting either. Story branching could use a little work here. Where this is concerned, the effort feels rather casual.

IRIS, the voice that helps you, is creepy even when it's trying to be helpful. Perhaps that's by design.



Sometimes it's not very obvious how to get out of the app and back into the real world. That's one of the instances where immersion is taken just a teeny bit too far.

Conclusion

As apps go, Sara Is Missing isn't bad. It's a great idea with a decent amount of quality in the execution. Sure, it could have been done a lot better, but all things considered, I think it's worth a download. There's not much in the replayability stakes, but that's the way these story-based things are.

Kaigan Games has released a well-received sequel to this app, named Simulacra. I intend to check that out soon-ish.

My Rating

7 / 10

App-ceptional!
T___T

Monday 12 August 2019

Web Tutorial: Tic-tac-toe (Part 2/2)

Now, we're going to handle placing "x" or "o" on the board. Modify the HTML. Each square should have the takeTurn() method set to run upon being clicked, with the number of the square and "o" passed in as arguments.
            <div id="board_container">
                <div id="square0" class="square" onclick="user.takeTurn(0, 'o');"></div>
                <div id="square1" class="square" onclick="user.takeTurn(1, 'o');"></div>
                <div id="square2" class="square" onclick="user.takeTurn(2, 'o');"></div>
                <div id="square3" class="square" onclick="user.takeTurn(3, 'o');"></div>
                <div id="square4" class="square" onclick="user.takeTurn(4, 'o');"></div>
                <div id="square5" class="square" onclick="user.takeTurn(5, 'o');"></div>
                <div id="square6" class="square" onclick="user.takeTurn(6, 'o');"></div>
                <div id="square7" class="square" onclick="user.takeTurn(7, 'o');"></div>
                <div id="square8" class="square" onclick="user.takeTurn(8, 'o');"></div>
            </div>


The method itself, of course, will cater to "x" as well. These If blocks are to ensure that it is the appropriate turn and that the game is started. We can't have "x" taking a turn when it's "o"'s turn, for instance. Also, that particular square on the board array must not be occupied, i.e, the value property has to be an empty string.
                takeTurn: function(square, mark)
                {
                    if (mark == game.turn && game.started)
                    {
                        if (game.board[square].value == "")
                        {

                        }
                    }
                },


First, set the value to whatever is appropriate ("x" or "o") determined by the value of mark.
                takeTurn: function(square, mark)
                {
                    if (mark == game.turn && game.started)
                    {
                        if (game.board[square].value == "")
                        {
                            game.board[square].value = mark;
                        }
                    }
                },


Then iterate through the entire winPatterns array and set the appropriate values as well. For instance, if we're setting the square a to "x", then this needs to be set for anything in winPatterns where the square is "a". This makes it easy to check later if victory conditions are met.
                takeTurn: function(square, mark)
                {
                    if (mark == game.turn && game.started)
                    {
                        if (game.board[square].value == "")
                        {
                            game.board[square].value = mark;

                            for (var i = 0; i < game.winPatterns.length; i++)
                            {
                                for (var j = 0; j < game.winPatterns[i].length; j++)
                                {
                                    if (game.winPatterns[i][j].square == game.board[square].square)
                                    {
                                        game.winPatterns[i][j].value = mark;
                                    }  
                                }
                            }
                        }
                    }
                },


And then we modify the class of the appropriate square, adding the value of mark as a CSS class.
                takeTurn: function(square, mark)
                {
                    if (mark == game.turn && game.started)
                    {
                        if (game.board[square].value == "")
                        {
                            game.board[square].value = mark;

                            for (var i = 0; i < game.winPatterns.length; i++)
                            {
                                for (var j = 0; j < game.winPatterns[i].length; j++)
                                {
                                    if (game.winPatterns[i][j].square == game.board[square].square)
                                    {
                                        game.winPatterns[i][j].value = mark;
                                    }  
                                }
                            }

                            document.getElementById("square" + square).className = "square " + mark;
                        }
                    }
                },


Let's modify the CSS some more. While the cursor property for square is pointer, we want to hammer home the point that any occupied square is not clickable (notice that in the takeTurn() method, clicking does nothing if the square is not empty), so we set the cursor property to default.
            .square
            {
                width: 100px;
                height: 100px;
                margin-right: 10px;
                margin-bottom: 10px;
                float: left;
                outline: 1px solid #444444;
                background-color: #FFFFFF;
                cursor: pointer;
            }

            .x, .o
            {
                cursor: default;
            }

            #user_x_container
            {
                color: #FF4400;
            }


Use the before pseudoselector for x and o. We basically want it to fill up the inside of its parent, with maybe some padding. Font properties should be set to personal taste.
            .x, .o
            {
                cursor: default;
            }

            .x:before, .o:before
            {
                display: block;
                width: 80%;
                height: 80%;
                margin: 10% auto 0 auto;
                font-weight: bold;
                font-size: 3em;
                text-align: center;
            }

            #user_x_container
            {
                color: #FF4400;
            }


For x, the content is "X" and the color is orange. For o, content is "O" and color is green.
            .x, .o
            {
                cursor: default;
            }

            .x:before, .o:before
            {
                display: block;
                width: 80%;
                height: 80%;
                margin: 10% auto 0 auto;
                font-weight: bold;
                font-size: 3em;
                text-align: center;
            }

            .x:before
            {
                content: "X";
                color: #FF4400;
            }

            .o:before
            {
                content: "O";
                color: #44FF00;
            }

            #user_x_container
            {
                color: #FF4400;
            }


Go on, click on an empty square. An "O" should appear! Once it appears, mouse over that square and you should see your mouse cursor go back to default.


Back to the myTurn() method. We've established what happens when player "o" (the user) takes his or her turn. But what happens when the player "x" (the computer) takes its turn? We first set up a delay of one second.
                myTurn: function()
                {
                    document.getElementById("user_x_text").innerHTML = "";
                    document.getElementById("user_o_text").innerHTML = "";
                    document.getElementById("user_" + game.turn + "_text").innerHTML = "My turn!";

                    if (game.turn == "x")
                    {
                        setTimeout
                        (
                            function()
                            {

                            },
                            1000
                        )  
                    }
                }


Then we declare randomBlankSquare and set it to the returned value of the getRandomBlankSquare() method of the game object. Let's not bother about that method for now; but the plan is, it should return an integer which is the index of any one of the elements in the board array that has not yet been filled. And if all squares are filled, it returns null.
                        setTimeout
                        (
                            function()
                            {
                                var randomBlankSquare = game.getRandomBlankSquare();

                                if (randomBlankSquare == null)
                                {

                                }
                                else
                                {

                                }
                            },
                            1000
                        )  


If all squares are filled, display a message in the appropriate user's text box signifying that it's a draw. And set the started property of the game object to false to signify that the game is over.
                        setTimeout
                        (
                            function()
                            {
                                var randomBlankSquare = game.getRandomBlankSquare();

                                if (randomBlankSquare == null)
                                {
                                    document.getElementById("user_" + game.turn + "_text").innerHTML = "Looks like it's a draw.";
                                    game.started = false;
                                }
                                else
                                {

                                }
                            },
                            1000
                        )


And if there's a blank square, run the takeTurn() method of the user object, passing in the value of randomBlankSquare and "x". Which basically means player "x" places the mark on that square.
                        setTimeout
                        (
                            function()
                            {
                                var randomBlankSquare = game.getRandomBlankSquare();

                                if (randomBlankSquare == null)
                                {
                                    document.getElementById("user_" + game.turn + "_text").innerHTML = "Looks like it's a draw.";
                                    game.started = false;
                                }
                                else
                                {
                                    user.takeTurn(randomBlankSquare, "x");
                                }
                            },
                            1000
                        )


Wait... what happens if all squares are filled when it's player "o"'s turn?

Ah, I see the gears are turning! Logically, that never happens. The draw condition only happens when all 9 squares are filled. And that means 9 turns have to be taken. Player "o" always starts first... so if all 9 squares are filled, player "o" is always the one filling in the last square.

Back to the game!

We're going to fill in the getRandomBlankSquare() method. First, declare blanks. Set blanks to the array returned when you run the filter() method on the board array, returning only objects whose value properties are empty.
                getRandomBlankSquare: function()
                {
                    var blanks = this.board.filter(function (x) {return x.value == ""});
                },


If blanks is an empty array, return null.
                getRandomBlankSquare: function()
                {
                    var blanks = this.board.filter(function (x) {return x.value == ""});

                    if (blanks.length == 0)
                    {
                        return null;
                    }
                    else
                    {

                    }
                },


Otherwise, run the getRandomNumber() method, entering 0 and the length of blanks minus 1 as the minimum and maximum values.
                getRandomBlankSquare: function()
                {
                    var blanks = this.board.filter(function (x) {return x.value == ""});

                    if (blanks.length == 0)
                    {
                        return null;
                    }
                    else
                    {
                        var rand = this.getRandomNumber(0, blanks.length - 1);
                    }
                },


Next up is the getRandomNumber() method, and that's self-explanatory. We've been using that ad nauseam in web tutorials.
                getRandomNumber: function(min, max)
                {
                    return Math.floor((Math.random() * (min - max + 1)) + max);
                },


So now that you have a random number, run the findIndex() method on the board array. Compare the square property of the random element of blanks against the square property of each element in board, and return the matching index! Thus, if the square property is "a", then you will return 0. If it is "f", you return 5.
                getRandomBlankSquare: function()
                {
                    var blanks = this.board.filter(function (x) {return x.value == ""});

                    if (blanks.length == 0)
                    {
                        return null;
                    }
                    else
                    {
                        var rand = this.getRandomNumber(0, blanks.length - 1);
                        return this.board.findIndex(function (x) {return x.square == blanks[rand].square});  
                    }
                },


OK, now take a turn on the board! The computer should respond with "My Turn!" and place an "X" on the board, then make it your turn again!


For the next step, remember that once a turn is taken, we want to check for a victory condition. That's where the checkWin() method of the game object comes in. Pass in mark as an argument.
                takeTurn: function(square, mark)
                {
                    if (mark == game.turn && game.started)
                    {
                        if (game.board[square].value == "")
                        {
                            game.board[square].value = mark;

                            for (var i = 0; i < game.winPatterns.length; i++)
                            {
                                for (var j = 0; j < game.winPatterns[i].length; j++)
                                {
                                    if (game.winPatterns[i][j].square == game.board[square].square)
                                    {
                                        game.winPatterns[i][j].value = mark;
                                    }  
                                }
                            }

                            document.getElementById("square" + square).className = "square " + mark;

                            if (game.checkWin(mark))
                            {

                            }
                            else
                            {

                            }  
                        }
                    }
                },


If it's not a victory condition, run the nextTurn() method of the game object, signifying that the game goes on.
                            if (game.checkWin(mark))
                            {

                            }
                            else
                            {
                                game.nextTurn();
                            }  


If the game is won, put a victory message in the appropriate user's div. And then set the started property of the game object to false, because the game is over.
                            if (game.checkWin(mark))
                            {
                                document.getElementById("user_" + mark + "_text").innerHTML = "I win!";
                                game.started = false;
                            }
                            else
                            {
                                game.nextTurn();
                            }


The next thing to do is fill out the checkWin() method. By default, it returns false.
                checkWin: function(mark)
                {
                    return false;
                }  


Declare the findSquare variable and iterate through the winPatterns array using a For loop.
                checkWin: function(mark)
                {
                    var findSquare;

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
  
                    }

                    return false;
                }  


For each array inside the winPatterns array, check each object. If all three of the value properties of the array objects are set to mark, that means victory has been achieved. So return true.
                checkWin: function(mark)
                {
                    var findSquare;

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
                        if (this.winPatterns[i][0].value == mark && this.winPatterns[i][1].value == mark && this.winPatterns[i][2].value == mark)
                        {
                            return true;
                        }  
                    }

                    return false;
                }  


But of course, we need a visual indicator. So iterate through that array. Use the findIndex() method to get the index of the squares that have been identified as meeting the victory condition, and set the index to the value of findSquare. Then use findSquare to set add the CSS class win to that element.
                checkWin: function(mark)
                {
                    var findSquare;

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
                        if (this.winPatterns[i][0].value == mark && this.winPatterns[i][1].value == mark && this.winPatterns[i][2].value == mark)
                        {
                            for (var j = 0; j < 3; j++)
                            {
                                var winPatterns = this.winPatterns;
                                findSquare = this.board.findIndex(function (x) {return x.square == winPatterns[i][j].square});
                                document.getElementById("square" + findSquare).className += " win";                      
                            }

                            return true;
                        }  
                    }

                    return false;
                }  


Here's the styling for win. We basically set the background color to yellow.
            .o:before
            {
                content: "O";
                color: #44FF00;
            }

            .win
            {
                background-color: #FFFF00;
            }

            #user_x_container
            {
                color: #FF4400;
            }


Try it now. When you achieve victory, it should look like this. And clicking will not achieve anything more.


If it's a draw, it should look like this.


Well, that was fun...

... and brought back memories of having a pencil, paper and being a stupid kid.

xoxo,
T___T

Saturday 10 August 2019

Web Tutorial: Tic-tac-toe (Part 1/2)

Aloha!

Today, we will be doing something mind-numbingly simple... apparently. It's a Noughts And Crosses game on the web, also known as "Tic-tac-toe" in local parlance. 

Rules of the game, for everyone who hasn't played this as a kid (which is absolutely nobody, but let's do it anyway, just to spell out the requirements):

1. There is a 3 by 3 square board, totalling nine squares forming a larger square.



2. Each of the opponents take turns placing their mark (either "x" or "o") on the board.

X
O



3. Once either opponent manages to get three squares in a row with "x" or "o" (vertically, horizontally or diagonally), the game is won.

X O
X O
X



4. You can't place an "x" or "o" in any occupied square.
5. If there are no more vacant squares and no one has won the game, it ends in a draw.

Clear? Let's begin.

Set up some basic HTML structure. We'll just do the easy part first.

<!DOCTYPE html>
<html>
    <head>
        <title>Tic-tac-toe</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>

    </body>
</html>



Add a header tag and two buttons. Their ids are btnPlay and btnQuit respectively, and they're styled with the CSS class btn. One says "PLAY" and the other says "QUIT".

<!DOCTYPE html>
<html>
    <head>
        <title>Tic-tac-toe</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>
        <h1>Let's play Tic-tac-toe!</h1>
        <button id="btnPlay" class="btn">PLAY</button>
        <button id="btnQuit" class="btn">QUIT</button>
    </body>
</html>



So far so good. This is just the beginning.




Now for some CSS! It's a kiddy game, so let's use a kiddy font for the game... the hideously cheerful Comic Sans MS. I'm going to include some styling for the header and buttons, but honestly, they don't matter much in the grand scheme of things.

<style>
            body
            {
                font-family: "Comic Sans MS";
            }

            h1
            {
                width: 30em;
                text-align: center;
                margin: 0 auto 0 auto;
            }

            .btn
            {
                font-family: "Comic Sans MS";
                font-size: 2em;
                display: block;
                width: 5em;
                height: 1.5em;
                border-radius: 0.5em;
                border: 0px solid;
                background-color: #FF4400;
                color: #FFFFFF;
                margin: 1em auto 0 auto;
            }

            .btn:hover
            {
                background-color: #FFFF00;
                color: #FF4400;
            }
</style>



Bueno!




Add a div. The id is game_container. Within it, add three other divs. They are user_x_container, board_container and user_o_container. Style user_x_container and user_o_container using the player CSS class.

    <body>
        <h1>Let's play Tic-tac-toe!</h1>
        <button id="btnPlay" class="btn">PLAY</button>
        <button id="btnQuit" class="btn">QUIT</button>
    
        <div id="game_container">
            <div id="user_x_container" class="player">

            </div>

            <div id="board_container">

            </div>

            <div id="user_o_container" class="player">

            </div>
        </div>
    </body>


Within user_x_container and user_o_container, add divs styled using token and text. The divs styled using text should have ids of user_x_text and user_o_text, respectively. Also add smiley face symbols in the divs styled with token.

        <div id="game_container">
            <div id="user_x_container" class="player">
                <div class="token">&#9786;</div>
                <div id="user_x_text" class="text"></div>
            </div>

            <div id="board_container">

            </div>

            <div id="user_o_container" class="player">
                <div class="token">&#9786;</div>
                <div id="user_o_text" class="text"></div>
            </div>
        </div>



That's all you will see right now - two tiny smiley faces on the left.




Use different colors for user_x_container and user_o_container. I'm going with orange and green.

<style>
            .btn:hover
            {
                background-color: #FFFF00;
                color: #FF4400;
            }
           
            #user_x_container
            {
                color: #FF4400;
            }

            #user_o_container
            {
                color: #44FF00;
            }
</style>



For player, set the width and height, and use the margin property to align the divs to the middle of the screen. For token, this is mostly cosmetic. Set the font size to something large, limit the width, and float left. Since we want the smiley faces to align nicely, set the text-align property to center. text aligns left as well, and takes up 70% width. I've made some margin adjustments so that any text we put in there won't be hideously misaligned.

<style>
            #user_o_container
            {
                color: #44FF00;
            }

            .player
            {
                width: 600px;
                height: 150px;
                margin: 0 auto 0 auto;
            }

            .token
            {
                width: 20%;
                font-size: 5em;
                float: left;
                text-align: center;
                padding: 10px;
            }

            .text
            {
                width: 70%;
                font-size: 2em;
                float: left;
                text-align: left;
                padding: 10px;
                margin-top: 1.5em;
            }
</style>



And it's taking shape...




Now let's set the board. Add nine divs within board_container, all with a class of square. Set the ids from 0 to 8.

            <div id="board_container">
                <div id="square0" class="square"></div>
                <div id="square1" class="square"></div>
                <div id="square2" class="square"></div>
                <div id="square3" class="square"></div>
                <div id="square4" class="square"></div>
                <div id="square5" class="square"></div>
                <div id="square6" class="square"></div>
                <div id="square7" class="square"></div>
                <div id="square8" class="square"></div>
            </div>



board_container will be 330 by 330 pixels, and set in the middle of the screen. We give it a light grey background, and some padding to the left and top. square is a 100 by 100 pixel square, with a right and bottom margin of 10 pixels to separate it from the other divs, so we get some nice spacing between squares. Give it a deep grey outline and a white background. And finally, set the cursor property to pointer.

And... this really should go without saying, but, adjust colors to personal taste.

            .btn:hover
            {
                background-color: #FFFF00;
                color: #FF4400;
            }            body

            #board_container
            {
                width: 330px;
                height: 330px;
                margin: 0 auto 0 auto;
                background-color: #AAAAAA;
                padding-top: 10px;
                padding-left: 10px;
            }

            .square
            {
                width: 100px;
                height: 100px;
                margin-right: 10px;
                margin-bottom: 10px;
                float: left;
                outline: 1px solid #444444;
                background-color: #FFFFFF;
                cursor: pointer;
            }

            #user_x_container
            {
                color: #FF4400;
            }



OK! You have a board.




Time to JavaScript the hell out of this guy...

We still start with two objects - game and user.

<script>
var game =
{

};

var user =
{

};
</script>



game has four properties (a string, a boolean and two arrays) and seven methods (use these names for now; I'll explain as we go through them. user has two methods - takeTurn() and myTurn().

<script>
var game =
{
                turn: "x",
                started: true,
                board:
                [

                ],
                winPatterns:
                [

                ],
                init: function()
                {

                },
                play: function()
                {

                },
                quit: function()
                {

                },
                getRandomNumber: function(min, max)
                {

                },
                getRandomBlankSquare: function()
                {

                },
                nextTurn: function()
                {

                },
                checkWin: function(mark)
                {

                }               
};

var user =
{
                takeTurn: function(square, mark)
                {

                },
                myTurn: function()
                {

                }
};
</script>



For the game object, turn is a string used to determine whether player "x" or "o" gets to make their turn. Kind of like a traffic controller, if you will, and set to "x" by default. started is a flag that determines if the game has begun. By default, it's true.

board is a series of objects - each with square and value properties. The square property corresponds to the layout of the board. value is meant to determine if the square is currently occupied by "x" or "o".

a b c
d e f
g h i




var game =
{
                turn: "x",
                started: true,
                board:
                [
                    {square: "a", value: ""},
                    {square: "b", value: ""},
                    {square: "c", value: ""},
                    {square: "d", value: ""},
                    {square: "e", value: ""},
                    {square: "f", value: ""},
                    {square: "g", value: ""},
                    {square: "h", value: ""},
                    {square: "i", value: ""}
                ],
                winPatterns:
                [

                ],
                init: function()
                {

                },
                play: function()
                {

                },
                quit: function()
                {

                },
                getRandomNumber: function(min, max)
                {

                },
                getRandomBlankSquare: function()
                {

                },
                nextTurn: function()
                {

                },
                checkWin: function(mark)
                {

                }               
};



winPatterns is an array of an array of objects that help you determine if victory has been achieved. Take, for example, the first array that has been filled in for you. "abc" is a straight line right at the top of the board.

var game =
{
                turn: "x",
                started: true,
                board:
                [
                    {square: "a", value: ""},
                    {square: "b", value: ""},
                    {square: "c", value: ""},
                    {square: "d", value: ""},
                    {square: "e", value: ""},
                    {square: "f", value: ""},
                    {square: "g", value: ""},
                    {square: "h", value: ""},
                    {square: "i", value: ""}
                ],
                winPatterns:
                [
                    [
                        {square: "a", value: ""},
                        {square: "b", value: ""},
                        {square: "c", value: ""}
                    ]
                ],
                init: function()
                {

                },
                play: function()
                {

                },
                quit: function()
                {

                },
                getRandomNumber: function(min, max)
                {

                },
                getRandomBlankSquare: function()
                {

                },
                nextTurn: function()
                {

                },
                checkWin: function(mark)
                {

                }               
};



And the rest, you can figure out yourself. There are eight possible winning combinations.

                winPatterns:
                [
                    [
                        {square: "a", value: ""},
                        {square: "b", value: ""},
                        {square: "c", value: ""}
                    ],
                    [
                        {square: "a", value: ""},
                        {square: "d", value: ""},
                        {square: "g", value: ""}
                    ],
                    [
                        {square: "a", value: ""},
                        {square: "e", value: ""},
                        {square: "i", value: ""}
                    ],
                    [
                        {square: "b", value: ""},
                        {square: "e", value: ""},
                        {square: "h", value: ""}
                    ],
                    [
                        {square: "c", value: ""},
                        {square: "f", value: ""},
                        {square: "i", value: ""}
                    ],
                    [
                        {square: "c", value: ""},
                        {square: "e", value: ""},
                        {square: "g", value: ""}
                    ],
                    [
                        {square: "d", value: ""},
                        {square: "e", value: ""},
                        {square: "f", value: ""}
                    ],
                    [
                        {square: "g", value: ""},
                        {square: "h", value: ""},
                        {square: "i", value: ""}
                    ]
                ]



Now let's set create the init() method for the game object. This initializes the properties of the game object. We start with setting turn to "x" and started to true.

                init: function()
                {
                    this.started = true;
                    this.turn = "x";
                },



And then we iterate through the board and winPatterns arrays, and reset all values to an empty string.

                init: function()
                {
                    this.started = true;
                    this.turn = "x";

                    for (var i = 0; i < this.board.length; i++)
                    {
                        this.board[i].value = "";
                    }

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
                        for (var j = 0; j < this.winPatterns[i].length; j++)
                        {
                            this.winPatterns[i][j].value = "";
                        }
                    }
                },



After that, go through all the squares in the board and reset the class to square.

                init: function()
                {
                    this.started = true;
                    this.turn = "x";

                    for (var i = 0; i < this.board.length; i++)
                    {
                        this.board[i].value = "";
                    }

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
                        for (var j = 0; j < this.winPatterns[i].length; j++)
                        {
                            this.winPatterns[i][j].value = "";
                        }
                    }

                    for (var i = 0; i < 9; i++)
                    {
                        document.getElementById("square" + i).className = "square";
                    }
                },



Then clear the innerHTML property of all elements styled using the text CSS class.

                init: function()
                {
                    this.started = true;
                    this.turn = "x";

                    for (var i = 0; i < this.board.length; i++)
                    {
                        this.board[i].value = "";
                    }

                    for (var i = 0; i < this.winPatterns.length; i++)
                    {
                        for (var j = 0; j < this.winPatterns[i].length; j++)
                        {
                            this.winPatterns[i][j].value = "";
                        }
                    }

                    for (var i = 0; i < 9; i++)
                    {
                        document.getElementById("square" + i).className = "square";
                    }

                    var texts = document.getElementsByClassName("text");
                    for (var i = 0; i < texts.length; i++)
                    {
                        texts.innerHTML = "";
                    }
                },



For the play() method, hide the "PLAY" button and show the "QUIT" button. Then show game_container and run the nextTurn() method.

For quit(), you do almost the exact opposite - show the "PLAY" button and hide the "QUIT" button. Then hide game_container. But before all that, run the init() method.

                play: function()
                {
                    document.getElementById("btnPlay").style.display = "none";
                    document.getElementById("btnQuit").style.display = "block";
                    document.getElementById("game_container").style.display = "block";
                    this.nextTurn();
                },
                quit: function()
                {
                    this.init();
                    document.getElementById("btnQuit").style.display = "none";
                    document.getElementById("btnPlay").style.display = "block";
                    document.getElementById("game_container").style.display = "none";
                },



Now make sure the buttons run those.

        <button id="btnPlay" class="btn" onclick="game.play()">PLAY</button>
        <button id="btnQuit" class="btn" onclick="game.quit()">QUIT</button>



For there to be anything noticeable when you click the buttons, you first need to set this CSS to hide the "QUIT" button and game_container. Now, refresh. Click the "PLAY" button. It should disappear, only to be replaced by the "QUIT" button. And then the board should appear as well.

            .btn:hover
            {
                background-color: #FFFF00;
                color: #FF4400;
            }

            #btnQuit, #game_container
            {
                display: none;
            }

            #board_container
            {
                width: 330px;
                height: 330px;
                margin: 0 auto 0 auto;
                background-color: #AAAAAA;
                padding-top: 10px;
                padding-left: 10px;
            }



The nextTurn() method will set the turn property to "x" if it's currently "o", and vice versa. Then it will run the myTurn() method of the user object.

                nextTurn: function()
                {
                    this.turn =  (this.turn == "x" ? "o" : "x");
                    user.myTurn();
                },



Let's create myTurn(), then. This will manipulate the DOM to display whose turn it is on the board. First we clear the user_x_text and user_o_text divs, then fill the appropriate div with the string "My turn!".

                myTurn: function()
                {
                    document.getElementById("user_x_text").innerHTML = "";
                    document.getElementById("user_o_text").innerHTML = "";
                    document.getElementById("user_" + game.turn + "_text").innerHTML = "My turn!";
                }



If is the computer's turn, i.e. "x", then we do more stuff. Let's just leave the If block here for now.

                myTurn: function()
                {
                    document.getElementById("user_x_text").innerHTML = "";
                    document.getElementById("user_o_text").innerHTML = "";
                    document.getElementById("user_" + game.turn + "_text").innerHTML = "My turn!";

                    if (game.turn == "x")
                    {

                    }
                }



Now test this. When you refresh, you should now only see the "PLAY" button.




When you click the "PLAY" button, does "My turn!" come on for player "o"?




Next

The groundwork has been laid. The next codes we write will handle the meat of the game.