## Piece square tables

Discussion of chess software programming and technical issues.

Moderators: hgm, Dann Corbit, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
eligolf
Posts: 45
Joined: Sat Nov 14, 2020 11:49 am
Full name: Elias Nilsson

### Piece square tables

I have lately read lot on piece square tables, both here, on Chesswiki and at the internet in general. There seems to be incredibly different opinions and even wether to use them at all. My base questions is, is there a "standard" way peice square tables are used?

Currently I only have tables for the midgame implemented since I don't yet differentiate between game phases.

Code: Select all

``````king_mid = [0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0, -5,  -5, -5,  0, 0,
0, 0, 10, -5,  -5, -5, 10, 0]

queen_mid = [-20, -10, -10, -5, -5, -10, -10, -20,
-10,   0,   0,  0,  0,   0,   0, -10,
-10,   0,   5,  5,  5,   5,   0, -10,
-5,   0,   5,  5,  5,   5,   0,  -5,
-5,   0,   5,  5,  5,   5,   0,  -5,
-10,   5,   5,  5,  5,   5,   0, -10,
-10,   0,   5,  0,  0,   0,   0, -10,
-20, -10, -10,  0,  0, -10, -10, -20]

rook_mid = [10,  10,  10,  10,  10,  10,  10,  10,
10,  10,  10,  10,  10,  10,  10,  10,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,  10,  10,   0,   0,   0,
0,   0,   0,  10,  10,   5,   0,   0]

bishop_mid = [0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,  10,   0,   0,   0,   0,  10,   0,
5,   0,  10,   0,   0,  10,   0,   5,
0,  10,   0,  10,  10,   0,  10,   0,
0,  10,   0,  10,  10,   0,  10,   0,
0,   0, -10,   0,   0, -10,   0,   0]

knight_mid = [-5,  -5, -5, -5, -5, -5,  -5, -5,
-5,   0,  0, 10, 10,  0,   0, -5,
-5,   5, 10, 10, 10, 10,   5, -5,
-5,   5, 10, 15, 15, 10,   5, -5,
-5,   5, 10, 15, 15, 10,   5, -5,
-5,   5, 10, 10, 10, 10,   5, -5,
-5,   0,  0,  5,  5,  0,   0, -5,
-5, -10, -5, -5, -5, -5, -10, -5]

pawn_mid = [ 0,   0,   0,   0,   0,   0,   0,   0,
30,  30,  30,  40,  40,  30,  30,  30,
20,  20,  20,  30,  30,  30,  20,  20,
10,  10,  15,  25,  25,  15,  10,  10,
5,   5,   5,  20,  20,   5,   5,   5,
5,   0,   0,   5,   5,   0,   0,   5,
5,   5,   5, -10, -10,   5,   5,   5,
0,   0,   0,   0,   0,   0,   0,   0]``````
With base values at this for [P, N, B, R, Q, K ....]:

Code: Select all

``piece_value_base_mid_game = [100, 290, 320, 490, 900, 60000, -100, -290, -320, -490, -900, -60000]``
The main idea here is to encourage the engine to develop the pieces to "normal" places and castle. Also to encourage pawn advancement and to keep pawns around the king.

I understand that this is super simplified since I am a decent chess player, but it is the best I have for now without complicating the code a million times.

A last reflection is if I should just skip piece square tables and only use basic values and add different positional things such as bonus for castling, advanced pawns, open files, rook on open files and also punishment for e.g. isolated pawns, doubled pawns,restricted mobility. What approach would you go with?

Keep in mind I am writing this in Python and currently a mid game position takes around 5 seconds to reach 4 plies With normal alpha/beta with move ordering but nothing else fancy such as TTs or prunings.

maksimKorzh
Posts: 525
Joined: Sat Sep 08, 2018 3:37 pm
Location: Ukraine
Full name: Maksim Korzh
Contact:

### Re: Piece square tables

eligolf wrote:
Fri Jan 08, 2021 10:09 am
I have lately read lot on piece square tables, both here, on Chesswiki and at the internet in general. There seems to be incredibly different opinions and even wether to use them at all. My base questions is, is there a "standard" way peice square tables are used?

Currently I only have tables for the midgame implemented since I don't yet differentiate between game phases.

Code: Select all

``````king_mid = [0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0,  0,   0,  0,  0, 0,
0, 0,  0, -5,  -5, -5,  0, 0,
0, 0, 10, -5,  -5, -5, 10, 0]

