King safety

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: King safety

Post by mvanthoor »

algerbrex wrote: Fri Nov 12, 2021 2:48 am Any advice from others who have experience with implementing king safety would be appreciated. Otherwise, I'll continue tinkering with things myself, as it seems like I'm close to getting it all to work, based on some games I've seen the dev version of Blunder play.
I haven't implemented mobility or king safety yet, but as a chess player, I can say: don't conflate mobility and attacks on the king. A piece can definitely attack the opposite king zone, and still not be very mobile; such as a rook on h8 which is blocked by its own king on g8. If the other king is well defended, for example by a knight on f3 which defends h2, or has even played h2h3 and has a queen on e3 defending h3, then the "attack" may not bring you much.

It would mean that your engine is going to leave the rook stuck on h8 because it is "attacking".

It would be better to _first_ calculate mobility, and _then_ calculate attacking values and stack that on top of the mobility values.

Remember that in chess, an attack comes from a superior position. It is not the other way around: an attack does _not_ necessarily give you a superior position. A superior position comes from:

- Having your king safe
- Being more mobile
- Have the king of the opponent in the open
- Attack the king

So that is the order in which you have to calculate the values.

Don't conflate any of them. Your safety value is not less because the king's zone is attacked; your opponent just gets more attacking points. That may make your king less safe, but it does not lower your king safety value.

Let's say you are being shot at by a single person with one gun. You are behind a wall which can't be penetrated by the gun. You are therefore safe. Now your opponent whips out a cannon that could demolish the wall. Your safety value is still exactly the same, but your opponent's attacking points became much more; so you are now less safe. Not because your position became less safe, but because the opponent has more attacking power.

So you calculate:

- king safety (pawn shield, open lines or not, own pieces near king)
- your own mobility value
- your own attacking value

Then you add all of them for each side. If you subtract your opponent's total from yours and you are still in the positive, your position is superior, and therefore there will be tactical attacking chances. (Assuming your calculations are half-way decent, and the positive value is large enough.)

There can be more terms involved in calculating the positional value. If your positional value is +125 _after_ you subtract your opponent's value, but your opponent is 1 pawn up, you are still +25; your position is so superior that it compensates for the loss of one pawn.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
jdart
Posts: 4409
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: King safety

Post by jdart »

algerbrex wrote: Fri Nov 12, 2021 5:28 am Also another quick question. I'm considering just adding king safety eval to the middlegame scores for black in white (in the context of tapered eval). Since my understanding is that king safety doesn't matter nearly as much in the endgame, and it wouldn't really be useful considering it there.
That is a standard approach. However, I taper king safety eval by the attacking side's material. So if the attacking side has low material then it is scaled down. That scaling doesn't consider how much material the defending side has.
User avatar
algerbrex
Posts: 608
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: King safety

Post by algerbrex »

mvanthoor wrote: Fri Nov 12, 2021 10:47 am
algerbrex wrote: Fri Nov 12, 2021 2:48 am Any advice from others who have experience with implementing king safety would be appreciated. Otherwise, I'll continue tinkering with things myself, as it seems like I'm close to getting it all to work, based on some games I've seen the dev version of Blunder play.
I haven't implemented mobility or king safety yet, but as a chess player, I can say: don't conflate mobility and attacks on the king. A piece can definitely attack the opposite king zone, and still not be very mobile; such as a rook on h8 which is blocked by its own king on g8. If the other king is well defended, for example by a knight on f3 which defends h2, or has even played h2h3 and has a queen on e3 defending h3, then the "attack" may not bring you much.

It would mean that your engine is going to leave the rook stuck on h8 because it is "attacking".

It would be better to _first_ calculate mobility, and _then_ calculate attacking values and stack that on top of the mobility values.

Remember that in chess, an attack comes from a superior position. It is not the other way around: an attack does _not_ necessarily give you a superior position. A superior position comes from:

- Having your king safe
- Being more mobile
- Have the king of the opponent in the open
- Attack the king

So that is the order in which you have to calculate the values.

Don't conflate any of them. Your safety value is not less because the king's zone is attacked; your opponent just gets more attacking points. That may make your king less safe, but it does not lower your king safety value.

Let's say you are being shot at by a single person with one gun. You are behind a wall which can't be penetrated by the gun. You are therefore safe. Now your opponent whips out a cannon that could demolish the wall. Your safety value is still exactly the same, but your opponent's attacking points became much more; so you are now less safe. Not because your position became less safe, but because the opponent has more attacking power.

