# Chess 960 and Castling #2

For how many Chess 960 starting position you can play into a position such that the game requires castling?

Again for "standard" chess, this is impossible(§): You must let a bishop out, but then instead of castling, the king can crawl out and swap with the rook this way. For another example, with K and R on f1 and g1 it works - just castle in the starting position.

§ Disclaimer: With retro check tricks like Kg1 Rf1 Pf2 - Ka1 of course it is possible, so assume that the black pieces are absent.

• I'm uncertain about this, but rot13(vf guvf n qhcyvpngr bs dhrfgvba 121794 ba guvf fvgr)? Sep 17, 2023 at 20:05
• @BenjaminWang It is not (SPOILER alert): rot13("Bar jnl gurl qvssre vf gung urer zbivat n cnja vf fbzrgvzrf erdhverq. Pbafvqre n fgnegvat cbfvgvba jvgu ovfubcf ba o1 naq p1 naq gur dhrra'f ebbx naq xvat whfg arkg gb gurz. Lbh pna zbir gur o cnja gb yrg bhg gur p1 ovfubc znxvat ebbz sbe 0-0-0. Gur o1 ovfubc ceriragf fjnccvat xvat naq ebbx jvgubhg pnfgyvat.") Sep 18, 2023 at 1:26
• Ah, but one of the chess960 castling rules state that "all the squares between the king's initial and final squares (including the final square), and all the squares between the castling rook's initial and final squares (including the final square), must be vacant except for the king and castling rook". Perhaps a different idea might work? Sep 18, 2023 at 7:07
• I wasn't aware of 121794. It becomes a duplicate "in spirit" as soon as you prove that if you move a pawn, K and R always can castle artificially by the K crawling out. (And @loopywalt - rook on a1 going to d1 jumps over b1 occupied by wB. Verbotttten!) Sep 18, 2023 at 8:45
• @HaukeReddmann Rook not on a1, rook on d1. Sep 18, 2023 at 8:48

Partial answer as OP appears to believe that moves by pawns can be ruled out.

They can't:

Here white can play 1.b3 2.Bb2 3.0-0-0. The resulting position cannot be reached without castling and white cannot castle without moving a pawn.

Variations of the same principle:

1.e3 2.Bg4 3.Qd1 4.Qf3 5.0-0-0

Here an uncastling white king could get out but still couldn't leapfrog the rook.

All this also works on the king's side:

1.d3 2.Bd2 3.Qe1 4.0-0

Sometimes the queen and the nonblocking bishop can be swapped

1.h3 2.Qh2 3.0-0

Finally, some care is required when counting:

This appears to match the pattern: 1.h3 2.Bh2 3.Bg3 4.Qg1 5.Qh2 6.0-0

But instead 1.Nc3 2.Nb3 3.0-0-0 does not need a pawn to be moved, so this position will presumably already have been counted elsewhere.

• If my prog (see partial answer below) isn't buggy, 438 positions unconditionally allow castling (a KR/KNR/KNNR block covering c1/d1 or f1/g1) so only the rest needs a second check. Sep 19, 2023 at 8:25
• @HaukeReddmann do you count stuff like RKRQNNBB? (White can castle without moving a pawn but has to move the queen.) Sep 19, 2023 at 23:01
• Nope :-) (But luckily I only claimed those 438 positions allow, not that only these 438 allow :-) Stay tuned while I try to cover this case - like I said, fiendish... Sep 20, 2023 at 10:50
• Done, after loads of swearing. Now 71 new positions with moving. Sep 21, 2023 at 12:56
• @HaukeReddmann Perhaps it would be easier to count the complement ;-) Sep 21, 2023 at 20:26

Final result to the question...assuming the code logic is sound AND loopywalt's condition when a pawn move allows castling but no artificial castling (i.e. a Q or B blocking a castling end point and another B not but standing right beside it) is IFF. (Personally, I trust it.)

599

Program output coding.

• If a castling without pawn move is impossible due to a B or Q between R and K or on the castling end points, right switches to False and is also coded by have=need=-9 on that side.
• If the castling gets possible by moving a pawn (a second bishop stands beside the obstructing one, not on an end point), right switches back to True and is also coded by have=need=-7 on that side.
• Otherwise, between K and R only NN stand and right stays True.
• It is clear to see that if K and R move into different directions, castling can't be obstructed for that reason. Stays True, coded by have=need=-8 on that side.
• If they move in the same direction, a careful analysis reveals that castling possibility without pawn move is only dependent on two variables: the distance from K to R's destination ("need") and the number of knights between K and the next "border", i.e. bishop ("have"). If need is bigger than have, can't castle and right switches to False. Otherwise, stays True: Ns move out, Q and maybe noncastling R can be shifted to the "holes" until they don't stand in the way.
• If False, White still can castle after a pawn move and can't castle artificially exactly if a queen stands on the kings destination and a non-blocking bishop beside her. Switch back to True and mark "need" and "have" by negating them.

