24
\$\begingroup\$

In chess, fork means to target two pieces with just one piece, and one of the best pieces for forking is the knight.

In this challenge, you will be given three coordinates in a to h and 1 to 8 (like a8 or e7) format. The first and second coordinates are for two other random pieces, and the third is the knight's coordinate. You must return or output the coordinate where the knight can move to create a fork, attacking both pieces. An example is this:

chess

Here, the first and second inputs will be d6 and f6 and the third (knight) will be g3. You must return e4, where the knight can attack both rooks.

Testcases

Input: d6,f6,g3 | Output:e4
Input: d4,d6,e7 | Output:f5
Input: c3,f2,b2 | Output:d1

Notes

  • You may assume it is possible to find a fork with the given input.

This is so the shortest code wins!

\$\endgroup\$
4
  • 4
    \$\begingroup\$ If there was two answers, You can output any of them. Given only two enemy pieces and one knight, I don't think it's possible to have more than one valid answer. \$\endgroup\$
    – Arnauld
    Jan 18 at 10:56
  • 24
    \$\begingroup\$ What is interesting is which piece is the night is actually irrelevant. What this is basically asking is, given 3 knights find the intersection of the points they can reach \$\endgroup\$
    – mousetail
    Jan 18 at 10:58
  • \$\begingroup\$ @Arnauld Yeah maybe i didnt think about it. Just wrote it to prevent users to ask this :) \$\endgroup\$ Jan 18 at 11:01
  • \$\begingroup\$ @Arnauld It wont have more than one valid answer. The answer is some point which have same distance (\$\sqrt 5\$) to each input cell. Or in the other word, the center of the circle determined by the three input points. \$\endgroup\$
    – tsh
    Jan 19 at 5:07

18 Answers 18

16
\$\begingroup\$

Python 2, 129 bytes

def f(a):x,p,y,q,z,r=map(ord,a);x-=z;y-=z;p-=r;q-=r;u=x*x+p*p;v=y*y+q*q;w=x*q-y*p<<1;return chr((u*q-v*p)/w+z)+chr((v*x-u*y)/w+r)

Try it online!

Input as a single string like f("d6f6g3").

For given three points \$\left(x_1,y_1\right)\$, \$\left(x_2,y_2\right)\$, \$\left(x_3,y_3\right)\$, the center of the circle determined by these three points is

$$ \left( \frac{\left|\begin{matrix}x_1^2+y_1^2 & y_1 & 1 \\ x_2^2+y_2^2 & y_2 & 1 \\ x_3^2+y_3^2 & y_3 & 1 \end{matrix}\right|}{2\cdot\left|\begin{matrix}x_1 & y_1 & 1 \\ x_2 & y_2 & 1 \\ x_3 & y_3 & 1 \end{matrix}\right|}, \frac{\left|\begin{matrix}x_1^2+y_1^2 & x_1 & 1 \\ x_2^2+y_2^2 & x_2 & 1 \\ x_3^2+y_3^2 & x_3 & 1 \end{matrix}\right|}{2\cdot\left|\begin{matrix}x_1 & y_1 & 1 \\ x_2 & y_2 & 1 \\ x_3 & y_3 & 1 \end{matrix}\right|} \right) $$

And this formula is find out from this SE post. I'm too lazy to find out the formula by myself.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Impressive. Using math in coding. Never thought math is useful in programming. \$\endgroup\$ Jan 19 at 20:49
  • 7
    \$\begingroup\$ "Never thought math is useful in programming." is the best joke I've read today! \$\endgroup\$
    – Stef
    Jan 21 at 14:45
13
\$\begingroup\$

Vyxal, 50 21 19 bytes

ƛk-:dẊ:RJ$Cv+C;Þf∆M

Try it Online!

One of the programs ever written. Luckily, there's no enpassant with horseys, so there's no bricks needed. However, I will note that this doesn't account for knightboosting. Also doesn't account for knook movements.

Uses the simplification of the problem pointed out by @mousetail in the comments.

Explained

□ƛ # To all squares in the input


k-:dẊ:RJ  # Generate all vector directions of how the horsey moves. This is the hardest part because until recently, not even the smartest scientists knew how the horsey moved.
# This will be a list of [horizontal spaces, vertical spaces]
# [[-1, 2], [2, 1], ...]]

# Generated by:
# Doubling the list [1, -1] (k-:d)
# Getting the cartesian product of those two lists (Ẋ)
# Pushing a second copy and reversing each list in it (R)
# And joining it to the cartesian product (J)

Cv+C # To a list of ordinal points of where the horsey is, add each horsey move

