I think the original proposal as well as the answers given so far are missing/reproducing what I'd consider as a main default: The programs are much more complicated thannot in adequacy with the problem would require. We have a specific problemsimplicity, and its specificities should be 'exploited' in a smart way to provide an eleganteven statement, lean solutionof the problem. IMHO As it is "bloatware" to have so many definitions (list of files, ranksformulated, possible moves...) or to try to make a program that can solve problems other than the given one.
The problem literally translatesmost natural answer is just to a simple increment statement within a loop over allthe 8 x 8 squares, and increment a few "one-liner" helper functions to know which counter must be incrementedfor the respective case, for each allowed square:
def amazonCheckmate(king: str, amazon: str, n_rows = 8, n_cols = None):
"""Return"""For given positions of the white king and amazon (moves like queen or
knight), return [c0,c1,c2,c3] where the four componentsc0-c3 count the number of squares
on which the black king would beis checkmate, in check, stalemate resp.or safe.""",
# Convert coordinate stringrespectively, 'a1'when the white king and amazon are at the positions
given by the arguments in usual notation, e.g., 'a1' or 'e4', etc.
Number of columns (files) defaults to number of rows of the board."""
# Convert coordinate string to (col, row) (= file, consideringrank): Consider it
# as a base 20 number (to accommodate for digitsallow 'a', 'b',... =as digits 10, 11,...);
# subtract 10*20 + 1 so that 'a' and '1' correspond to col. and row = 0:
if n_cols == None:
n_cols = n_rows
kc, kr = divmod(int( king , 20)-201, 20) # 'a' = digit 10 => col.0,
ac, ar = divmod(int(amazon, 20)-201, 20)
# '1'cnt = digit[0]*4 1 =># rowcounter 0.
for each of: checkmate, defcheck, forbidden(rstalemate,c): #safe.
Forbidden squares: at distancefor 1r fromin king.
range(n_rows): # row returnor abs(r-kr)"rank"
< 2 and abs(c-kc) < 2
for c defin shieldedrange(r,cn_cols): # iscolumn theor enemy"file"
king between r,c and ar,ac?
if not forbidden(r, c): # i.e.,: itstoo coordinatesclose (rowto &enemy col)king
are between our's and amazon's
# and we seecnt[ the(0 kingif andthreatened(r, amazonc) inelse the2) same+ directioncan_move(r, i.e.,
c) ] += 1
return #cnt
Now we just need the simple if not trivial functions forbidden()
(too close to the enemy king), threatened()
and can_move()
.
If we insert them somewhere before the above loop, they can access the coordinates (kr,kc)
and (ar,rc)
of the white king and amazon as variables defined within their environment:
directional vectors (delta row,def deltaforbidden(r, colc):
are collinear <=>
"""True if (r,c) #is determinantat isdistance zero:<= 1 from white king."""
return (kc-c)*abs(ar-r-kr) ==< (kr-r)*(ac-c)2 and minabs(c,ac-kc) <=< kc2
<= max def can_move(cr,ac c)\:
"""Is there a safe square next andto min(r,arc)?"""
<= kr <= max return any(rnot threatened(rr,arcc)
and not forbidden(rr,cc)
def threatened(r,c): #for isrr squarein range(max(r-1,c0), threatenedmin(r+2, byn_rows))
the amazon?
# <=> row or column is equal [rook move] orfor oncc diagonalin range(bishopmax(c-1,0), move:
min(c+2, n_cols),
# absolute differences of row & col are equal) or we're not more than
# 2 steps away (includes knight moves), and2 notif shieldedrr by== king:
r else 1)) # skip rr,cc = returnr,c
(r==ar or c==ac ordef abs(c-ac)==absthreatened(r-ar, c):
"""Is square (r,c) "threatened"/controlled by the amazon (or (abs(r-arking)?
< 3 and abs(c-ac) < 3)) and not shielded(r,c)
That's the defcase can_moveif (r,c): #is ifat blackdistance is<= at2 r,cfrom the amazon, is
there a safe square next to it?
or on the same returnrow any(notor threatened(rr,cc)column andor notdiagonal forbidden(rras the amazon,cc)
and the white king is not in between the two."""
for rr inreturn range(maxabs(r-1,0ar), min< 3 and abs(r+2,8c-ac) < 3)
or (r==ar or c==ac or
for cc in range(maxabs(c-1,0ac), min==abs(c+2,8r-ar), 2 if) rrand ==not shielded(r else 1),c)
cnt=[0]*4
fordef shielded(r in, range(7c):
for"""Is cthe inenemy rangeking between (7r,c):
and (ar,ac), in diagonal or
ifstraight notline? forbidden(r,c)Equivalently:
the directional vectors
(delta row, delta col) collinear #<=> 0,determinant 1,is 2,zero."""
3 <=> checkmate or check only, stalemate orreturn safe
(kc-c)*(ar-r) == (kr-r)*(ac-c) and \
cnt[ (0 if threatenedmin(r,c,ac) else<= 2)kc +<= can_movemax(r,c,ac) ] += 1
and min(r,ar) <= kr return<= cntmax(r,ar)
That's all that is needed to solve the problem in a simple, self-explaining way.