queen_mid = [-20, -10, -10, -5, -5, -10, -10, -20,
-10,   0,   0,  0,  0,   0,   0, -10,
-10,   0,   5,  5,  5,   5,   0, -10,
-5,   0,   5,  5,  5,   5,   0,  -5,
-5,   0,   5,  5,  5,   5,   0,  -5,
-10,   5,   5,  5,  5,   5,   0, -10,
-10,   0,   5,  0,  0,   0,   0, -10,
-20, -10, -10,  0,  0, -10, -10, -20]

rook_mid = [10,  10,  10,  10,  10,  10,  10,  10,
10,  10,  10,  10,  10,  10,  10,  10,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,  10,  10,   0,   0,   0,
0,   0,   0,  10,  10,   5,   0,   0]

bishop_mid = [0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   0,
0,  10,   0,   0,   0,   0,  10,   0,
5,   0,  10,   0,   0,  10,   0,   5,
0,  10,   0,  10,  10,   0,  10,   0,
0,  10,   0,  10,  10,   0,  10,   0,
0,   0, -10,   0,   0, -10,   0,   0]

knight_mid = [-5,  -5, -5, -5, -5, -5,  -5, -5,
-5,   0,  0, 10, 10,  0,   0, -5,
-5,   5, 10, 10, 10, 10,   5, -5,
-5,   5, 10, 15, 15, 10,   5, -5,
-5,   5, 10, 15, 15, 10,   5, -5,
-5,   5, 10, 10, 10, 10,   5, -5,
-5,   0,  0,  5,  5,  0,   0, -5,
-5, -10, -5, -5, -5, -5, -10, -5]

pawn_mid = [ 0,   0,   0,   0,   0,   0,   0,   0,
30,  30,  30,  40,  40,  30,  30,  30,
20,  20,  20,  30,  30,  30,  20,  20,
10,  10,  15,  25,  25,  15,  10,  10,
5,   5,   5,  20,  20,   5,   5,   5,
5,   0,   0,   5,   5,   0,   0,   5,
5,   5,   5, -10, -10,   5,   5,   5,
0,   0,   0,   0,   0,   0,   0,   0]``````
With base values at this for [P, N, B, R, Q, K ....]:

Code: Select all

``piece_value_base_mid_game = [100, 290, 320, 490, 900, 60000, -100, -290, -320, -490, -900, -60000]``
The main idea here is to encourage the engine to develop the pieces to "normal" places and castle. Also to encourage pawn advancement and to keep pawns around the king.

I understand that this is super simplified since I am a decent chess player, but it is the best I have for now without complicating the code a million times.

A last reflection is if I should just skip piece square tables and only use basic values and add different positional things such as bonus for castling, advanced pawns, open files, rook on open files and also punishment for e.g. isolated pawns, doubled pawns,restricted mobility. What approach would you go with?

Keep in mind I am writing this in Python and currently a mid game position takes around 5 seconds to reach 4 plies With normal alpha/beta with move ordering but nothing else fancy such as TTs or prunings.
This is a question I'm now deeply researching as well.
It seems like you've taken those values "from the head" - I tried so as well)
Despite the fact that engine with these like PST would develop both knights, most likely plays d2d4 and castles
the overall playing strength is around 50-70 Elo worth compared to say simplified eval by Tomash Mchniewski:
https://www.chessprogramming.org/Simpli ... n_Function

I'm not talking about your engine obviously but when I used pretty similar values "taken from the head" based on
"my chess knowledge and understanding" and than played 100 games at ultra bullet time control - the version of
"simplified" eval was always beaten my "from the head" values.

So I just want to emphasize that general considerations and the fact that engine can develop a couple of knights and castle in the opening
doesn't yet mean that it would result strong playing.

Probably the most important thing in material + PST evaluation is the matter of how likely values "support" each other
and how harmoniously they interact with each other. This is so important so that Texel's tuning method is capable to
increase elo by 100 points by simply fine tuning the values.

Another consideration is whether you're about to use material + PST only or planning to add pawn structure eval and king safety in future.
For material evaluation only things like pawn structure and king safety are incorporated into the PST values, for instance
giving bonuses for pawns on f2, g2, b2, c2 encourages engine to keep the pawn shield around castled king and discouraging
it from pushing pawns away from the king. Another example - penalties on c3, f3 for pawns are discouraging engine from
recapturing pieces on c3, f3 with pawn, so that double pawns are avoided. Or rook on the 7th, 8th rank like in your case.

