Are you learning to become a programmer? Have you spent time mastering a language and gone through all the important algorithms? Have you created all sorts of simple and fun applications? Do you want to put everything you know about writing software into action? My goal here is to help bridge the gap between knowing how to write code and creating something out of code. You can create small algorithms, which is impressive, but what about a whole project, how about a Chess game?
Creating a Chess game may seem too big a challenge for someone who is new to developing software, but while we go through all the steps, you will learn and see that almost anything is possible, if you break them down into smaller blocks. Do not be afraid of the size and complexity of the project you want to create. Rome wasn't built in a day, and they didn't just give up on day one because the job looked impossible.
I am treating this like a development diary. Writing my thoughts and plans down as I work my way through the process. I will probably make some errors along the way, and rewrite stuff, but hopefully you will see how a software developer thinks and works.
At the start of a new project, I normally have no clear idea what I want it to become, I only have a list of ideas which grow and sometimes change over time. For now, this is what I want the project to be.
I do not want it to be able to play against other people over the internet, that would be too much to do, requiring backend servers, user accounts, and other parts that would cost real money to put together.
So, where on earth do I begin? Before I start writing any code, I get a notepad and pen and start to list the different parts and how they all link together. I first want to list the stuff I think I need.
I also want to test different modules, making sure they are working correctly. However, it is important not to start writing any testing code right away, as I am more than likely to be changing the code, or even removing some of it, long before it is finished. I normally start writing tests after I am sure the code I have created will be in the final project and is unlikely to change much.
I am going to start by creating something very basic, a list of the pieces that are used. However, even at this point there are choices to make. The first thing to consider is the name of the file. Should I name it "pieces.js" (plural), "piece.js" (singular), "Pieces.js" (capitalized) or something else. Personally, within JavaScript projects, I always name files and folders in lower case and in a singular form. If the name has more than one word, I add the hyphen "-" character between them (best-file-name-ever.js). I do this because some hosting platforms prefer it this way, and Linux/Windows OS treat file names with upper case characters differently.
You may notice that I like to add comments to my code, even when they are not needed. For me, any code without some green (the traditional color of comments) looks out of place. There needs to be more comments than code, but not too much, anything that starts to look like documentation really needs to be moved out into a document on its own. This is not the law however, and most JavaScript code I see has almost no comments, which looks rubbish to me.
When it comes to tabs, in coding source files (*.js), I use 4 spaces for tabs. For CSS and HTML files I use 2 spaces. This comes from my many years of C/C++/C# programming, a long time ago, and is something my own eyes prefer. I have other funny quirks which you will start to notice as we continue.
I also prefer, where possible, to have one "class" per source file. This should allow me to quickly find the class module by looking into the relative file. I name the file to match the name of the class. With the "export default" keywords, I can "import" the source file without needing to name the classes I want to access. I guess I got this way of thinking from using Java (also many years ago). All class names start with a capital letter, which I think is a standard naming convention, though it is not mandatory.
You may be wondering why I have loads of static upper-case variables?
Later, I will be comparing piece variables together, seeing if square (x,y) is a KING or something.
I could give the variables the name of the piece and compare it to that, for example, if (boardSquare.piece === 'king') {...}.
When I do this, it is faster to compare numbers rather than strings (text).
It is also more memory efficient, not having the text "king" littered all over your code.
Also, technically, they are used as constants, something that does't change, which is why they are upper case, an old programming convention from my C/C++ days.
I am not sure if it is better to just have the pieces without any player color part, and then to also include the player's color.
At this stage, I look into the future of the project and try to see what the better method would be. I can always change it if things start to look odd.
I have also added the EMPTY option, which is given the default value of zero. If there isn't a piece, then the board square is seen as being empty. It may seem odd to have a piece called EMPTY, but I have a feeling I will need it later.
I have made a start, I am now fully committed, and only hard work and complexity can stop me now. I have created my first source file, but now I am not sure where to keep it? I now start to look into the future and think about what bits are needed, and where to put them. I need to work out a good folder layout that I can use for all the different parts.
There is no standard, no fixed way to name your folders, only lots of different methods and maybe the odd person proclaiming their way is the right way. Not me though, I change my ways all the time, whatever works will do, depending on the project (more or less).
For now, I am going to have two folders, one for the main "chess" source code, called "src", and another one to put all my testing stuff inside, called "testing". Why not call it "source" instead of "src"? Tradition. Long ago disk operating systems (DOS) were restricted to file and folders names of no more than 8 characters long (plus the 3-character extension). This forced software developers to stop using real names and to abbreviate everything. The word "source" is less than 8 characters, I know, but the confusion needed to be consistent, so it was shortened, and the convention has stuck around forever.
I now move on to thinking about the board and how it is going to look. In my mind I create the parts I think it should have and how they would be used. Here are my initial thoughts.
The main idea is for there to be a Board object that represents the current state of a game, which I can pass on to different functions.
There is no single perfect method of creating this, no single "right" way, though I can think of some wrong ones, but whatever works nicely, looks and feels correct, is normally good enough. Plus, I can change it later when I change my mind.
So, what should I call the file and the class. Maybe "ChessBoard", though I am already inside a "chess" library of sorts, so using the word "Chess" again seems redundant. I think "board" would be a good fit, as it could not be mistaken for something else and seems logical. Naming stuff can be easy at times.
When thinking about how to list the pieces on the board, I come up with a few different ideas. First is to a "Square" object that contains the piece, its location and if it has moved.
Then I have a list of all the squares on the board, that is 64 (8x8) Square objects, one for each possible location.
Or, I could only have one Square object for every piece on the board, that is 32 (8x2x2), which would take up less memory.
But, how about I make two lists, one for white pieces and one for black ones.
None of these ideas sit well with me.
Later, I want to work out if there is a piece next to another one, how do I do that, by searching each Square object and checking their row and column values?
Though the data is stored well enough, it cannot be used in a quick and simple way.
If it feels wrong, then I need to dream up some other options.
Cooking, eating, watching something boring on the TV, or trying to sleep. These all seem like the best time for my mind to dwell on problems like this. The mind can dream up lots of ideas and run through how they could be used without needing to use a computer. By the time you are finished with breakfast you should have some new ideas to play with.
I came up with a new idea on how to structure the board.
I will no longer use the Square object.
Instead, I will have a list of integer numbers, one for each square location on the board, containing a Piece constant value.
There will be additional members for all the other information required.
This is the start of the Board class.
The constructor is used to set up the object when it is created with the new keyword, adding all the members with their starting values.
I also use this to lay out the internal variables (private members) that will be used throughout the whole class.
In JavaScript there is a way of setting a variable up as private, which means it cannot be used outside of the class, by starting the variable name with the "#" hash character, but it is not something I like to use, because I often need access to private members for testing. Instead, I prefix my private variables with an "_" underscore character.
Inside the constructor I start off by setting the number of rows and columns, which for now will always be 8x8. I then move on to the list of squares, which is set to null, instead of an array with 64 integer items. I am not sure if this is the best thing to do at this point. My thinking is, keep it simple in the constructor, and set it in one of the other functions.
I then set the player to white by default.
My first idea was to use integer values 1 and 2, instead of using a constant, PLAYER_WHITE,
but you would need to always remember that 1 is white and 2 is black every time you use the _player variable.
This didn't seem like something my future self would want to do.
Now, however, I still do not feel right. I have the player constants inside the Board object, instead of having some type of Player object,
just like I did with the pieces.
I find myself in two minds about this.
Which one looks and feels better?
Sorry, it's no good.
Even though I know an extra file will probably need to be loaded for everything to work, and the Player object will be very small,
I need it all to fit together well in my head, otherwise it will irritate my mind.
I have removed the PLAYER_xxx constants and created the "player.js" file.
Not the most exciting source code you'll ever see. I do wish my other work was as simple to write. Still, I do feel better now it is all over. On to the next problem.
Now for the rest of the members I set in the constructor. The king can castle, but only if the king and rook have not moved before. Therefore, for each king (white and black) and for both rooks (king side and queen side), I want to flag if they have moved or not. By default, no pieces exist so I guess they haven't moved.
The last member uses a French word that I don't understand. It is related to the pawns and the "en passant" move, something you may want to look up. I was thinking that I would need to record some type of flag for each pawn, but technically, you can only have one possible en passant at a time. Here, I am recording which of the columns it is that a pawn last moved up two spaces. After the next player moves, this flag is reset to nothing.
I was thinking of adding an "in check" member, to state if the current player is in check or not, but this is something that could be worked out. For now, I do not think it is required, but I will have to see what the future has for us.
Object-oriented Programming (OOP) is one of those programming models that has been around longer than most programmers have been alive. You either use it without knowing and therefore don't really care all that much about it, or it is some gold standard solution to all of mankind's problems. I find it best to use it when needed, only understanding how it can work when you need it to, but not use it to abstract everything into meaninglessness. It's best to try to keep things simple, even if that means writing more code.
With all that said, I come to the point of adding getters and settings. Even though you don't always need them, and they can fill up source code with unnecessary clutter, I do like to add them. I think I had it drummed into me in my C++ and C# days, which always required them (if you wanted good looking code).
Here I am giving the owner of a board object access to the number of rows and columns of the board's grid. I do not have any setters for these values because if they are changed then I would need to reset the square list, by increasing or decreasing the number of integers listed within. It would mean changing the board's grid size after creating it, at any time, which doesn't seem like something you would want to do. These values are going to be set when the board is created using some static functions I will create later.
I have added a getter for the list of squares. Again, there is no setter, but this time it is because this is an array, and I do not want the whole array to be set to a totally different array. I can still change the items within, even add and remove items (which is not something I want to do), because I am getting the array object, which then allows you to access its member properties and functions. For example.
The player has both a getter and a setter.
This means you can change whose turn it is to play.
I am using the parameter type Number, even though the constants are from the Player class, because I am not setting the class itself,
only some value it contains (either 1 or 2).
I also include getters and setters for the other properties. I won't add it here, it's not very exciting, you can check the source code.
You may have noticed some odd text in the comments starting with the "@"" character, @param and @return for example.
These are part of the JSDoc standard and are used to help document what a function's parameters and return types are.
It can be used by Visual Stupid Code to give IntelliSense information while you are typing in the function and its parameters,
and it can also perform simple type checking, making sure you are entering a Boolean and not a String.
The original idea behind the JSDoc system was to create a set of documentation detailing all the classes and functions used within a project. This is not something I would want to do for a library, because there are better methods to document them (mark down files for example). I think the tools used by JSDoc are not used that much, but the embedded notations are, and they come in very useful for JavaScript.
There is another option, using TypeScript, but for me, this is a technology that is no longer needed and seems pointless. I have stronger views about this which I'll not go into here. However, if your boss wants you to use it, I guess you just learn to work with it (even if it's a bad idea).
I have added the constructor and all the getters and setters. Now it is time to start adding in the functions (also known as methods). I want to be able to get the piece located at a given row and column in the grid. I also want to be able to set a piece at a given row and column within the grid.
I have the grid set up so that the square list contains each row, one after the other, starting at the bottom left of the board and moving up to the top right.
This way, I can quickly find out the location of the square inside the list by using the (row * this._columnCount) + column calculation.
I do not validate the parameters. I am not checking if the row and column values are within the correct range, between 0 and the column/row counts. I am also not checking if the square list member exists and isn't null. These functions will be used primarily within other functions inside the chess library, and therefore it is up to me to make sure I am using them correctly. You only need to validate parameters on functions other people are likely to use, and even then, you don't have to.
A chess board does number to rows from 1 to 8, but I am using row numbers 0 to 7. Also, the columns on a chess board are from "a" to "h", but again I am using column numbers 0 to 8. I will need to keep this in mind when creating the user interface parts.
Now that I have these functions, I am thinking that the squareList property (getter function) is no longer needed.
You can access the required data using these functions instead of using the square list directly.
I will leave it in for now. I may remove it in the future.
I want a function that creates a board object and sets up the square list array.
This can be done in a few different ways, but I have chosen to use a static create function.
But why a static function?
The Board class seems like the right place to put a function that creates a new board,
but the function cannot be part of an existing board object, not without looking odd, so using a static function fits well.
You would use it like this.
I have added default parameter values, both set to create an 8x8 grid of squares. The function doesn't have much to do, just set some members, create the list and populate it with empty pieces.
I also want to include a way of cloning a board, to make a copy of one. I have created another static function, this time called clone (I'm great at naming stuff).
This function doesn't need to be static. It may even make more sense to have it as normal function.
At times like this I just do not know what to do for the best. I can live with either, but whichever method I choose I'll have to live with it forever (or until I change it). I'll sleep on it, but for now it's staying static.
I want to represent the board as a set of encoded characters in text. This requires me to create two functions, one to encode the board and another to create a board by decoding the text. This can be done in many different ways, but I want something quick and simple. I am dealing with integer and boolean values, which are not characters, so I need to convert them into some type of character encoding.
The Booleans are either true or false, which can be converted as either "T" or "F".
The row and column count values can range from 1 to 8 (or larger if required).
The pieces range from 0 (Piece.EMPTY) to 12 (Piece.BLACK_PAWN).
I can convert the integers into alphabetic characters, "a" = 0, "z" = 25.
In this function I am taking the board and for each member converting their values into a text character.
The row count value of 8 is converted into the ASCII character value 97 + 8 = 105, which is the character "i".
The Boolean member "whiteKingMoved" is checked, if true then the "T" character is used, otherwise "F" is added.
The result is a string with either "a" to "z" or "T" and "F" characters in them.
The reverse process follows the same sort of steps, converting the characters into values for the board's members. You pass the code as a parameter and the result is a new board containing the same state as one used to create the code.
I have finished writing the source code for the Board class, but are there any bugs, does it work correctly,
can I really be sure there isn't something wrong with it?
No matter how great my coding stills are, I will make mistakes, my code will always have faults, and I will always need to double check it.
I could just check if it works while I am using it later, debugging it, going through it line by line, manually once or twice, there's no problem doing this right?
When creating software that will be public, where other people (even programmers) will be seeing it, there is a higher standard required, it not only needs to look good, not only works correctly, but it needs to be bulletproof. This is where testing code comes in.
In a separate section of the library, I will be creating a collection of testing functions that will be using the main chess source code in different ways to check it works correctly. This set of testing code would not be distributed with the rest of the source code, it is only used to test the main source code, and therefore it does not need any documentation, any special optimization, and the code doesn't have to look perfect. It is only used internally.
It is somewhat standard practice to include a set of testing functions with every software library or application. However, how much testing I include, what functions are tested, when I create the test function, changes from project to project. For private projects, or when adding something simple, I don't use automated testing.
As with all things in the world of software development, there are many ways to handle testing.
Also, like most software developers, I don't use any of them and have created my own.
I use the same Test class tool in all my projects.
It really doesn't do all that much, it only asserts if an object exists and asserts if a property equals a given value.
I have created the file "test-board.js" that will hold all the code required to test the Board class and all its functions.
I start off by importing all the chess library source code I need to perform all the tests.
I also import the Test tool.
Each testing class will contain a static run function that performs all the individual tests.
I use the Test tool's test function to state what module I am testing.
After this I perform all the different tests one by one.
Each of these tests are just static functions, nothing really fancy going on here.
In this test I am first calling the Test tool's describe function to state what is being tested.
Then I create a new board using default parameters and then call the Test tool's assert functions to make sure each of
the board's properties have the right values.
After all this, whenever I make any changes to the software, I can perform all the tests to make sure I haven't broken anything. It makes me feel good when everything passes and everything is good to go.
This whole testing process may seem unnecessary but when I created and used it, I did catch some faults in my code. So, it can be useful, and for creating something like a chess engine, it will be important.