So you calculate:

- king safety (pawn shield, open lines or not, own pieces near king)
- your own mobility value
- your own attacking value

Then you add all of them for each side. If you subtract your opponent's total from yours and you are still in the positive, your position is superior, and therefore there will be tactical attacking chances. (Assuming your calculations are half-way decent, and the positive value is large enough.)

There can be more terms involved in calculating the positional value. If your positional value is +125 _after_ you subtract your opponent's value, but your opponent is 1 pawn up, you are still +25; your position is so superior that it compensates for the loss of one pawn.
Thanks for the insight, Marcel. I think I see what you're getting at, but I have two questions.

First, if I have separate values for king safety and king attacking power for each side, would that not drive the engine to just try to huddle up all its pieces around the king, if all other evaluation terms are equal?

Perhaps my understanding is just wrong since I'm still trying to make sure I'm fully groking your answer. The way I'm interpreting your answer is it is that I would need to keep track of two separate values in regards to king safety: my own king's safety and my attacking power against the enemy king. Each side of course tracks these values, and for each side, they're both still calculated using the model I outlined in my original answer.

So if both white and black have equal attacking power, but say white has very good king safety, would this not drive white to try to further up its king safety by building a sturdy (but detrimental) fortress of pieces around its king?

The way I originally accounted for defending pieces is by subtracting attacking points from the opposite color, depending on the type of the piece defending and how many squares. So for example, if black is ganging up on the white king with a queen and a bishop, but white's king zone squares are being defended by its queen, a rook, and a knight, it doesn't look like black's attack is nearly as dangerous. But in a case like this (from a game of mine):

[fen]r1bqr1k1/1ppnpp1p/p2p1npQ/6N1/3PP3/2N5/PPP2PPP/R3KB1R w KQ - 3 10[/fen]


My engine would still recognize that white has a pretty nice attack going, even with the defense of the black knight on f6 and the black rook on e8, for some of the black king zone squares.

Second, how are you defining whether or not a piece attacks or defends the squares around the king zone in your answer? I was thinking about this, and whether it would make sense to count a king zone square as being attacked or defended even if there is a piece of the same color sitting there since you're still putting/relieving pressure on the squares surrounding the king.
Last edited by algerbrex on Fri Nov 12, 2021 3:49 pm, edited 4 times in total.
User avatar
algerbrex
Posts: 608
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: King safety

Post by algerbrex »

jdart wrote: Fri Nov 12, 2021 12:16 pm
algerbrex wrote: Fri Nov 12, 2021 5:28 am Also another quick question. I'm considering just adding king safety eval to the middlegame scores for black in white (in the context of tapered eval). Since my understanding is that king safety doesn't matter nearly as much in the endgame, and it wouldn't really be useful considering it there.
That is a standard approach. However, I taper king safety eval by the attacking side's material. So if the attacking side has low material then it is scaled down. That scaling doesn't consider how much material the defending side has.
Right, I think I've seen that approach mentioned as well. I suppose for now I'll just stick with only considering king safety in the middlegame phase.
User avatar
emadsen
Posts: 441
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: King safety

Post by emadsen »

jdart wrote: Fri Nov 12, 2021 12:16 pm That is a standard approach. However, I taper king safety eval by the attacking side's material. So if the attacking side has low material then it is scaled down. That scaling doesn't consider how much material the defending side has.
Isn't that already handled by tapered eval code? I only evaluate king safety for the middlegame. So the egKingSafety = 0 and tapered eval (not just for king safety, for the entire evaluation) will scale the total king safety score down as pieces are swapped off. This encourages the defending side to exchange pieces to thwart the attack.

As I'm writing my question I realize there's a subtle difference between what you describe and what I do. My king safety is tapered as both sides lose pieces. Yours is tapered if the attacking side loses pieces. Hmm. But I don't think that should matter much*. That just means the defending side has won a minor piece at least. That's usually enough to thwart the attack, unless the king safety difference between sides exceeds 300 centipawns.

* Famous words, often disproved by empirical testing.
Erik Madsen | My C# chess engine: https://www.madchess.net
User avatar
algerbrex
Posts: 608
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: King safety

Post by algerbrex »