Say if you have double pawn eval or rook eval the bonuses would get separated from PST and migrate to specific
eval terms which would result a more flexible evaluation, however the more eval params you have the more they start relying
on each other, hence lots of tuning is needed to find the best relative values. So thinks like "double pawns" are bad so
I'll give them penalty -20 wouldn't work - you need to calculate the panaly so it correlates with both material and PST values.

In Wukong JS I'm using material + PST + tapered evaluation only and now playing around with Texel's tuning to
normilize the relations between up to 794 params:
(12 pieces opening/endgame + 12 PST (64 square each) opening/endgame + opening/endgame score margins)

And interesting is that Texel's tuning implementation inspired me to try one interesting experiment:
1. calculating mean square error
3. recalculating mean square error

If error is minimized I keep the updates, otherwise changing further more.
It doesn't result in stronger play but at very least prevents much weaker play.
Not sure if this is the right way to go though, but at very least it helps to obtain
the initial material/PST values to tune later on.

If you don't know how to calculate mean square error from set of training positions
this video I've made yesterday might be helpful (see timestamps in the description):
JavaScript chess engine with UCI support, own GUI and public API:
https://github.com/maksimKorzh/wukongJS

eligolf
Posts: 45
Joined: Sat Nov 14, 2020 11:49 am
Full name: Elias Nilsson

### Re: Piece square tables

Good answer, and it also seems very complicated to tune all parameters in the head or just by guessing. I assume I will use the simplified evaluation to start from (which also seems to be taken sort of from the head) and see how far that goes. And maybe add "positionally unrelated" things such as mobility or center/king attacks.

You are right about the development thing. Maybe there are better ways to make it develop faster since those values are getting outdated as the game progresses. Really complicated subject and hard to get right...

The goal is just to get something that is playing equally good/slightly better than me. I have no interest in getting a super engine since I find those boring to play against

hgm
Posts: 25520
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

### Re: Piece square tables

Some things just cannot be controlled by PST very well. E.g. to maintain a Pawn shield in front of your King you would have to discourage advancement of almost all Pawns, even of those were the King will never be. Or when the King has already left for the center in the end-game.

maksimKorzh
Posts: 525
Joined: Sat Sep 08, 2018 3:37 pm
Location: Ukraine
Full name: Maksim Korzh
Contact:

### Re: Piece square tables

eligolf wrote:
Fri Jan 08, 2021 1:22 pm
Good answer, and it also seems very complicated to tune all parameters in the head or just by guessing. I assume I will use the simplified evaluation to start from (which also seems to be taken sort of from the head) and see how far that goes. And maybe add "positionally unrelated" things such as mobility or center/king attacks.

You are right about the development thing. Maybe there are better ways to make it develop faster since those values are getting outdated as the game progresses. Really complicated subject and hard to get right...

The goal is just to get something that is playing equally good/slightly better than me. I have no interest in getting a super engine since I find those boring to play against
re: (which also seems to be taken sort of from the head)
- not exactly, read about the logic behind calculating the values for material/PST: https://www.chessprogramming.org/Simpli ... n_Function

re: And maybe add "positionally unrelated" things such as mobility or center/king attacks.
- not very good idea because of a quote from CPW: "Please note that the values presented here have been designed specifically to compensate for the lack of any other chess knowledge, and not for being supplemented by it."

From my experiments - whatever additional "knowledge" I tried to add to simplified eval it performed worse.

- I wish I could be as smart as you are) NN implementation details are beyond my understanding, well unless
I wait until Ronald Friederich implements his own NNUE and teaches me how to do that as he taught me texel's tuning)

re: The goal is just to get something that is playing equally good/slightly better than me. I have no interest in getting a super engine since I find those boring to play against
- For me the matter of engine beating me is more likely the matter of search rather than evaluation.
I mean even strong engine's handcrafted evals are pretty basic if compared to human's understanding of the position, I mean grandmaster's
positional understanding is just somewhat another level. Without NNUE engines simply trying to develop pieces, castle, create passed pawn,
avoid getting mated due to bare king - they don't have a "plan", so the strength is coming more likely from search. Say you can take top level
engine (alpha-beta, not Leela or similar) and limit it's search to 1 ply depth - you'll be able to beat it quite easily.

Depending on goals behind creating an engine options to consider during development vary significantly.
For instance my goal is didactic - I'm trying to master every single aspect of chess programming at basic level and
try to explain it via videos to wide auditory - kind of like proof of concept implementations of all the modern techniques.
JavaScript chess engine with UCI support, own GUI and public API:
https://github.com/maksimKorzh/wukongJS

lithander
Posts: 7
Joined: Sun Dec 27, 2020 1:40 am
Full name: Thomas Jahn

