# Knook to Mate... With Portals!

Alternatively: Now you're checking with portals!

Inspired this challenge

I am somewhat of a self-declared Chess Anarchist. That means that when I play chess, en passant is forced (else the brick gets used), double check is mate (and pasta), and all sorts of new pieces and squares are added to the game.

One such piece is the Knook (also called an "Empress" or "Chancellor" in fairy chess). It moves like a horsey and a rook combined. Another common addition are portals, like the kinds you see in the Portal series. They behave as you would expect.

Therefore, in this challenge, I'll be give you the position of a white knook, two black kings and an orange and blue portal. You'll give me the square I should move my knook to in order to check both the kings at once and win the game.

## Detailed Explanation of Knooks and Portals

### The Knook

Here is how a knight moves in chess:

Here is how a rook moves in chess:

Therefore, this is how a knook (knight + rook) moves in chess:

In BCPS notation, it's move is EM. In Parlett notation, it's move is n+, ~ 1/2. In Betza notation, it's move is RN.

### Portals

From the Portal Wiki:

Portals in a pair act as a direct link between one another. Anything that goes into one portal comes instantly out the other.

Therefore, when a piece moves into a portal, it comes out the other portal. Portals occupy a single square. There are only ever two portals on a board - one orange and one blue. Pieces cannot land on a portal, as they'd just infinitely teleport between the orange and blue portals. Pieces can also attack through portals (so a piece in a position where another piece could exit a portal would be able to be taken.)

Here's are some examples of how a rook would move through a portal. Note that it always exits the other portal in the direction it entered the first portal. Note that the rook also cannot "jump" over the portal - it has to go through if there is a portal in its way.

Here's how a knight would move through portals. Note that it can either move two squares into a portal and exit one square in a perpendicular direction, or one square into a portal and exit two squares in a perpendicular direction.

Therefore, this is how a knook would move through a portal, obeying laws of both the rook and knight portal movement rules:

## An Example

On the following board, the knook is on square b2, the black kings are on d7 and f6 and the portals are on squares b5 and d2. The winning move is to move the knook through the blue portal to d5, which checks the king on d7 via rook moves and the king on f6 via knight moves.

On the following board, the knook is on square c5, the black kings are on g3 and h4 and the portals are on squares f7 and g4. The winning move is to move the knook to d7, as the knook threatens to take the king on h4 with rook moves after portal travel and threatens to take the king on g3 with knight moves after portal travel.

On the following board, the knook is on square f4. The black kings are on b8 and d3. The portals are on squares f6 and a4. The winning move is to move the knook through the portal on d6 and exit the portal on a4 via a knight move (up 2, right 1). This checks both kings.

## Rules

• The positions will be given in algebraic chess notation (letter then number of the square).
• The winning move will be returned in algebraic chess notation.
• Positions can be given and returned in any reasonable and convienient format, including:
• A list of strings (e.g. ["f4", "b8", "d3", "f6", "a4"])
• A list of list of strings (e.g. [["f", "4"], ["b", "8"], ["d", "3"], ["f", "6"], ["a", "4"]])
• A list of list of numbers that represent the character codes of each string item (e.g. [[102, 52], [98, 56], [100, 51], [102, 54], [97, 52]])
• A list of string, number pairs (e.g. [["f", 4], ["b", 8], ["d", 3], ["f", 6], ["a", 4]])
• Input formats and output formats don't have to match, so long as they are consistent.
• Piece positions can be taken in any order (e.g. [portal 1, portal 2, knook, king 1, king 2] or [knook, king 1, king 2, portal 1, portal 2])
• This doesn't change much, but you can assume that the black kings will never be on the c2 square.
• You may assume that there will always be at least one solution to each input.
• Double check is strictly defined as checking both kings for this challenge. A knook checking a king through a portal and starting in check is counted as a single check only for simplicity.
• It doesn't matter if a king can capture the knook if double check is achieved. All that matters is that both kings are in check at the same time.
• If there is more than one solution, you can output one, or all of the solutions.
• Portal travel might not be required for a winning move. Double check via normal knook movement is just as valid as portal usage.
• This is , so the shortest answer in bytes in each language wins.

## Testcases

Input order is [knook, king 1, king 2, portal 1, portal 2]