emadsen wrote: Fri Nov 12, 2021 5:07 pm Isn't that already handled by tapered eval code? I only evaluate king safety for the middlegame. So the egKingSafety = 0 and tapered eval (not just for king safety, for the entire evaluation) will scale the total king safety score down as pieces are swapped off. This encourages the defending side to exchange pieces to thwart the attack.

As I'm writing my question I realize there's a subtle difference between what you describe and what I do. My king safety is tapered as both sides lose pieces. Yours is tapered if the attacking side loses pieces. Hmm. But I don't think that should matter much*. That just means the defending side has won a minor piece at least. That's usually enough to thwart the attack, unless the king safety difference between sides exceeds 300 centipawns.

* Famous words, often disproved by empirical testing.
That was my reasoning as well, just letting the tapered eval handle king safety and have no extra work. But I suppose since I'm still testing things, I might try Jon's method as well.
User avatar
j.t.
Posts: 268
Joined: Wed Jun 16, 2021 2:08 am
Location: Berlin
Full name: Jost Triller

Re: King safety

Post by j.t. »

You could try king-position-aware-piece-square-tables.

A solution to tables with sparse data for some entries could be to also consider immediate neighbors in the table for gradient calculation / error calculation.
User avatar
algerbrex
Posts: 608
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: King safety

Post by algerbrex »

To begin comparing approaches, I started from the beginning. Here's a game Blunder 7.3.0 (the dev version with king safety) played against Blunder 7.2.0. For this version, I'm using the original method I described in my original post:

[pgn]
[Event "?"]
[Site "?"]
[Date "2021.11.12"]
[Round "?"]
[White "Blunder 7.2.0"]
[Black "Blunder 7.3.0"]
[Result "1-0"]
[ECO "C46"]
[GameDuration "00:03:31"]
[GameEndTime "2021-11-12T14:12:07.229 CST"]
[GameStartTime "2021-11-12T14:08:35.736 CST"]
[Opening "Four knights"]
[PlyCount "141"]
[TimeControl "40/60"]
[Variation "Italian Variation"]