### Re: Piece square tables

I've recently run a test of 600 games between two versions of my minimal engine that searches (only) 4 plys deep with the "Simplified Eval" Maksim mentioned above and the PSTs from sunfish (https://github.com/thomasahle/sunfish) and even thought the sunfish version doesn't distinguish between mid game and endgame at all it came out ahead in the test!

So for me sunfish tables (wich seem like they are computer generated and not guessed but sadly I found no comments on the details) are both simpler and stronger. Maybe you could give it a try, too? If you do let me know of the results! I'm also still searching for a best compromise regarding strength and simplicity, so your findings would be of great interest to me!
Busy working on my first chess engine! Details on Youtube & Github

maksimKorzh
Posts: 525
Joined: Sat Sep 08, 2018 3:37 pm
Location: Ukraine
Full name: Maksim Korzh
Contact:

### Re: Piece square tables

lithander wrote:
Fri Jan 08, 2021 3:25 pm
I've recently run a test of 600 games between two versions of my minimal engine that searches (only) 4 plys deep with the "Simplified Eval" Maksim mentioned above and the PSTs from sunfish (https://github.com/thomasahle/sunfish) and even thought the sunfish version doesn't distinguish between mid game and endgame at all it came out ahead in the test!

So for me sunfish tables (wich seem like they are computer generated and not guessed but sadly I found no comments on the details) are both simpler and stronger. Maybe you could give it a try, too? If you do let me know of the results! I'm also still searching for a best compromise regarding strength and simplicity, so your findings would be of great interest to me!
At a glance it seems that sunfish's PSTs are auto tuned.
Tapered eval improves eval but it's not a silver bullet.
Poorly tuned tapered eval will always be loosing to well tuned non tapered (with the only game phase)

I'm now applying texel's tuning to simplified eval to see whether it improves or not.
Another idea would be to try my own game data instead of positions from gm2600.pgn
And one lest thing - to obtained endgame values meanwhile simplified eval is used for opening phase
I was recalculating mean square error after manually changing endgame values.
Before that whatever endgame values I used simplified eval + tapered eval was always loosing to pure simplified eval
Now with manual tuning of simplified eval + tapered eval and checking the mean square error every time I did a least
manage keep the tapered version at least as strong as pure simplified eval.

Probably around in a week I hope to come up with eventual results and document them so others could
reproduce steps I made and come up with their own material + PST values from scratch.
JavaScript chess engine with UCI support, own GUI and public API:
https://github.com/maksimKorzh/wukongJS

Harald
Posts: 287
Joined: Thu Mar 09, 2006 12:07 am

### Re: Piece square tables

I have another question or thought in this discussion.
Some people use piece square tables in the evaluation and for move ordering in the search.
May be the piece square tables for evaluation - especially if auto tuned - are not the best tables
to be used for move ordering. What do you think?

maksimKorzh
Posts: 525
Joined: Sat Sep 08, 2018 3:37 pm
Location: Ukraine
Full name: Maksim Korzh
Contact:

### Re: Piece square tables

Harald wrote:
Fri Jan 08, 2021 6:31 pm
I have another question or thought in this discussion.
Some people use piece square tables in the evaluation and for move ordering in the search.
May be the piece square tables for evaluation - especially if auto tuned - are not the best tables
to be used for move ordering. What do you think?
Hi Harald, good to see you joining!

Most likely so.
In most tuned PSTs I've researched e4 and d4 usually have miserable bonuses which looks like strange but the moves e4 and d4 are likely
to be played just like if you have +20 bonuses for those squares. The reason for that is that search finds e4 and d4 moves not due to PST
directly but more likely due to PV. For move ordering on the other hand bonuses like +20 for moves e4, d4, Nf3, Nc3 would be beneficial
to order them first but with tuned knight PST values we have a similar story like with e4 and d4.

I tried using PST for move ordering but it didn't give any significant advantage - in some positions it may strip 2k nodes, but in other
it can slow down the search. I know Rebel was using PST for move ordering, but I guess the way it did is more sophisticated than just a lookup.
History heuristic seems more beneficial because moves that has raised alpha within previous iteration are more likely to produce beta cutoffs than
relative PST values. IMO this is so because score > alpha is more likely to become score >= beta (because it's already within the alpha-beta bounds)
it's more likely to produce a cutoff than PST move ordering because PST move ordering does not even guarantee to improve alpha, not even talking

But without tests all this doesn't mean much.
JavaScript chess engine with UCI support, own GUI and public API:
https://github.com/maksimKorzh/wukongJS