Positions -> Winning Square
["b2", "d7", "f6", "b5", "d2"] -> "d5"
["c5", "g3", "h4", "f7", "g4"] -> "d7"
["f4", "b8", "d3", "f6", "a4"] -> "a4"
["h1", "a1", "a3", "c1", "f1"] -> "b1"
["c2", "a8", "h8", "d2", "d6"] -> "d8"
["d2", "c6", "g2", "b2", "g7"] -> "g6"
["d3", "f6", "h6", "d4", "e4"] -> "g4"
["c4", "f7", "h5", "a2", "f5"] -> "b2" // Attacks through the portal
["h5", "a7", "e2", "a4", "g6"] -> "g3" // Attacks a7 through the portal and e2 normally.
["h6", "d4", "g3", "a1", "a8"] -> "f5" // No portal travel needed

• @FryAmTheEggman as stated in the introduction: "double check is mate (and pasta)". This isn't your regular chess game. This is the anarchist's game! Therefore, it doesn't matter if a king can take the knook. Also, it's stated in the rules that there may be more than one solution. Jan 31 at 1:53
• you actually put all the anarchy chess memes into a codegolf challenge what has this world come to Jan 31 at 2:10
• Can the knook choose to not use a portal? For example if it's on f3 and there is a portal on d3 can it move to d2 or c3? Jan 31 at 3:30
• @loopywalt as shown in the last test case, portal travel is not required Jan 31 at 3:58
• @loopywalt if it's a knight move, it can jump over the portal. Rooks however will go through the portal Jan 31 at 4:21

# Python3, 970 bytes:

M=[((1,0),1,3),((0,1),0,2),((-1,0),1,3),((0,-1),0,2)]
def A(c):
q=[(c[0],i,1,[c[0]])for i,*_ in M]+[(c[0],[(i,2),(M[j][0],1)],0,[c[0]])for i,*J in M for j in J]+[(c[0],[(i,1),(M[j][0],2)],0,[c[0]])for i,*J in M for j in J]
while q:
(x,y),m,o,P=q.pop(0)
if o:
X,Y=m
if 0<=x+X<8 and 0<=y+Y<8:
if(T:=(x+X,y+Y))in P:continue
if T in c[1:3]:yield(1,T)
elif T in c[-2:]:q+=[([*{*c[-2:]}-{T}][0],m,o,P+[T])]
else:yield(0,T);q+=[(T,m,o,P+[T])]
else:
[(X,Y),C],*I=m
if 0<=x+X<8 and 0<=y+Y<8:
if(T:=(x+X,y+Y))in P:continue
if C-1==0 and[]==I:yield(T in c[1:3],T)
else:
if T in c[-2:]and C-1:continue
q+=[([T,[*{*c[-2:]}-{T}][0]][T in c[-2:]],[[[(X,Y),C-1]]+I,I][C-1==0],0,P+[T])]
def f(d):
S,*c=[(8-int(b),ord(a)-97)for a,b in d]
q,s=[S],[S]
while q:
S=q.pop(0)
for x,y in A([S]+c):
q+=[y]
if x==0:
k=[[],[]]
for X,Y in A([y]+c):k[X]+=[Y]
if{*k[1]}=={*([1]+c)[1:3]}:return chr(97+y[1])+str(8-y[0])


Try it online!

• I think replacing the continues with 0s and then replacing the next ifs with elifs will save a few bytes. (The TIO link is too long to put in this comment.) Feb 1 at 9:51
• i.e. if(T:=(x+X,y+Y))in P:continue; if T in c[1:3]:yield(1,T) becomes if(T:=(x+X,y+Y))in P:0; elif T in c[1:3]:yield(1,T) and you can do the same for the other one. Feb 1 at 9:52
• "d5", "d2", "d4", "e5", "e6" should be "e4"
– tsh
Feb 2 at 6:56

# JavaScript (Node.js), 367 bytes

(R,J,K,$,_)=>( U=p=>parseInt(p,36), // internal type P=U($),Q=U(_),           // Portal
g=n=>(                   // p^P^Q switch P and Q
M=(p,a,b)=>a?M((p+=a)-P&&p-Q?p:p^P^Q,b):p==n,
// Two movements for knight
h=(p,x)=>
[1,2,-1,-2].some((i,_,o)=>o.some(j=>
i*i-j*j&&M(U(p),i*36,j)|M(U(p),j,i*36)
))|                  // X then Y; Y then X
(e=(w,i=24,q=U(p))=>q-U(x)?
// Maximum 13 moves + w%36 range 8
(q+=w)-P&&q-Q?
w%36<i&&q==n|e(w,i-1,q)
:
e(w,i,q^P^Q)     // Not counting teleport don't hurt
)(36)|e(-36)|e(1)|e(-1):0
)(R)&h(J,K)&h(K,J)&~-n%36<8&
!~[J,K,\$,_].indexOf(N=n.toString(36))?N:g(-~n)
)(360)