ÞfĊ↑h # Flatten by a layer and get the most common square.

If you can't tell from that, I am somewhat of a chess anarchist :p

\$\endgroup\$
8
  • 6
    \$\begingroup\$ "One of the programs ever written."? \$\endgroup\$ Jan 19 at 13:52
  • 7
    \$\begingroup\$ reading this without knowing any of the context from r/anarchychess would probably be enough to give someone an aneurysm \$\endgroup\$ Jan 19 at 22:48
  • 7
    \$\begingroup\$ @JonathanAllan well of all the programs that have been written, this sure is one of them \$\endgroup\$
    – lyxal
    Jan 19 at 23:15
  • 2
    \$\begingroup\$ @JonathanAllan the application of "if you can't say anything nice, don't say anything at all". If something isn't "one of the greatest/coolest/trickiest programs ever written" but it's certainly something, it's 'one of the programs ever written'. As if you wrote a superlative there but couldn't decide what the right superlative was, so you just left it out. \$\endgroup\$
    – Kaia
    Jan 20 at 1:09
  • 2
    \$\begingroup\$ @InertialIgnorance #morbiussweep (never actually watched it lol) \$\endgroup\$
    – lyxal
    Jan 20 at 1:48
8
\$\begingroup\$

Factor, 86 79 76 67 bytes

