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.

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.