Try it online!

Modified to list all possible outputs

[ 'b2', 'd7', 'f6', 'b5', 'd2' ] [ 'b6', 'd5', 'd6' ]
[ 'c5', 'g3', 'h4', 'f7', 'g4' ] [ 'd7', 'f5', 'h5' ]
[ 'f4', 'b8', 'd3', 'f6', 'a4' ] [ 'b4' ]
[ 'h1', 'a1', 'a3', 'c1', 'f1' ] [ 'b1', 'c2' ]
[ 'c2', 'a8', 'h8', 'd2', 'd6' ] [ 'c8', 'd8' ]
[ 'd2', 'c6', 'g2', 'b2', 'g7' ] [ 'a7', 'c2', 'c7', 'e7', 'g6' ]
[ 'd3', 'f6', 'h6', 'd4', 'e4' ] [ 'g4' ]
[ 'c4', 'f7', 'h5', 'a2', 'f5' ] []
[ 'h5', 'a7', 'e2', 'a4', 'g6' ] [ 'g3' ]
[ 'h6', 'd4', 'g3', 'a1', 'a8' ] [ 'f5', 'g4' ]

• "d5", "d2", "d4", "e5", "e6" should be "e4"
– tsh
Feb 2 at 6:56
• @tsh Fast fixed
– l4m2
Feb 2 at 9:11
• seem new issue that die in
– l4m2
Feb 2 at 9:13

# Charcoal, 194 163 bytes

ＵＭθ⍘ι⁴⁰≔Ｅ²⊟θδＦ⁸ＦＥ⁸⁺κ⁺⁴⁰¹×⁴⁰ι¿¬№⁺θδκ«≔⟦⟧ηＦθ«≔⊙⊞ＯΦ⟦δ⮌δ⟧⬤⟦κλ⟧№⟦¹¦²¦⁴⁰¦⁸⁰⟧↔⁻ξ§μπυ№⟦³⁸¦⁴²¦⁷⁹¦⁸¹⟧↔⁻⁻λκ↨μ±¹ζＦ⟦¹¦⁴⁰±¹±⁴⁰⟧«≔κεＦ¹⁵«≧⁺με≧⁺⁼λεζ¿№δε≦⁻Σδε¿‹⁰⌕θε≔⁰μ»»⊞ηζ»¿⌊η⟦⍘κ⁴⁰


Try it online! Link is to verbose version of code. Explanation:

ＵＭθ⍘ι⁴⁰


Inspired by @l4m2's use of base conversion, convert the inputs from "base 40" (chosen to make it easier for me to calculate the various constants).

≔Ｅ²⊟θδ


Split off the portal squares.

Ｆ⁸ＦＥ⁸⁺κ⁺⁴⁰¹×⁴⁰ι¿¬№⁺θδκ«


Loop over each potential square, converted into a "base 40" value, but excluding the input squares.

≔⟦⟧η


Start counting the number of pieces this square attacks.

Ｆθ«


Loop over the knook and the two kings.

≔⊙⊞ＯΦ⟦δ⮌δ⟧⬤⟦κλ⟧№⟦¹¦²¦⁴⁰¦⁸⁰⟧↔⁻ξ§μπυ№⟦³⁸¦⁴²¦⁷⁹¦⁸¹⟧↔⁻⁻λκ↨μ±¹ζ


Check whether the portals are near to the two squares (trying both permutations of squares near to different portals), then also considering the case of a regular knight's move away, see whether the squares are a knight's move away, and if any of the three cases succeeds then mark this square as attackable.

Ｆ⟦¹¦⁴⁰±¹±⁴⁰⟧«


Loop over all possible rook movements.

≔κε


Start at one square.

Ｆ¹⁵«


Repeat 15 times.

≧⁺με


Move one square in the current direction.

≧⁺⁼λεζ


If this is the target square then mark it as attackable.

¿№δε≦⁻Σδε


If it's a portal then jump through it.

¿‹⁰⌕θε≔⁰μ


If it's a king then stop moving.

»»⊞ηζ


Keep count of the number of pieces that were attackable.

»¿⌊η⟦⍘κ⁴⁰


Output the square if all three were attackable, meaning that the knook can move to this square, and from this square can check both kings.