[ [ """"zip [ 3 v-n v+ ] with map ] map-flat mode ]

Try it online!

Takes input as a sequence of three strings.

  • [ ... ] map-flat Map over each element in the input, flattening the results.
  • """" Two strings with eight literal control characters each. (You can see them on TIO.)
  • zip Zip them together. These are the knight moves + 3 -- i.e.
{ { 4 5 } { 4 1 } { 5 4 } { 5 2 } { 2 1 } { 2 5 } { 1 2 } { 1 4 } }
  • [ 3 v-n v+ ] with map Add the element we're mapping over to each of the knight moves. For example, if the current element is "d4", this is the result:
{ "e6" "e2" "f5" "f3" "c6" "c2" "b5" "b3" }
  • There will occasionally be results that are outside of the board, but it doesn't matter because these will never be the most frequent move.
  • mode Find the most common move.
\$\endgroup\$
7
\$\begingroup\$

K (ngn/k), 32 bytes

Takes input as a single list of three strings.

`c$*>#'=,/(2-5\28848 84144)+/:\:

Try it online!

Apply all 8 knight moves to each of the pieces, then find the most common target square.

The knight moves are hardcoded using base encoding, the shortest way I found to actually generate them was 5 bytes longer:

+,/|:\',/2 -2,'/:1 -1
\$\endgroup\$
2
  • \$\begingroup\$ Nice answer. How is the input decoding being done? \$\endgroup\$
    – Jonah
    Jan 19 at 1:13
  • \$\begingroup\$ @Jonah there is not much decoding to here really, you can do arithmetic on bytes, which results in integers. In the end the `c$ casts the result back to bytes. \$\endgroup\$
    – ovs
    Jan 19 at 6:22
7
\$\begingroup\$

Python, 96 bytes (@tsh)

f=lambda A,R=1:{5}^{(R//9-ord(f))**2+(R%9-int(r))**2for f,r in A}and f(A,R+1)or f"{R//9:c}{R%9}"

Attempt This Online!

Old Python, 100 bytes

f=lambda A,R=1,F=97:{5}^{(F-ord(f))**2+(R-int(r))**2for f,r in A}and f(A,R%8+1,F+R//8)or f"{F:c}{R}"

Attempt This Online!

Expects a list of three two-character strings. Trusts OP's promise that it is a forkable position (will never return otherwise).

How?

Well, there are only 64 candidate squares so we check them all.

\$\endgroup\$
2
  • \$\begingroup\$ Maybe you can initial F with 1 instead of 97 to save 1 byte. \$\endgroup\$
    – tsh
    Jan 20 at 6:06
  • 1
    \$\begingroup\$ Or 96 bytes: f=lambda A,R=1:{5}^{(R//9-ord(f))**2+(R%9-int(r))**2for f,r in A}and f(A,R+1)or f"{R//9:c}{R%9}" \$\endgroup\$
    – tsh
    Jan 20 at 6:09
6
\$\begingroup\$

Python, 144 bytes

lambda a,b,c:(g(a)&g(b)&g(c)).pop()
g=lambda x:{chr(ord(x[0])+i)+str(int(x[1])+j)for(k,l)in((1,2),(-1,2),(1,-2),(-1,-2))for(i,j)in((k,l),(l,k))}

Attempt This Online!

Performs "en passant" whenever possible. Which is never, since there are no white pawns.

\$\endgroup\$
4
  • 4
    \$\begingroup\$ holy hell. \$\endgroup\$
    – lyxal
    Jan 18 at 12:20
  • \$\begingroup\$ lambda a,b,c:[*g(a)&g(b)&g(c)][0];g=lambda x:{chr(ord(x[0])+i//5)+str(int(x[1])+i%5-2)for i in range(-9,14)if(i//5)**2+(i%5-2)**2==5} \$\endgroup\$
    – tsh
    Jan 19 at 3:50
  • 3
    \$\begingroup\$ En passant is best chess move XD \$\endgroup\$ Jan 19 at 13:20
  • 3
    \$\begingroup\$ for(k I see what you did there ^_^ \$\endgroup\$
    – DLosc
    Jan 19 at 18:48
6
\$\begingroup\$

Excel, 126 122 bytes

Saved 4 bytes by dropping m as a variable.

=LET(a,A1:C3,x,CODE(A1:A3)-96,c,MMULT(MINVERSE(2*IFS(a=0,.5,ISTEXT(a),x,1,a)),x^2+B1:B3^2),CHAR(INDEX(c,1)+96)&INDEX(c,2))

Inspired by tsh's answer although I found a different formula. Note that Excel will change IFS(a=0,.5, to IFS(a=0,0.5, after you enter the formula.

Input is in the range A1:B3 with one half of each coordinate per cell. The range C1:C3 must be left blank. The formula can go anywhere except in the range A1:C3. The first testcase is input like this:

test case

The LET() function allows you to store data as variables and later reference those variables. The terms are in pairs except the last which is the output.

  • a,A1:C3 stores the input range as a 3x3 array.

  • x,CODE(A1:A3)-96 stores the number version of the input letters in a 1x3 array.

    • You could leave off the -96 part here and the +96 part later but doing that matrix math with larger numbers has rounding errors so you may sometimes get answers like e4.00000000000023 and these two offsets are less bytes than trying to round it later.
  • IFS(a=0,.5,ISTEXT(a),x,1,a) converts the input array into a more usable form by:

    • Replacing the blanks in C1:C3 with .5
    • Replace the characters in A1:A3 with their numerical equivalent
    • The end result looks like this:
      Value of m
  • c,MMULT(MINVERSE(2*IFS(~)),x^2+B1:B3^2) does fancy math stuff (that I did not write myself but I did tweak a bit) and it spits out a 1x3 array with the x-coordinate, y-coordinate, and constant from the general equation for a circle. For the first testcase, the value of c looks like this:
    Value of c

  • CHAR(INDEX(c,1)+96)&INDEX(c,2) changes the x-coordinate to a letter and concatenates it with the y-coordinate.


Here are the results for the three testcases:

Results

\$\endgroup\$
3
  • \$\begingroup\$ Assume that A1:C3 is defined as a dynamic array & use A1# :) \$\endgroup\$ Feb 24 at 0:24
  • \$\begingroup\$ @TaylorAlexRaine I like the golfiness of that but, in this case, it would require extra values to be input since I need C1:C3 to be equivalent to zero. Requiring the input to be ={"d",6,0;"f",6,0;"g",3,0} or ={"d",6,"";"f",6,"";"g",3,""} feels like it's too far from the intent of the original question. Arguably, requiring that the formula not be in the range C1:C3 even though it appears unused is somewhat in the same vein, but feels less like a stretch. \$\endgroup\$ Feb 27 at 12:15
  • \$\begingroup\$ Oh I hadn't even recognized that - those assumed zeros are real clever :) \$\endgroup\$ Mar 1 at 0:25
5
\$\begingroup\$

Charcoal, 52 30 bytes

F³⊞υSΦΣEβEχ⁺ιλ⬤υ⁼⁵ΣXEλ⁻℅ν℅§ιξ²

Attempt This Online! Link is to verbose version of code. Explanation:

F³⊞υS

Input the three strings.

ΦΣEβEχ⁺ιλ

Create the 260 strings a0 to z9 and filter on the one that satisfies...

⬤υ⁼⁵ΣXEλ⁻℅ν℅§ιξ²

... the sum of the squared ordinal differences between corresponding code points is equal to 5.

\$\endgroup\$
5
\$\begingroup\$

Jelly, 14 bytes

O+€Ø+pḤUƬẎ¤f/Ọ

A monadic Link that accepts a list of the three distinct, pairs of characters and yields a list of one pair of characters representing the destination square. When run as a full program the destination is printed.

Try it online!

How?

The square on which the knight may fork is the square all three pieces could move to if they were all knights. The code finds those three sets of squares (including off-board ones*) and finds the intersection.

O+€Ø+pḤUƬẎ¤f/Ọ - Link: list of lists of characters, C
O              - cast (C) to ordinals
          ¤    - nilad followed by link(s) as a nilad:
   Ø+          -   [-1, 1]
      Ḥ        -   double -> [-2, 2]
     p         -   cartesian product -> [[1,2],[1,-2],[-1,2],[-1,-2]]
        Ƭ      -   collect while distinct applying:
       U       -     reverse each -> [[[1,2],[1,-2],[-1,2],[-1,-2]],[[2,1],[-2,1],[2,-1],[-2,-1]]]
         Ẏ     -   tighten -> [[1,2],[1,-2],[-1,2],[-1,-2],[2,1],[-2,1],[2,-1],[-2,-1]]
 +€            - add to each ordinal pair (vectorises)
            /  - reduce by:
           f   -   filter keep
             Ọ - cast to characters

* Even though off-board positions may be present in the three sets I believe that this will yield the single destination square if possible or an empty list if not possible. (The three inputs just need to be distinct!)

\$\endgroup\$
5
\$\begingroup\$

Brachylog, 20 bytes

{l;1~ȧᵐ≜p;?ạᵗz+ᵐ~ạ}ᵛ

Try it online!

{                 }ᵛ    Produce the same output from all elements of the input:
 l                      take the element's length (2),
  ;1                    pair it with 1,
    ~ȧᵐ≜                un-absolute-value both,
        p               and permute;
         ;   z+ᵐ        sum with corresponding elements of
           ạᵗ           the character codes of
          ?             the element;
                ~ạ      convert from character codes.
\$\endgroup\$
4
\$\begingroup\$

05AB1E, 16 bytes

Ç®X‚xâDí«δ+çJ˜.M

Inspired by @mousetail's comment!

Try it online or verify all test cases.

Explanation:

Ç         # Convert the (implicit) input-triplet of strings to pairs of their codepoints
®X‚xâDí«  # Push list [[-1,-2],[-1,2],[1,-2],[1,2],[-2,-1],[2,-1],[-2,1],[2,1]]:
®X‚       #  Push pair [-1,1]
   x      #  Double the values in this pair (without popping): [-2,2]
    â     #  Get the cartesian product of the two pairs
     D    #  Duplicate this list
      í   #  Reverse each inner pair
       «  #  Merge the two lists together
δ         # Apply on the two lists double-vectorized:
 +        #  Add them together
ç         # Convert each inner-most integer back to a character with this codepoint
 J        # Join each inner pair together to a string
  ˜       # Flatten the list of lists of strings
   .M     # Pop and leave the most frequent string
          # (which is output implicitly as result)
\$\endgroup\$
4
\$\begingroup\$

Jelly, 11 bytes

⁹p`ạỤ€Ƒ¥ƇOỌ

Try it online!

Sidesteps actually generating knight moves by just checking them with good old brute force.

⁹p`            Generate the Cartesian product of [1 .. 256] with itself.
⁹p`            256 is Jelly's smallest single byte constant >= 108,
         O     the character code of 'h'.
        Ƈ      Filter that list of pairs to the single one for which
   ạ   ¥       the list of its element-wise absolute differences from each of
         O     the input pairs converted to character codes
      Ƒ        is equal to itself with
     €         each difference pair
    Ụ          graded up (converted to a list of indices sorted by their values).
    Ụ Ƒ        Every list of length 2 grades up to either [1, 2] or [2, 1].
          Ọ    Convert the surviving pair from character codes.
\$\endgroup\$
4
\$\begingroup\$

C (GCC), 138 133 131 126 bytes

-12 bytes thanks to @ceilingcat

f(s,x,b,i)char*s,*x;{b=0;for(*x=96;b=i=!b&(++x[1]<58||++*x<105&&(x[1]=48));)for(;i<8;i+=3)b*=abs((*x-s[i-1])*(x[1]-s[i]))==2;}

Attempt This Online!

\$\endgroup\$
0
3
\$\begingroup\$

Ruby, 113 bytes

->s{a=s.bytes
20000.times{|i|(a[1+j=i%3*2]-y=i/3%58)**2+(a[j<1?C=0:j]-x=i/174)**2==5&&C+=1
C>2&&(p x.chr+y.chr)}}

Try it online!

Function takes input as a single string like d6f6g3 and prints output to stdout.

The idea is to find coordinates whose euclidean distance squared from all three inputs is 5. This is counted in C, which is reset every third iteration when j=i%3*2 is zero. A lowercase c (variable) would halt execution because Ruby assumes that it may not be initialized by the time it is needed. Therefore we use an uppercase constant C which executes fine (but generates a warning to stderror every time it is changed.)

Input is converted from characters to ASCII codes and final result is converted back from ASCII codes to characters. As ASCII codes for h8 are 104 and 56, there are nearly 6000 possibilities for the output. For each of these we have to check the 3 inputs so the minimum number of iterations required is a little under 20000. Code is short, but inefficient! If uppercase input is allowed, this can be reduced to just over 12000 iterations.

\$\endgroup\$
3
\$\begingroup\$

Desmos, 126 bytes

L=[-2...2]
P=[(a,b)fora=L,b=L]
A=[p+qforp=l+0P,q=P[P.x^2+P.y^2=5]]
X=A[A.x=i.x]
C=[X[X.y=i.y].lengthfori=A]
f(l)=A[C=C.max][1]

Takes in a list of points, with each coordinate being a charpoint, and returns a point, with each coordinate being a charpoint.

This is just a port of one of the strategies I saw while scrolling through here. It finds all possible positions that can be reached if all three pieces are treated as knights, and find the mode (most common value) of those positions. There is probably a better way to do this (maybe something more mathematical?), but I think this is fine for now.

As a bonus, I included a simple chessboard graphic so y'all can visualize the test cases :D

Try It On Desmos!

Try It On Desmos! - Prettified

\$\endgroup\$
0
3
\$\begingroup\$

JavaScript (Node.js), 77 76 bytes idea from tsh

-1 byte from naffetS

f=(a,i)=>a.some(x=>(parseInt(x,18)-i)**2%323%179^77)?f(a,-~i):i.toString(18)

Try it online!

JavaScript (Node.js), 87 85 bytes

f=(a,i=180)=>a.every(x=>/16|20|35|37/.test(parseInt(x,18)-i))?i.toString(18):f(a,-~i)

Try it online!

Discuss in base 18

18 is only choice

25-29 to only save a $

\$\endgroup\$
4
  • \$\begingroup\$ You can put f=/ in header saving you 2 bytes \$\endgroup\$ Jan 18 at 11:09
  • 1
    \$\begingroup\$ @MehanAlavi no it's recursive \$\endgroup\$
    – l4m2
    Jan 18 at 11:21
  • \$\begingroup\$ 81: f=(a,i=180)=>a.some(x=>(parseInt(x,18)-i)**2%323%70%13-7)?f(a,-~i):i.toString(18) \$\endgroup\$
    – tsh
    Jan 19 at 3:19
  • \$\begingroup\$ != can be ^ \$\endgroup\$
    – naffetS
    Mar 27 at 1:43
3
\$\begingroup\$

Wolfram Language (Mathematica), 182 170 bytes

Saved 12 bytes thanks to comment.

Module[{x,p,y,q,z,r,u,v,w},{x,p,y,q,z,r}=ToCharacterCode@a;x-=z;y-=z;p-=r;q-=r;u=x^2+p^2;v=y^2+q^2;w=(x*q-y*p)*2;FromCharacterCode@{⌊u*q-v* p⌋/w+z,⌊v*x-u*y⌋/w+r}]

Try it online!

A port of @tsh's answer.

Explicit Mathematica code

f[a_String] := Module[{x, p, y, q, z, r, u, v, w, char1, char2},
  {x, p, y, q, z, r} = ToCharacterCode[a];
  x -= z;
  y -= z;
  p -= r;
  q -= r;
  u = x*x + p*p;
  v = y*y + q*q;
  w = BitShiftLeft[x*q - y*p, 1];
  char1 = FromCharacterCode[Quotient[(u*q - v*p), w] + z];
  char2 = FromCharacterCode[Quotient[(v*x - u*y), w] + r];
  StringJoin[char1, char2]
]
\$\endgroup\$
0
0
\$\begingroup\$

Nekomata, 13 bytes

eᵐ{2R↕ᵐᶜ_+}≡H

Attempt This Online!

eᵐ{2R↕ᵐᶜ_+}≡H
e               Char to codepoint
 ᵐ{       }     Map
   2R↕ᵐᶜ_       Any of the 8 knight moves
         +      Add
           ≡    Check if all equal
            H   Char from codepoint

The 2R↕ᵐᶜ_ part is taken from my answer to the challenge Generate All 8 Knight's Moves.

\$\endgroup\$

Your Answer

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

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