I now have a Board class with testing code to make sure it all works great.
But I now ask myself, where do I go next, what is my next move?
I want the computer to work out its next move, but before I can do that, I need to be able to make my own move, and before I can do that,
I need to work out all the valid moves that can be made next.
If I select a piece on a chess board, I want to know where it can move next.
This seems like a good next step for me too.
I will create a Move class that can be used to work out all the stuff relating to pieces moving on the board.
This is where things start to get more complicated, which for some people like me, is the fun part. However, things do not get very far.
My new Move class has the static function listNext, but when I start to think about what to return, what a list of moves looks like, I get stuck, I'm really not sure. When a piece moves it can do one of the following.
I need a list of moves that contain all these possibilities.
I could create a base Move class and then have CaptureMove, CastleMove, PromoteMote classes derived from it?
I could have a single Move class with a moveType property with some type constants (TYPE_CAPTURE, TYPE_CASTLE, etc).
Either way, I would need to change the name of my current Move class to something else, but what?
I really struggle with naming stuff at times!
After some thought, I will create a single Move class that handles all movement types,
and I will create a MoveCalculator class that will be used to work out the next possible moves a player can make.
I was thinking about calling it MoveGenerator, or just Calculator, but there are times when there is no perfect word to use,
and you must pick something, and stop wasting time searching for the impossible (or, maybe I could just call it PossibleMoves, no that's worse).
Before I can start making my move calculator class, I need to make the Move class,
which will be used to give information about a possible move a piece can make.
This is what I have come up with so far.
I have the static constants at the top, the TYPE_ parts, listing the type of moves that are possible.
Inside the constructor I list all the members needed for each of the different moves.
Some members will be used for all move types, some will only be used for the one type of move.
Looking at this, I have noticed a number row/column pairs. These are used to point to a square within the board's grid. Like X/Y coordinates for a vector in math. I am thinking that I should create a new class that points to a single square, giving a row and column value. I would end up with something like this.
In my mind it does seem like a good idea, but when I think about how it would be used in the future,
it may be a pain point, having to create a Square object each time I want to access a piece on the board.
I guess this good idea isn't really all that good.
Therefore, I have abandoned the Square class idea and I am sticking to using rows and columns instead.
I have added getters for each of the members.
There are no setters for them, only getters, because the members are set by one of the static create functions I will be adding later.
Here is what the fromRow getter looks like.
After getting this far, I now start to think whether the Move class covers everything I need it to do.
I can't really know what the future is going to look like and I normally need to add other parts that I've missed.
Code isn't concrete, I can change it whenever I need, but doing so can create pain points, and throw any design you have created into a mess.
Early on in development, changing things can be simple, but after the code base has grown, after it has been deployed and is being used by hundreds of users,
then making changes will not be so simple.
There was something missing.
I want to know if a move has put the opponent into check or checkmate.
Also, when castling, there is nothing stating which rook is being used.
I need a casteRookFrom and castRookTo row column parts too.
Even more so, I need to know the rook piece, because it could be either a white rook or a black rook.
I didn't like the "(if relevant)" comments too, so I have removed them.
I will add these changes and the extra required getters.
Hopefully I haven't missed anything else.
I now need to add the static create functions.
These will take a number of parameters, create a new Move object, set the required members for what I am creating, and then return the object.
What am I talking about, well, below is the createMove function.
This function has a lot of parameters.
All the static create functions basically do the same type of thing.
The functions are createMove, createCapture, createCastle, createPromotion and createEnPassant,
one for each type of move available.
I could just create the move objects like this whenever I need them, but I wanted the logic relating to what the members do and are for,
to stay within the Move class, just in case I need to add more members or change something else.
These static create functions help keep the complexity of the Move object all within itself and not scatter it around the code base.
My future self will thank me.
The final part to this Move object is to create all the testing functions to make sure I haven't created any bugs.
Now, at last, I can return to the complicated part of working out what the next possible moves could be. I have created the "move-calculator.js" file, imported the modules I need and then stopped, as I try to work out what main public functions I need to have. How am I going to use this move calculator class? Because this is one of the more complex parts of the whole chess library, I want to hide all the difficult parts inside and only have one or two simple functions that handle all the hard work for me.
When a player selects a piece on the chess board, I want to be able to show where they can move it. To do this I will want some type of "list all possible moves for the given piece on the board" function. When the computer is trying to work out the next best move, it will want a "list all possible moves for the given player (either black or white)" function.
To start off with, I have created the listForSquare function, which, as you can probably guess,
is for getting a list of moves for a single piece on the board.
You pass a board object, the location of the piece and you get back a list of all the possible moves that can be performed.
I am creating a moveList array, passing it on to another _list function and then returning it.
The _list function is doing all the hard work.
I will be using it again in the next function, listForPlayer, as well.
The second function is used to work out all the possible moves for all the pieces for the given player.
It again creates a moveList array and returns it at the end.
I need to look at each square on the board, this is why I am looping through each row and column.
For each square I need to perform the following.
I get the piece on the board at the given row and column location.
I then check if there is a piece there or if it is empty.
After this I make sure I only look at white pieces if the player is white and likewise only black pieces if the player is black.
If I know the piece needs to be looked at, I can call that _list function to add possible moves to the moveList array.
Both functions are basically doing the same sort of thing.
They both create a moveList array, call the _list function, and return the list.
I wanted both functions to be simple, passing on the complexity to a shared function used by both.
I didn't want to duplicate the move calculation algorithms.
So, both functions pass the hard work on to the _list function. What does this look like?
This function is checking which piece it is and forwarding the hard work on to another function. I am reducing the whole complex block into easier to handle smaller blocks. It is also a way for me to put off doing the hard stuff for a bit longer, however, I will need to start calculating possible moves at some point.
I am going to start with one of the simpler pieces, the rook, which can only move horizontally or vertically. It can be used with castling, but I will leave that for the functions handling the king piece.
I am going to start by moving left and seeing what the code looks like.
I am not very happy with this. I have some problems that I need to look into.
isBlack, isWhite function to keep the code looking less cluttered.
I find myself writing code that checks to see if a piece is white or black.
This ends up with a lot of lines of code, comparing the piece to each type of white or black piece.
To tidy things up a little, I want to add two functions that make all those comparisons.
The most logical place to put them is into the Piece object.
This is the black version of the function (there is a white one too). I am checking the piece and returning true if it is one of the black ones. Why not one big condition with lots of "||"" or parts, why am I checking each piece one at a time? Technically I could talk about optimization, how the code would look on the CPU, and about minimizing the number of comparisons, but this is JavaScript and it really doesn't matter all that much. The main reason is because it looks nice to me and fits well in my head.
I have also added some testing to make sure the functions operate correctly. Some of these tests seem pointless, a little over-kill, but if I want bulletproof code, stuff like this must go in.
As I was going through the move calculator function listForPlayer, to replace the old piece checks for the new one, I found it contained an error.
The old code, above, was checking if the piece was black, and if so, skipping it, where it should have been the other way around. Compare it to the newer code below.
If the player is black, but the piece is not black, then skip. I make mistakes like this all the time.
Back to the _listWhiteRook function and other issues I found before.
I need to make sure a move does not leave the player in check, and I need to see if I have put the other player into check or checkmate.
I have added in the isBlack function to replace the large condition I had before.
I am now creating the move object without the check and checkmate parameters.
I want these properties to have their own settings, so that I can set the state of the check and checkmate values afterwards.
Doing this makes the Move object feel a little less than perfect.
Forcing what was a simple symmetrically designed class into a bit of a misshapen fudge.
This also makes me wonder, should I do these checks at this point (for each move I create),
or add all the possible moves without knowing if they are valid and then later perform the required check related processing.
At the moment I do not have the inCheck and inCheckmate functions, and if I can add them later, I can continue making the other parts first.
Also, testing may be easier, as I can start looking at the _listWhiteRook function without needing to finish the whole move calculator class.
Now, after the list of moves has been created, this function will process it, making sure the move is valid (not leaving the player in check),
and set the check and checkmate properties.
I cannot perform any testing on this function at the moment, so I will just have to hope they work for now and return to it in the future.
Going back to the _listWhiteRook function, I have removed the check related parts and just added the created move objects to the list.
I need to go back to the Move class and make changes to the check related properties.
I have removed the check and checkmate parameters from the static create functions.
This is the adjusted createMove function with the parameters removed.
The other create functions are basically the same.
The new setter functions for check and checkmate have been added.
This now allows the move object to have these properties adjusted at any time after they have been created.
When I returned to the _listWhiteRook function, I started to think about creating the same type of function but for the black rook and
saw that the only difference would be the handling of the piece's color.
It would be better to have one function for the rook, no matter what color piece was being used.
Maybe I could have a single function for bishops, knights, queens and so on, instead of having one for each color piece.
This would cut down the total size of the code I need to write, but more importantly, the logic for moving rooks is in one place, and not duplicated in two areas (one for white and one for black).
I have renamed the function to _listRook and added the new player parameter.
The first thing the function then needs to do is set which piece the player is moving, either the WHITE_ROOK or the BLACK_ROOK.
The playerPiece is then used instead of the hard coded Piece.WHITE_ROOK constant.
The problem I have now is what to do with the opposition piece check I perform.
At the moment I am only looking to see if the piece is black, but now I need to check if the piece is the opposite of the player.
What can I do?
I could do something like this, or maybe combine them?
How about adding a new function that does the check.
I could add a function to the Piece class that checks if a piece belongs to the given player.
That name "belongs" just doesn't feel right though.
Is there something better I could use?
How about "own", "owner", "instance", "isPlayer", or maybe "isOwner".
I find myself spending more time thinking about naming functions than creating them some times.
I know, "isPlayer" sounds about right, as I already have isBlack and isWhite functions.
This is the new function for checking if a piece belongs to a player.
It is using the other static isWhite and isBlack functions instead of comparing the piece to all the piece constants,
as there is no need to duplicate other conditions.
I have also added some extra test functions to make sure they work correctly.
Back to the _listRook function.
So far, I have added moves by checking all the squares left of the piece.
I need to now look for moves in the right, up, down directions.
Each one has its own loop, adjusting the next row and column variables, and basically performing the same set of checks within.
In the queen version of this function, I will need to check the diagonals too, that's 8 loops.
I need to think of a better way of handling this.
I have created a loop for each direction, 0 is left, 1 is right, 2 is up and 3 is down. I can then use this direction to work out how to increase or decrease the next row and column. I needed to add some extra checks to make sure the row and column are still on the board's grid and haven't moved outside of it. After this everything is more or less the same as before.
I just need to go back to the _list function and change the functions they are calling, so that _listRook is being called.
I have finally finished the first part of the move calculator. However, before I move on, I need to start thinking about testing the moves. I have a feeling this will be boring but important.
I have made a start creating the move calculator and I feel now is the time to begin adding testing for it. I would not normally create testing so early on when building a class, usually I make sure everything is finished first, but the size of this move calculator is going to grow, and I want to make sure each sub-part is functioning correctly before I move on to the next part.
There is a danger in doing this. I could spend time creating the tests, only to later redesign the code, which would then require me to rewrite the testing code. I could be wasting time with the testing (and its rewriting) while still trying to solve and create the main code. I guess I'll have to wait and see if doing it now is a good idea or not.
The question now is, what do I test and how do I test it?
I have the _listRook function, which is finished and can be called.
It is a private function, but I still have access to it.
I will need to create a board, set some test pieces on it, call the function, and make sure the results are what I was expecting.
There are going to be a lot of different types of tests and hard coding in all the board setup and results could take a lot of coding.
Maybe I could create some test data files with this type of information?
Here are my first thoughts. This would be a JSON file, containing the name of what is being tested, with a list of all the tests, each with a starting board layout, and what the move locations need to be after performing the test. The testing functions would need to look something like this.
This is very ruff at the moment. I would also need to come up with formatting of the boards, and end move encoding. I am thinking of the following.
You cannot use this method to test castling, pawn promotion and maybe some other things. Is all the extra work needed for this worth it? How many of these different tests am I going to do?
For the _listRook function I want to test the following.
That is around 25 tests for the white rook, and another 25 tests for the black rook (just to be sure). Have I included all the tests needed? I think to start with, I'll create some tests manually without any formatted files and see how far I get.
Here is what one of the tests looks like.
It creates an empty board, places the rook in the test location, calls the _listRook function,
and then checks if each of the move objects exist in the list.
I had to create a moveExist tool function to help with this.
This looks through the list of moves and checks each one to see if it matches the one given. There will be other helper functions like this that will look for different move types, like caption, castle, and so on.
I just now need to create all the 50+ tests required to make sure the rook move function is doing what I want it to do. I hope my carpal tunnel syndrome can cope.