Please do at least a few spot checks for each case.

# generates lexicographic next permutation
# don't bother to understand code - it works :-)
def nextperm(permo):
n = len(permo)
y = n - 1
while permo[y - 1] > permo[y]:
y -= 1
yy = n - 1
while permo[y - 1] > permo[yy]:
yy -= 1
permn = permo[0:y - 1] + [permo[yy]] + sorted(permo[y - 1:yy] + permo[yy + 1:n])
return permn

# inverts permutation to get piece type from location
def perminv(perm):

num_sqsize = len(perm)
perm_inv = [0 for _ in range(num_sqsize)]
for y in range(num_sqsize):
x = perm[y]
perm_inv[x] = y
return perm_inv

ch = ['K','Q','R','R','B','B','N','N']
perm = [_ for _ in range(8)]
ct = 0
ca = 0
# destination squares
kl = 2
kr = 6
jl = 3
jr = 5
for i in range(0,40320):
# piece locations
ki = perm[0]
qu = perm[1]
lr = perm[2]
rr = perm[3]
lb = perm[4]
rb = perm[5]
ln = perm[6]
rn = perm[7]

# check if valid chess 960 position encoding
if lr < ki < rr and ln < rn and lb < rb and (lb+rb)%2 == 1:

# Can castle without pawn move?
castl = True
castr = True

# if B or Q between R and K, can't castle
if lr < qu < ki or lr < lb < ki or lr < rb < ki:
castl = False
if ki < qu < rr or ki < lb < rr or ki < rb < rr:
castr = False

# if B between K castling destination and K, can't castle
if ki <= kl:
if ki < lb <= jl or ki < rb <= jl:
castl = False
else:
if ki > lb >= kl or ki > rb >= kl:
castl = False
if ki >= kr:
if ki > lb >= jr or ki > rb >= jr:
castr = False
else:
if ki < lb <= kr or ki < rb <= kr:
castr = False

# if not, between R and K only NN can stand.
# Thus, can castle unconditionally if castling makes R and K
# move in different directions. Else, might need N holes.
# Required holes only depend on K position
# Split over movement direction and count NN to next B border
if castr:
if kr > ki and jr >= rr:
if ki < lb < rb:
bo = lb
elif lb < ki < rb:
bo = rb
else:
bo = 8
needr = jr-ki
haver = 0
if ki < ln < bo:
haver += 1
if ki < rn < bo:
haver += 1
if haver < needr:
castr = False
if bo == 7 and qu == 6:
castr = True
haver = -haver
needr = -needr
elif kr <= ki and jr < rr:
if lb < rb < ki:
bo = rb
elif lb < ki < rb:
bo = lb
else:
bo = -1
needr = ki-jr
haver = 0
if bo < ln < ki:
haver += 1
if bo < rn < ki:
haver += 1
if haver < needr:
castr = False
if bo == 4 and qu == 5:
castr = True
haver = -haver
needr = -needr
else:
haver = -8
needr = -8
else:
haver = -9
needr = -9
if rr < lb and lb == 6 and rb == 7 and not (ki < qu < rr):
castr = True
haver = -7
needr = -7
if ki > rb and lb == 4 and rb == 5 and not (ki < qu < rr):
castr = True
haver = -7
needr = -7

if castl:
if kl >= ki and jl > lr:
if ki < lb < rb:
bo = lb
elif lb < ki < rb:
bo = rb
else:
bo = 8
needl = jl-ki
havel = 0
if ki < ln < bo:
havel += 1
if ki < rn < bo:
havel += 1
if havel < needl:
castl = False
if bo == 4 and qu == 3:
castl = True
havel = -havel
needl = -needl
elif kl < ki and jl <= lr:
if lb < rb < ki:
bo = rb
elif lb < ki < rb:
bo = lb
else:
bo = -1
needl = ki-jl
havel = 0
if bo < ln < ki:
havel += 1
if bo < rn < ki:
havel += 1
if havel < needl:
castl = False
if bo == 1 and qu == 2:
castl = True
havel = -havel
needl = -needl
else:
havel = -8
needl = -8
else:
havel = -9
needl = -9
if ki < lb and lb == 3 and rb == 4 and not (lr < qu < ki):
castl = True
havel = -7
needl = -7
if lr > rb and lb == 1 and rb == 2 and not (lr < qu < ki):
castl = True
havel = -7
needl = -7

ct += 1
permi = perminv(perm)
out = ''
for j in range(8):
out += ch[permi[j]]

if castl or castr:
ca += 1
print(ct,out,castl,havel,needl,castr,haver,needr)
perm = nextperm(perm)
print(ca)