Finished, picoEngine?

picoEngineComplet

Today I released version 1.0 of picoEngine.

That’s right! My UCI compatible chess engine is now released as picoEngine version 1.0! You can view the tag on my GitLab. Now you too can download and compile picoEngine for yourself! It comes with a generic 64 bit version that I tested on Ubuntu 18.04 with both Arena and PyChess interfaces. Here’s the information on this release:

Version 1.0

Features:

  • UCI compatible engine!
  • Accepts both FEN and MovePos standard inputs.
  • Up to 8 ply weighted moves.
  • Has an optional random move mode for easy chess players.
  • Fast, even at 8 ply only takes a second on a modern 64 bit machine.
  • Light weight, it only takes 2 MB of ram to run this engine.
  • Small size, the (Linux 64 bit) compiled engine is only 364.2 KB in size.
  • Small source code, the entire source repository is less than 1.3 MB in size.
  • Can output moves and engine evaluation (only displayed by interfaces that support it).

I hope you enjoy it! If the prebuilt doesn’t work, just review the read me for simple compiling instructions, involving just one command. (I like to keep things simple.)

Linux – keep it simple.

Advertisements

picoEngine: Fixing FEN + Moves!

fenplusmoves

Today I was able to finally put the nail in the coffin of the FEN + Moves bug in picoEngine! It felt great to close that long standing issue. You can even check out the commit for all the details, but as usual, I’ll talk about the pertinent part here.

The reason this is important is because many chess programs allow you to set up a position on the board, and then seek the engine’s advice on a next best move. Initially, while meeting the UCI (Universal Chess Interface) standard, I enabled picoEngine to accept either “movepos” ( a move by move insertion from the program to my chess engine ), or “FEN” ( a string of numbers and letters that represents the current board ). What I didn’t realize is that some chess programs did not do what I expected per the UCI guidelines.

The way I understood it by reading the UCI guidelines, was that the controlling chess program (say Arena, in our case) would choose before hand to either send “movepos” with a list of moves to get the board set up, or it would send “FEN” with a string of the board setup for each move. I understood that if you set up the board in an unusual position, it would need to send FEN commands to my engine. That made sense.

What I thought would happen for further moves, however, did not. I thought, since it started as a FEN command game, then every turn, it would send the FEN string of the new board. Some chess programs do this. In the case of many programs, such as Arena, it did something quite unexpected to me. For further moves, it would send the FEN to set the board, then a string of the moves after that setup. So it was doing both movepos and FEN all at the same time!

Knowing that now was an easy fix. Simply read the FEN to get the current position, and if you have follow on moves, then apply the movepos rules on them. What gave me the biggest hiccup, however, was a slight miscalculation on my part. I was feeding the FEN into the engine in such a way that the board came out mirrored! Here was the code I used to fix it:

From this:

	int j = stringBoard.length();	
        for (int i = 0; i < j; i++) {
	if (i < 64){ m_theBoard[63 - i] = stringBoard.at(i); }
	}

To this:

 

        for (int i = 0; i < 8; i++) {
		m_theBoard[i+0] = stringBoard.at(i+56);
		m_theBoard[i+8] = stringBoard.at(i+48);
		m_theBoard[i+16] = stringBoard.at(i+40);
		m_theBoard[i+24] = stringBoard.at(i+32);
		m_theBoard[i+32] = stringBoard.at(i+24);
		m_theBoard[i+40] = stringBoard.at(i+16);
		m_theBoard[i+48] = stringBoard.at(i+8);
		m_theBoard[i+56] = stringBoard.at(i+0);
	}

The picoEngine is really coming along nicely! I think it is playable now, and I’m just about done working on it. It’s still not very bright yet, but it is getting better!

Linux – keep it simple.

Choice by chance, picoEngine?

choiceply2

