3
$\begingroup$

You are given a Chess960 starting position, but you don't know it is actually the starting position (the knights and maybe other pieces moved around). For which of the Chess960 starting positions you can safely state that you can still castle, i.e. king and at least one rook never moved?

(Example: For the "standard", not, since Nc3,Nf3,Rb1,Rg1 and back ruins all castling rights.)

(Relatively easy, I did it faster in my head than I could write a Python proggie to confirm...)

$\endgroup$

2 Answers 2

1
$\begingroup$

The answer is

220.

I got it by noticing that

the Bishops split the pieces into three components. If a rook or a king is in the same component as a knight, then that rook or king could have already moved, otherwise we call it "untouched". Then, I found the answer using this code below. The answer 220/960 is not a nice fraction and I am curious how the puzzle setter got it easily in their head.


 from itertools import permutations
 pieces = "RRNNBBQK"
 candidates = set(permutations(pieces))

 def valid_960(candidate):
     bishop_left, bishop_right = [file for file, piece in enumerate(candidate) if piece == 'B']
     rook_left, rook_right = [file for file, piece in enumerate(candidate) if piece == 'R']
     king = candidate.index('K')
     return (bishop_right - bishop_left) % 2 == 1 and rook_left < king < rook_right

 starting_960 = list(filter(valid_960, candidates))

 def can_castle(candidate):
     rook_left, rook_right = [file for file, piece in enumerate(candidate) if piece == 'R']
     bishops = [file for file, piece in enumerate(candidate) if piece == 'B']
     knight_left, knight_right = [file for file, piece in enumerate(candidate) if piece == 'N']
     king = candidate.index('K')

     rook_left_untouched, rook_right_untouched, king_untouched = True, True, True

     def check(shift):
         nonlocal i, rook_left_untouched, rook_right_untouched, king_untouched
         while 0 <= i < 8 and i not in bishops:
             if i == rook_left:
                 rook_left_untouched = False
             elif i == rook_right:
                 rook_right_untouched = False
             elif i == king:
                 king_untouched = False
             i += shift

     i = knight_left
     check(-1)
     i = knight_left
     check(1)
     i = knight_right
     check(-1)
     i = knight_right
     check(1)

     return king_untouched and (rook_left_untouched or rook_right_untouched)

 can_castle_list = list(filter(can_castle, starting_960))
 len(can_castle_list)
 

$\endgroup$
4
  • $\begingroup$ Did you consider the case of castling to make castling illegal? (I think this is possible without moving knights?) $\endgroup$
    – tehtmi
    Sep 18, 2023 at 4:21
  • 1
    $\begingroup$ Immediately after castling, it would not be a starting position, because in starting positions, the King has to be between the Rooks. It is then impossible to move back to a starting position, because there's no other way to change the relative order of the rooks and kings without disturbing the pawns. $\endgroup$ Sep 18, 2023 at 7:00
  • $\begingroup$ @BenjaminWang: Exactly. I already considered that. My head calculation was wrong as always, though :-) See my own Python program which shows that it can be done in the head. $\endgroup$ Sep 18, 2023 at 8:09
  • $\begingroup$ Oh cool. Can you post your python program into a Pastebin please? $\endgroup$ Sep 18, 2023 at 8:21
1
$\begingroup$

I don't spoiler my program.

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

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']
#01234567 = kqrrbbnn
perm = [_ for _ in range(8)]
ct = 0
ca = [0]*7
for i in range(40320):
    ki = perm[0]
    qu = perm[1]
    lr = perm[2]
    rr = perm[3]
    lb = perm[4]
    rb = perm[5]
    ln = perm[6]
    rn = perm[7]
    if lr < ki < rr and ln < rn and lb < rb and (lb+rb)%2 == 1:
        ct += 1
        out = ''
        permi = perminv(perm)
        for j in range(8):
            out += ch[permi[j]]
        if ln < rn < lb < rb:
            cas = 1
            can = not (ki < lb)
        elif ln < lb < rn < rb:
            cas = 2
            can = rb < ki
        elif ln < lb < rb < rn:
            cas = 3
            can = lb < ki < rb and not (lr < lb < rb < rr)
        elif lb < ln < rn < rb:
            cas = 4
            can = not (lb < ki < rb)
        elif lb < ln < rb < rn:
            cas = 5
            can = ki < lb
        elif lb < rb < ln < rn:
            cas = 6
            can = not (rb < ki)
        else:
            cas = 0
            can = False
        if can:
            ca[cas] += 1
        if cas == 1 and can and not lb < qu < rb:
            print(ct,out,cas,can)
    perm = nextperm(perm)
print(ca,sum(ca))

Call Benjamin's bishop components L,M,R and the placement of the NN LL...RR. The six cases amount to the following number of positions with castling rights. If you split further into the Q position, you can do it in your head...but need an aspirine afterwards.

60, 16, 24, 44, 16, 60

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.