1. e4 {+0.13/12 1.5s} e5 {-0.07/11 1.5s} 2. Nf3 {+0.11/12 1.5s}
Nc6 {-0.16/11 1.5s} 3. Nc3 {+0.04/12 1.5s} Nf6 {-0.04/11 1.5s}
4. Bc4 {+0.18/11 1.5s} Bc5 {-0.12/11 1.5s} 5. O-O {+0.15/10 1.5s}
d6 {-0.08/11 1.5s} 6. d3 {+0.15/11 1.5s} Nd4 {-0.15/11 1.5s}
7. Nxd4 {+0.23/11 1.5s} Bxd4 {-0.10/11 1.5s} 8. Nd5 {+0.14/12 1.5s}
Nxd5 {-0.15/12 1.5s} 9. exd5 {+0.16/12 1.5s} Qh4 {-0.19/12 1.5s}
10. c3 {+0.38/11 1.5s} Bb6 {-0.14/12 1.5s} 11. a4 {+0.39/11 1.5s}
Bg4 {-0.28/10 1.5s} 12. Qd2 {+0.39/10 1.5s} a5 {-0.21/11 1.5s}
13. Bb5+ {+0.26/12 1.5s} Kf8 {-0.25/12 1.5s} 14. h3 {+0.40/11 1.5s}
Bxh3 {+0.03/13 1.5s} 15. gxh3 {-0.25/12 1.5s} Qg3+ {-0.25/14 1.5s}
16. Kh1 {-0.25/16 1.5s} Qxh3+ {-0.25/15 1.5s} 17. Kg1 {-0.25/17 1.5s}
Qg3+ {-0.25/14 1.5s} 18. Kh1 {-0.25/18 1.5s} Qf3+ {-0.25/15 1.5s}
19. Kh2 {+0.54/12 1.5s} c6 {-0.25/14 1.5s} 20. dxc6 {+0.24/14 1.5s}
bxc6 {+0.09/13 1.5s} 21. Bc4 {+0.20/13 1.5s} d5 {0.00/13 1.5s}
22. Bb3 {-0.07/13 1.5s} Bc7 {-0.09/13 1.5s} 23. Qg5 {+0.29/12 1.5s}
e4+ {-0.03/12 1.5s} 24. Kg1 {+0.25/12 1.5s} exd3 {-0.09/12 1.5s}
25. Qg2 {+0.32/12 1.5s} Qf5 {-0.05/11 1.5s} 26. c4 {+0.53/12 1.5s}
Rb8 {0.00/11 1.5s} 27. Ba2 {-0.10/12 1.5s} Be5 {+0.17/10 1.5s}
28. Rb1 {+0.30/11 1.5s} h5 {-0.18/10 1.5s} 29. cxd5 {+0.68/11 1.5s}
Rb4 {-0.28/12 1.5s} 30. f4 {+1.01/12 1.5s} Bd4+ {-0.30/12 1.5s}
31. Kh2 {+1.16/11 1.5s} Rxa4 {-0.47/12 1.5s} 32. b3 {+1.03/13 1.5s}
Rxa2 {-0.83/12 1.5s} 33. Qxa2 {+1.06/12 1.5s} Qg4 {-1.04/11 1.5s}
34. Ba3+ {+1.78/11 1.5s} Kg8 {-1.32/12 1.5s} 35. Qg2 {+1.75/12 1.5s}
cxd5 {-1.48/13 1.5s} 36. Rbd1 {+1.94/13 1.5s} Be3 {-1.59/14 1.5s}
37. Rxd3 {+2.12/14 1.5s} Qh4+ {-1.59/12 1.5s} 38. Qh3 {+2.13/14 1.5s}
Bxf4+ {-2.06/14 1.5s} 39. Kh1 {+2.10/14 1.5s} Qg4 {-1.99/14 1.5s}
40. Rff3 {+2.17/14 1.00s} Rh6 {-2.11/13 1.00s} 41. Rxd5 {+2.12/13 1.5s}
Bc7 {-2.25/13 1.5s} 42. Bc5 {+2.31/12 1.5s} Re6 {-2.27/13 1.5s}
43. Re3 {+2.47/12 1.5s} Bf4 {-2.53/13 1.5s} 44. Qxg4 {+2.65/15 1.5s}
hxg4 {-2.85/17 1.5s} 45. Rxe6 {+2.78/16 1.5s} fxe6 {-2.97/17 1.5s}
46. Rd8+ {+3.03/16 1.5s} Kh7 {-2.97/15 1.5s} 47. Kg2 {+3.07/17 1.5s}
Kg6 {-3.07/14 1.5s} 48. Bb6 {+3.07/15 1.5s} Kf5 {-3.09/14 1.5s}
49. Bxa5 {+3.80/15 1.5s} g6 {-3.84/13 1.5s} 50. b4 {+4.52/14 1.5s}
Bg5 {-4.70/13 1.5s} 51. Rf8+ {+5.08/15 1.5s} Ke5 {-5.02/13 1.5s}
52. b5 {+5.97/15 1.5s} Ke4 {-5.89/14 1.5s} 53. b6 {+9.59/16 1.5s}
Be7 {-9.87/15 1.5s} 54. Re8 {+9.75/15 1.5s} Bg5 {-10.19/15 1.5s}
55. Rxe6+ {+10.21/15 1.5s} Kd5 {-10.45/14 1.5s} 56. Re5+ {+10.30/16 1.5s}
Kxe5 {-10.54/14 1.5s} 57. b7 {+10.30/15 1.5s} Be7 {-10.54/13 1.5s}
58. b8=Q+ {+10.30/13 1.5s} Bd6 {-10.78/14 1.5s} 59. Bc3+ {+10.36/13 1.5s}
Ke6 {-10.87/14 1.5s} 60. Qe8+ {+10.55/14 1.5s} Kd5 {-10.87/13 1.5s}
61. Qd7 {+12.79/15 1.5s} Kc4 {-10.81/13 1.5s} 62. Be1 {+13.28/14 1.5s}
Bc5 {-13.10/12 1.5s} 63. Qc6 {+13.39/13 1.5s} g5 {-13.87/15 1.5s}
64. Bf2 {+13.84/16 1.5s} Kd3 {-14.06/14 1.5s} 65. Qxc5 {+13.84/14 1.5s}
g3 {-14.21/13 1.5s} 66. Kxg3 {+14.01/13 1.5s} g4 {-M10/12 1.5s}
67. Qd4+ {+M9/12 1.5s} Kc2 {-M8/12 1.5s} 68. Qc4+ {+M7/12 1.5s}
Kd2 {-M6/12 1.5s} 69. Qb3 {+M5/12 1.5s} Ke2 {-M4/13 1.5s} 70. Qd5 {+M3/13 1.5s}
Kf1 {-M2/14 1.5s} 71. Qb5# {+M1/13 1.5s, White mates} 1-0
[/pgn]