Today I added another set of options to picoEngine. Since it can now think through up to 8 ply, I needed to give it an option to choose how many ply you want it to think through. The commit is simple enough, which you can check out, but here is the gist of it:

	cout << "option name Ply type combo default 8 var 1 var 2 var 3 var 4 var 5 var 6 var 7 var 8" << endl;
	// End of Options
	cout << "uciok" << endl;
}
                styleRandom = false;
                cout << "Normal Mode." << endl;
            }
    if (std::string::npos != setString.find("1"))
            {
                chosenPly = 1;
                cout << "Ply 1." << endl;
            }

With further blocks for 1 through 8. I could have used case, but this worked well enough. Now just to make it smarter….

Linux – keep it simple.

Think deep, picoEngine!

8Ply

Okay, so I’ve been going on and on about making picoEngine think through multiple ply, and it really has been a challenge. I think this latest commit finally fixed it with the ability to think through up to 8 ply. That might seem like a lot, but the grandmaster level chess player is thinking through 16 ply.

A ply, for those who are wondering, is a move, so 8 ply is 4 complete turns of 8 moves. I’m certainly no grandmaster, but I’ve been beating this thing at 8 ply like it’s nobody’s business, so, despite thinking deep, it is not thinking well.

Either way, be sure to check out the commit, as I completely rewrote the ply thought process today. Here is some highlights with notes:

string makeMoves (string proposedMove, string boardPositions){
	string boardReturned = boardPositions;
	try{
		int first =((proposedMove.at(0) - 'a' + 1) + (((proposedMove.at(1) - '1') * 8) - 1));
		int second =((proposedMove.at(2) - 'a' + 1) + (((proposedMove.at(3) - '1') * 8) - 1));
		boardPositions[second] = boardPositions[first];
		boardPositions[first] = '-';
		boardReturned = boardPositions;
	} catch (...) {
	cout << " Exception " << endl;
	} // End try/catch block
	return boardReturned;
}

The above code allows the engine to use the board and make a move with it.

playBoard = makeMoves(proposedMove, originalBoard);
				currentEval = evaluations.getEval(playBoard);
				cout << " current eval and ply " << currentEval << " " << plyMoves << endl;
				if (whoseTurn) {
					if (currentEval > 9000) {cout << " ply  ends 10000." << endl;
					chosenMove = proposedMove;
					return chosenMove;
					}} else {
						if (currentEval < -9000) {cout << " ply  ends -10000." << endl;
					chosenMove = proposedMove;
					return chosenMove;
					}} 
				if (plyMoves-1 < 1){ 
						cout << " ply  ends 1." << endl;
					if (whoseTurn){
						// White's turn, higher is better.
						if ( currentEval > bestEval ) {
							chosenMove = proposedMove; 
							bestEval = currentEval;
							cout <<"info depth " << plyMoves << " score cp "<< currentEval << " pv " << chosenMove  << endl; //<< " comment " << boardPositions 
							} else if ( currentEval == bestEval && (int)time(0)%2 == 0) {
							chosenMove = proposedMove; 
							bestEval = currentEval;
							cout <<"info depth " << plyMoves << " score cp "<< currentEval << " pv " << chosenMove  << endl; //<< " comment " << boardPositions 
						}
						}

Here we see the general concept. We look at each available move, we determine the evaluation of that board after the move, we check if that is better or worse than what we had previously. With the weighted system, the “best” move wins.

The shortcomings I’ve seen while playing against picoEngine is probably related to poor evaluation criteria. It can only gauge the moves based on two things right now: movement and material. Hopefully I can get it smarter.

I did test it out, and it will checkmate itself if you have it play against itself in Arena. So that is good, it knows *how* to win, even if it is not very good at it.

Linux – keep it simple.

Are you listening to yourself, picoEngine?

firstMove

Last post I was really excited about granting picoEngine permission to make multi-ply moves. However, I came to realize that while it was considering the end result of multiple ply moves, it was still only making the current move based on a single ply decision.

So, in layman’s terms: It would sacrifice a queen for a pawn because of the immediate gain, even though it knows the queen is toast next turn.

Obviously, that’s not going to make a very good chess engine. Not only that, but resources are wasted calculating moves that have no bearing on the current decision. So, I reworked the multi-ply decision tree in my latest commit. Unfortunately, it is currently stuck at a ply of 2 while I sort this out. You are welcome to take a look at the commit while I continue to work on it.

For now, though, it considers the moves this turn, and the opponents move next turn, and then decides on the best coarse of action. However limited that may be.

Linux – keep it simple.

Are you mobile, picoEngine?

firstMove

With so many of my posts being about mobile phones, this title might seem misleading. However, I am not implying that picoEngine is on a mobile phone, but rather that I have added the ability for it to determine the mobility of the pieces on the board.

So far, picoEngine is off to a good start, since it now believes that the best first move you can make is that of e4, or the kings pawn to the fourth rank. This is great because it is taking into account the fact that such a move would allow it to be more active with it’s pieces. With one move it adds multiple options to it’s repertoire of available moves for the next turn. Here’s a look at the code:

	// Mobility evaluation
	string listMoves ="";
	int deltaChange = 0;
	try {
	listMoves = moveEvaluations.available(thatBoard, true, false, false);
		if (listMoves.size() == 0){
			deltaChange -= 10000; } else {
			deltaChange = deltaChange + listMoves.size()/5;
		}
	listMoves = moveEvaluations.available(thatBoard, false, false, false);
		if (listMoves.size() == 0){
			deltaChange += 10000; } else {
			deltaChange = deltaChange - listMoves.size()/5;
		}
	} catch (...) {
			cout << " Exception " << endl;
			} // End try/catch block
			//cout << deltaChange << " Delta " << endl;
	picoEval += deltaChange;

Pretty straight forward. Essentially, it checks both sides to see how many legal moves they are able to make, and adds a point for each white move, and minuses a point for each black move, creating a mobility delta. This delta, positive or negative, is added to the picoEval variable for final consideration. You can always check out the full commit if you’d like.

I wrapped it in a try/catch block to be safe, but I don’t think that I actually need it in this case. I may remove that later. The best part about this is the null move return. E.g., if no moves are returned, then the opponent must be in stalemate or check mate. This is highly desirable, and hopefully will allow picoEngine to choose moves that lead to a win. We’ll have to play it out and see.

Linux – keep it simple.

Multi-ply picoEngine!

output2

Hopefully, the above gif loaded for you. It’s not much to look at, but it is really neat to see the output and evaluation from picoEngine as it calculates through multiple moves before making a decision. At present, it is set to 3 ply, which means, if I play as white, then after making my move, picoEngine will calculate it’s move as black, my potential white move, and then it’s next move as black, or vise versa if we were to change sides.

The commit is not the largest one I’ve ever done, but certainly among the most thought intensive. Again, my goal with the picoEngine is just as the name implies: a small engine. Right now, the executable engine is only 335 kb, and while being loaded in Arena Chess, takes less than 2 MB to run. However, these stats don’t make or break a good engine, they are just in keeping with my lightweight goal.

So far, the only item considered by the engine to weigh in a decision is material. Now I need to work on two main things: pruning and/or a better evaluation system. As it stands, picoEngine is so material driven that it often falls prey to weak tactics, allowing picoEngine to capture something now, only to loose it later or be check mated, etc….

The largest problem right now is that picoEngine doesn’t actually know how to win. It is driven currently to attempt to whittle down the opponent to have no material left, but it doesn’t understand that it really needs to focus on check mates. I am thinking I can kill two birds with one stone though, if I add more evaluation for “mobility” (the ability to move about the board), with zero mobility of the enemy being desirable. This may lead to a stalemate engine though, so I will have to be careful.

Linux – keep it simple.

Single Ply Decisions from picoEngine!

evalsWorking

While this may not seem like a real feat to many, I’m actually really excited about this. For the first time, picoEngine actually made an “informed decision” of what move to make. Granted, it is still making poor decisions, but they are at least no longer random.

Keeping in mind that the only evaluation criteria that I have given the engine is that of material difference, so currently, picoEngine is a hungry hungry hippo, because all it can do is attack any piece that comes within range. The downside to this is it will capture a pawn with it’s queen only to have you take back the queen with the defending pawn. So it is not a very bright engine, yet.

If I want to push it to the next level, there are several things I need to do. Currently, it is only searching 1 ply deep, meaning it checks each available move, and then picks the one move that gains the most points after it’s turn. In an ideal computer setup, you would want it to search multiple ply, as in what will it’s turn yield, and what will the evaluation read after the opponents turn. E.g., will they recapture the queen that you marched down there and stole their pawn with?

The commit is actually in two parts, and you are welcome to check them both out on my GitLab. One of the cool things about the current setup, is it does display the information in standard out, so you can actually see the decision being made first hand. The evaluation looks like this:

2019-02-19 13:40:13.611<–1:Move eval: f6g8 eval -10 places RNBQKBNRPPP–PPP———–Pn——————-pppppppprnbqkb-r
2019-02-19 13:40:13.611<–1:Move eval: f6e4 eval 0 places RNBQKBNRPPP–PPP———–PP—p————n—ppppppprnbqkb-r

Still needs some work, but definitely a step in the right direction!

Linux – keep it simple.

What’s your evaluation, picoEngine?

eval

While certainly nothing fancy, I have added a quick material evaluation to picoEngine. Up till now, I’ve been using picoEngine with random moves on. It is an option that by default is off, but the end user can choose to play against the engine in random move mode, where the next move is chosen at random. By default it will now play in “Normal” mode, which tries to make an educated decision.

Of course, the engine does not have a brain, or any essence of being, and thus cannot really “choose” a move. Thus, by educated decision, I really mean a weighted decision. The simplest of all weights is that of material advantage. In this case, I’m using “deca-pawns”, where each pawn is worth 10 points, the nights 30, the bishops 30, the rook 50, the queen 100, and the king 1000 points, respectively.

I don’t intend for this to be the final say in making the decision for picoEngine. At this time, though, I’m really in a position to work out the details of making a decisive move, but to be able to “choose” the best move, it needs some criteria to choose from. Thus, I put in the smallest and simplest criteria I could think of so I could work on the real part of determining how picoEngine will cycle through the available moves in order to pick one to play.

Other good methods of evaluating the board are:

  • Space – how much area you control.
  • Development – leading or lacking thereof.
  • Mobility – the freedom of movement that your pieces enjoy verses your opponent.
  • Aggression – the ability to attack your opponent.
  • Defense – things like the status of castling, or if your pieces are defended from loss.

And of course, materialism, which is the simplest to implement, as it is basically a count of remaining pieces. The problem with materialism as a goal is that such a machine can be easily tricked with things like a queen sacrifice, but it is a start!

Linux – keep it simple.

Would you like to en passant, picoEngine?

After hours of toil and pain, I realized that I was going about this all wrong, and then in 15 minutes enabled the ability for picoEngine to choose to en passant. It is amazing how far off track I was, and how quickly it could be fixed when I was on the right path.

enpassGood

I was attempting to call a private product of the “Board” class, when I needed to simply make it a public class method that could be called. It’s a bit lengthy, but you can always take a look at my GitLab for the full commit. Here is the important snippet:

if (isPass){
if (i > 23 && i < 32) {
int passedPawn = 8;
if (enPass == ‘a’){ passedPawn = 0; }
else if (enPass == ‘b’){ passedPawn = 1; }
else if (enPass == ‘c’){ passedPawn = 2; }
else if (enPass == ‘d’){ passedPawn = 3; }
else if (enPass == ‘e’){ passedPawn = 4; }
else if (enPass == ‘f’){ passedPawn = 5; }
else if (enPass == ‘g’){ passedPawn = 6; }
else if (enPass == ‘h’){ passedPawn = 7; }
if (passedPawn – colNum == 1) {
theseMoves.push_back(i-7);
}
if (colNum – passedPawn == 1) {
theseMoves.push_back(i-9);
}
}}// End en passant moves

The best part is that picoEngine can now suggest an en passant move, which is an important part of the game of chess.

Linux – keep it simple.