17
\$\begingroup\$

Hexagonal chess describes a family of chess variants played on a board where the cells are hexagons instead of the traditional squares. There are many such variants; in this challenge we'll be focusing on Gliński's variant, which is the most common.

The board is composed of three colors (so that the same color doesn't share an edge), with the edges of the hexagons facing the players. The board has 11 files, marked by letters a through l (letter j is not used), and 11 ranks (which bend 60° at file f). Ranks 1 through 6 each contain 11 cells, rank 7 has 9 cells, rank 8 has 7, and so on. Rank 11 contains exactly one cell: f11. (If it helps, think of each rank as making a very wide "V" shape.)

Here is an example picture of the board, with the knight on the center cell. The cells marked with a dot are the legal moves of this particular knight. The knight moves in a similar fashion to "normal" chess, two-down-and-one-over. In hexagonal chess terms, it's an orthogonal move (across an edge), then a diagonal move in the same direction (the closest move to the same color). For example with the knight below, an orthogonal move "up" to the light brown is then accompanied by a diagonal move "up and right" or "up and left" to the nearest light brown.

Gliński's variant knight

From the public domain via https://commons.wikimedia.org/wiki/File:Glinski_Chess_Knight.svg

This knight is positioned at f6 and the legal moves are thus

c4, c5, d3, d7, e3, e8, g3, g8, h3, h7, i4, i5 

Input

A single input giving the starting cell of our knight. This can be as a single string "b6", as two strings, "b", "6", etc., in any convenient format. The input letters can be uppercase or lowercase -- your choice.

Output

A list of the valid moves that a knight on that location can make. This can be as an array of strings, a single string with an unambiguous and consistent delimiter, separate strings by newlines, etc., whatever is most convenient. The output does not necessarily need to be in sorted order, and can be in either uppercase or lowercase -- your choice.

Rules

  • Assume no other pieces are on the board or interfere with the moves. We're focusing on just the knight.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so other people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

b6 a3, c4, d5, d9, e7, e8 f6 c4, c5, d3, d7, e3, e8, g3, g8, h3, h7, i4, i5 f11 d8, e8, g8, h8 i1 f2, f3, g4, h4, l2, k3 
\$\endgroup\$
3
  • 12
    \$\begingroup\$ This coordinate system is the work of the devil. \$\endgroup\$ Commented Apr 11, 2017 at 16:09
  • 2
    \$\begingroup\$ @MartinEnder Points if you do it in Hexagony then :) \$\endgroup\$ Commented Apr 11, 2017 at 16:11
  • \$\begingroup\$ I feel like I could transform this into another vector space by redefining the two axes to the horizontal and the 60 degree diagonal, and then just use regular moves and then translate it back using linear algebra, but I think that's overcomplicating things :P And also I agree that the coordinate system is the most evile thing I have seen around here on this site. :P \$\endgroup\$ Commented Apr 14, 2017 at 21:05

6 Answers 6

11
\$\begingroup\$

JavaScript (ES6), 184 bytes

Takes the file F as a character and the rank R as an integer in currying syntax (F)(R). Returns an array of strings.

F=>R=>[...'100124566542'].map((X,i)=>(X-=3-(x=(s='abcdefghikl').search(F)))-7<(Y=('9641001469'[i]||10)-(A=Math.abs)(x-5)+17-2*R)&X+Y>3&X+16>Y&X+Y<27&&s[X]+(22-Y-A(X-5))/2).filter(n=>n) 

How?

Step #1: convert file/rank to Cartesian coordinates

We convert the hexagonal chess coordinates to Cartesian coordinates (x, y) with x in [0 .. 10] and y in [0 .. 20]:

 00 01 02 03 04 05 06 07 08 09 10 +---------------------------------- 00 | f11 F = file (letter) 01 | e10 g10 R = rank in [1 .. 11] 02 | d09 f10 h09 03 | c08 e09 g09 i08 F | a b c d e f g h i k l 04 | b07 d08 f09 h08 k07 --+----------------------- 05 | a06 c07 e08 g08 i07 l06 x | 0 1 2 3 4 5 6 7 8 9 10 06 | b06 d07 f08 h07 k06 07 | a05 c06 e07 g07 i06 l05 y = 22 - |x - 5| - 2R 08 | b05 d06 f07 h06 k05 09 | a04 c05 e06 g06 i05 l04 10 | b04 d05 f06 h05 k04 11 | a03 c04 e05 g05 i04 l03 12 | b03 d04 f05 h04 k03 13 | a02 c03 e04 g04 i03 l02 14 | b02 d03 f04 h03 k02 15 | a01 c02 e03 g03 i02 l01 16 | b01 d02 f03 h02 k01 17 | c01 e02 g02 i01 18 | d01 f02 h01 19 | e01 g01 20 | f01 

Step #2: apply the move vectors

Below is the list of the move vectors in the Cartesian system:

(-2, +4), (-1, -5), (+3, +1), (-3, +1), (+1, -5), (+2, +4), (-3, -1), (+2, -4), (+1, +5), (-2, -4), (+3, -1), (-1, +5) 

We apply each of them to the source coordinates (x, y) and get a list of target coordinates (X, Y).

Step #3: test the target coordinates

We now need to check which target coordinates are actually located inside the board. This is done by testing X + Y and X - Y:

X/Y

The coordinates are valid if all the following comparisons are true:

  • X + Y > 3
  • X + Y < 27
  • X - Y < 7
  • X - Y > -17

We should also verify that X is in [0 .. 10]. This is not done explicitly because s[X] is undefined if it's not, which eventually results in a falsy value that gets filtered out.

Step #4: convert back to hexagonal chess coordinates

Finally the valid target coordinates are converted back to hexagonal chess coordinates, using the inverse of the formulas described at step #1.

Test cases

let f = F=>R=>[...'100124566542'].map((X,i)=>(X-=3-(x=(s='abcdefghikl').search(F)))-7<(Y=('9641001469'[i]||10)-(A=Math.abs)(x-5)+17-2*R)&X+Y>3&X+16>Y&X+Y<27&&s[X]+(22-Y-A(X-5))/2).filter(n=>n) console.log(JSON.stringify(f('b')(6))) console.log(JSON.stringify(f('f')(6))) console.log(JSON.stringify(f('f')(11))) console.log(JSON.stringify(f('i')(1)))

\$\endgroup\$
1
  • \$\begingroup\$ Ah, that's a really clever way of getting around the hexagonal coordinate system. Nice! \$\endgroup\$ Commented Apr 11, 2017 at 21:21
4
\$\begingroup\$

Batch. 403 bytes

@echo off set j=a b c d e f g h i k l set f=0 for %%f in (%j%)do set/af+=1&if %%f==%1 goto l :l set j=j%j: =% set/a"r=6-f,r*=r>>31,r+=%2 for %%s in ("-3 -2" "-3 -1" "-2 1" "2 -1" "3 1" "3 2")do call:c %%~s exit/b :c call:l %2 %1 :l set/ag=f+%1,s=r+%2,t=g-s if %g% geq 1 if %g% leq 11 if %s% geq 1 if %s% leq 11 if %t% geq -5 if %t% leq 5 set/a"t=6-g,s-=t*=t>>31"&call echo %%j:~%g%,1%%%%s%% 

Adjusts the coordinate system, although in a different way to @Arnauld's answer. The c subroutine takes advantage of the symmetry by trying the mirror reflection of each move. (I also tried rotating but that took too many bytes.)

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

JavaScript (ES6), 184 bytes

(s,t,j=' abcdefghikl',f=j.search(s),r=f<6?t:t+f-6)=>[...'120405..162645'].map((c,i)=>[(i>>1)-3+f,c-3+r]).filter(([f,r])=>f>0&f<12&r>0&r<12&f-r<6&r-f<6).map(([f,r])=>j[f]+(f<6?r:r+6-f)) 

I thought I'd port my Batch solution to ES6 to see how it compared... I didn't expect it to be that close...

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

CJam, 77

1Z2W2Z]_Wf*+2/_Wf%+[r('a-_9>-_6-We>@~+]f.+{_~m5++B,-!},{~1$6-We>-\_8>+'a+\S}/ 

Try it online

Overview:

I'm using a coordinate system that looks like a..f and 1..6 on the left side, extended without bending, with letters replaced with numbers, and changed to be 0-based (b3→[1 2], g1→[6 1], k3→[9 6]). The relative moves in this system are [1 3], [2 -1], [2 3] and their reflections (negative and swapped, e.g. [1 3] → [-1 -3], [3 1], [-3 -1]). A resulting [x y] position is valid iff [x y z] ⊂ [0 1 .. 10] where z=x-y+5.

\$\endgroup\$
2
  • \$\begingroup\$ Interesting. So you translate the input to that coordinate system, perform the calculations, and then translate back? Neat. \$\endgroup\$ Commented Apr 14, 2017 at 20:54
  • \$\begingroup\$ @AdmBorkBork pretty much, yeah \$\endgroup\$ Commented Apr 14, 2017 at 21:04
1
+250
\$\begingroup\$

Dyalog APL, 72 bytes

(6=|×/t,-/t←↑j[a⍳⊂⍞]-j←⊃,/i,¨¨↓∘i¨i-6)/a←⊃,/(11⍴⎕a~'J'),∘⍕¨¨⍳¨5+i⌊⌽i←⍳11 

try

builds a list a of all valid cells: 'A1' 'A2' ... 'L6'

a is used for both input and output

builds a list j of the corresponding coordinates to a in a system where the x axis is along A6-L1 and y along F1-F11

an imaginary third coordinate is the difference of the first two

if the input cell is translated to coords 0 0 0, a knight can move to those cells whose product of coords is 6 or -6

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

Python 3.6, 149

H='abcdefghikl' lambda f,r:[H[i]+str(j)for i,j in[(H.find(f)+p%4*s,int(r)+p//4)for p in[9,6,-1,-5,-11,-10]for s in(1,-1)]if 0<i<11if 0<j<12-abs(6-i)] 

An anonymous function called with two strings for the file and rank; returns a list of strings.

Ungolfed:

def h(f,r): H='abcdefghikl' A = [] for p in[9,6,-1,-5,-11,-10]: for s in(1,-1): i = H.find(f) + p%4*s j = int(r) + p//4 A.append(i, j) B = [] for i,j in A: if 0 < i < 11 and 0 < j < 12 - abs(6 - i): B.append(H[i] + str(j)) return B 
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.