I can definitely see the king-safety evaluation taking effect as Blunder 7.3.0 immediately jumps to attack the king with 9. Qh4 by putting pressure on the f2 square with the bishop on b6, which is not something it would normally do. However, as far as I can tell, there's really nothing to the attack, since white has an adequate defense with the rook on h2 and the queen nearby as well.

So the problem with the method in my original post seems to be, AFAIK, that Blunder doesn't recognize when the attack it's mounting is futile since its opponent usually has plenty of defense. So the next step will be to play around more with how attackers and defenders are registered to achieve a final point value index for the king safety table.
Last edited by algerbrex on Fri Nov 12, 2021 9:34 pm, edited 1 time in total.
User avatar
algerbrex
Posts: 608
Joined: Sun May 30, 2021 5:03 am
Location: United States
Full name: Christian Dean

Re: King safety

Post by algerbrex »

j.t. wrote: Fri Nov 12, 2021 5:58 pm You could try king-position-aware-piece-square-tables.

A solution to tables with sparse data for some entries could be to also consider immediate neighbors in the table for gradient calculation / error calculation.
Thanks and thanks Jost, those could be things to try. Although I'm still not quite sure how the tuning method you suggested would pan out.
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: King safety

Post by mvanthoor »

algerbrex wrote: Fri Nov 12, 2021 3:41 pm First, if I have separate values for king safety and king attacking power for each side, would that not drive the engine to just try to huddle up all its pieces around the king, if all other evaluation terms are equal?
It depends on how you code it. When you create a mobility function, you also have to watch that the engine doesn't plop the queen in the middle of the board on move 4 because it would be very mobile there. (It's probably one of the reasons why computers without opening books love the Scandinavian. Massive mobility due to the number of squares the queen can go.) You'll have to do something like: no mobility -> 1 square mobility = big bonus. 25 squares mobility -> 27 squares mobility = small bonus (the bonus for an extra square of mobility gets smaller as you have more squares.)

Something will probably be true for the king safety and attacking parameters, to make sure the engine doesn't collect all its pieces around the king, or goes on an all-out attack when it's not safe itself.
So if both white and black have equal attacking power, but say white has very good king safety, would this not drive white to try to further up its king safety by building a sturdy (but detrimental) fortress of pieces around its king?
That was my idea of keeping the variables separate: If your opponent doesn't have a lot of attacking power, your defensive strength doesn't have to be high either. In the end, you can calculate king safety from both defensive and attacking values, but the two values should not be conflated. Your attacking power doesn't diminish because the opponent's defenses get better. You will have to raise your attacking power further.

The entire trick is trying to find out how, and when. It is a problem for every chess player. If you attack, and your attacking power isn't large enough compared to the opponent's defenses, the attack fizzles out; and you're probably not fast enough to retreat to guard your own king. This is called "overextending" in chess. (And in go as well: when you try to grab so much territory that you can't actually hold it, and your opponent builds a territory within your territory. That is also called overextending.)

It's a balancing act, at which I'm... less good in chess (and go) than I'd like, to be honest.
Second, how are you defining whether or not a piece attacks or defends the squares around the king zone in your answer? I was thinking about this, and whether it would make sense to count a king zone square as being attacked or defended even if there is a piece of the same color sitting there since you're still putting/relieving pressure on the squares surrounding the king.
My idea is to:
- first look for the pawn shield.
- if the middle pawn (g2 or g7) has been moved up, is there a bishop for g2 or g7? if not, those squares are weak. (As in your example.) Big penalty. Never fianchetto the bishop and then trade it. (Not in the early/middle game, anyways.)
- Is the pawn shield complete? If not, penalty. If f2/f7 is missing, move the king to h1/h8. Then you get a penalty for missing f2/f7, but bonus for the king being on h1/h8.
- Bonus if the pawn shield is covered by anything else but the king
- Bonus if the squares before the pawn shield are covered.

Basically, the largest part of the king safety is the pawn shield and how well it's covered.

But the balancing act means that you can throw away the entire pawn shield an use it for a storm / attack if your opponent's attacking power is not high.

This king saftey thing is going to be fun to program, but it needs lots of testing to see what works for your engine or not.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL