8
\$\begingroup\$

The game is played on a 1x8 board with the following setup:

KNR..rnk

White's pieces are on the left, while black's pieces are on the right.

The king (K) can move 1 space in any direction.

The knight (N) can jump 2 spaces in any direction, regardless of bordering pieces.

The rook (R) can move any number of spaces in any direction but cannot move over other pieces.

Pieces can't capture pieces of the same color.

Kings can't ever be on neighboring spaces.

A player wins when they checkmate the opponent

A tie occurs when:

  1. There's only 2 kings left.
  2. There's a stalemate.

See here for a playable version. A 3 fold repetition tie is not required in the implementation.

Rules:

  1. The goal is to implement an interactive 2-player version of 1D Chess using as little code as possible.
  2. The input should be made up of two numbers, START CELL and END CELL.
  3. Output should be in the form wKNR..rnk with the first character (w or b) signifying whose turn it is, the uppercase characters representing white's pieces and lowercase representing black's pieces. Alternatively w♔♘♖..♜♞♚ may be used instead. The dots represent empty spaces.
  4. Incorrect moves should be rejected by asking for new input.
  5. The smallest solution wins.

Clarification: The program should display whose turn it is as well as the current board state using ascii or unicode characters. After receiving correct input it should output updated information. When a tie/checkmate occurs, the program should output the board as per usual but changing the first character to: W if white won, B if black won, and S if they tied. Afterwards the program should either halt or ignore all new input. Moving into check is considered an illegal move.

\$\endgroup\$
7
  • \$\begingroup\$ Isn't this an identical reposting of your previous question that you deleted 2 days ago? \$\endgroup\$ Mar 27 at 3:05
  • \$\begingroup\$ @cairdcoinheringaahing it's similar but I put it into sandbox for a bit to fix it \$\endgroup\$
    – Quadruplay
    Mar 27 at 6:07
  • 1
    \$\begingroup\$ @JonathanAllan you're right, i'll remove it \$\endgroup\$
    – Quadruplay
    Mar 27 at 11:42
  • 2
    \$\begingroup\$ There is no clock running. Turns are discrete, so they constitute an ordered list rather than a dimension. What you have is N copies of a 1-dimensional entity, which is not the same as two dimensions. \$\endgroup\$ Mar 29 at 7:40
  • 1
    \$\begingroup\$ @Arnauld yeah, i'll also edit that in \$\endgroup\$
    – Quadruplay
    Mar 31 at 17:20

3 Answers 3

4
\$\begingroup\$

Python 3, 836 513 bytes

def v(f,s,e):a=1-(f[s]in P[t][1:])+(f[e]in P[t])+any(f[s].upper()==p!='RKN.....NK'[s-e]for p in"R"*(1-r(f,s,e))+"KN");f[s],f[e]=d,f[s];return a<1>c(f,f.index)!=s-e
c=lambda f,i:[(N in f and abs(i(N)-i(K))==2)+(R in f and r(f,i(R),i(K)))for K,N,R,_ in P][~t]
r=lambda f,s,e:{*f[s+1:e]+f[e+1:s]}<={d}
t=1
d,*b='.KNR..rnk'
P="Knrk","kNRK"
R=range(8)
J=''.join
while any(v(b[:],s,e)for s in R for e in R)*6>b.count(d):
    print('bw'[t]+J(b));*n,=b
    if v(n,*map(int,input())):b,t=n,1-t
print("SBW"[~t*c(b,b.index)]+J(b))

Much shorter thanks to Mukundan314, Jonathan Allan, and l4m2. Try it online!

836 byte version matches up a bit more with the un-golfed explanation. The logic is similar to most chess programs. The core is about checking if a move is valid, i.e.:

  • the start and end positions are valid
  • the piece movement is legal
  • the movement does not put yourself in check

Un-golfed functions are as follows:

def v(f, s, e):  # Check if a move is valid
    # Check valid start and end positions
    if t=="w" and (b[s] not in "KNR" or b[e] in "KNR"):  return False
    if t=="b" and (b[s] not in "knr" or b[e] in "knr"):  return False

    # Check correct movement
    if b[s] in "Kk" and abs(s-e) != 1:  return False
    if b[s] in "Nn" and not abs(s-e) == 2: return False
    if b[s] in "Rr" and not r(b, s, e): return False
    
    # Check if move puts own king in check
    f = f.copy()
    f[s], f[e] = '.', f[s]
    if c(f): return False
    
    return True

def c(f):  # Is in check
    if t=="w":
        K = f.index("K")
        if "n" in f and abs(f.index("n")-K) == 2: # black knight can hit king
            return True
        if "r" in f and r(f, f.index("r"), K): # black rook can hit king
            return True
    if t=="b":
        k = f.index("k")
        if "N" in f and abs(f.index("N")-k) == 2: # white knight can hit king
            return True
        if "R" in f and r(f, f.index("R"), k): # white rook can hit king
            return True
    return False

def r(f, s, e): # Rook can move from s to e (i.e. there are no pieces in-between)
    if s < e and f[s+1:e].count(".") == e-s-1:
        return True
    if s > e and f[e+1:s].count(".") == s-e-1:
        return True
    return False

and the while loop just checks:

  • there is any valid move any(v(b, s, e) for s in range(8) for e in range(8))
  • the board doesn't only have kings on it b.count('.')<6
\$\endgroup\$
4
  • 1
    \$\begingroup\$ well so far your answer is the smallest lol \$\endgroup\$
    – Quadruplay
    Mar 27 at 6:29
  • \$\begingroup\$ tio.run/… \$\endgroup\$
    – l4m2
    Mar 27 at 11:01
  • 1
    \$\begingroup\$ 500 \$\endgroup\$ Mar 28 at 4:24
  • \$\begingroup\$ 440 \$\endgroup\$ Mar 31 at 5:15
3
\$\begingroup\$

Charcoal, 254 244 bytes

≔KNR..rnkη≔⁰ζW∧›⁶№η.Φ⪪⭆η⭆η⭆׋№⎇ζβαμ∧№⎇ζβακ⎇⁼R↥κ⬤η∨⁼ξ.›¹×⁻πν⁻λπ⁼∨⁼K↥κ²↔⁻νλη⎇⁼πλ.⎇⁼πνκξ⁸∧⊖↔⁻⌕κK⌕κk⬤⌕Aκ§Kkζ›⬤⌕Aκ§nNζ⁻²↔⁻ξμ⊙⌕Aκ§rRζ⬤κ∨⁼ρ.›¹×⁻ςξ⁻μς«§wbζηD⎚Sθ≔⭆η⎇⁼λI§θ⁰.⎇⁼λI§θ¹§ηI§θ⁰κδ¿№ιδ«≔δη≦¬ζ»»¿⊙⌕Aη§Kkζ∨⊙⌕Aη§nNζ⁼²↔⁻λι⊙⌕Aη§rRζ⬤η∨⁼ν.›¹×⁻ξλ⁻ιξ§bwζsη

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

≔KNR..rnkη≔⁰ζ

Start with the initial position with white to play.

W∧›⁶№η.Φ⪪

While there are at least three pieces on the board, and filtering on...

⭆η⭆η⭆׋№⎇ζβαμ∧№⎇ζβακ

... all pairs of starting square (which must contain a piece of the current player's colour) and ending square (which must not), ...

⎇⁼R↥κ⬤η∨⁼ξ.›¹×⁻πν⁻λπ⁼∨⁼K↥κ²↔⁻νλη

... where the piece's movement is legal, ...

⎇⁼πλ.⎇⁼πνκξ⁸

... generating the resulting positions after those moves, and...

∧⊖↔⁻⌕κK⌕κk⬤⌕Aκ§Kkζ›⬤⌕Aκ§nNζ⁻²↔⁻ξμ⊙⌕Aκ§rRζ⬤κ∨⁼ρ.›¹×⁻ςξ⁻μς«

... excluding those that move into check, is not empty:

§wbζηD⎚

Output the current player and position.

Sθ≔⭆η⎇⁼λI§θ⁰.⎇⁼λI§θ¹§ηI§θ⁰κδ

Input the (0-indexed) move and calculate the resulting position.

¿№ιδ«≔δη≦¬ζ

If this is one of the legal positions then set this as the current position and switch player.

»»¿⊙⌕Aη§Kkζ∨⊙⌕Aη§nNζ⁼²↔⁻λι⊙⌕Aη§rRζ⬤η∨⁼ν.›¹×⁻ξλ⁻ιξ§bwζsη

If the current player is in check then show that the other player won otherwise show that the current position is a tie.

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

JavaScript (ES6), 341 bytes

A full program that uses prompt() for I/O.

for(b=[5,9,C=1,0,0,2,10,6],M=c=>b.map((v,x)=>(h=n=>v&c&&b[X=x+n]%4-c&&v<3>b[k|=b[X]&4,m.push(x+[X]),X]&&h(n+d))(d=~(v>8))|h(d=-d),k=m=[]),g=_=>M(C^3)|k;f=g(P=([x,X])=>b[x]^=b[X]=b[x]),M(C),m=m.filter(a=>/[129]/.test(B=[...b])>g(P(a))|(b=[...B])),q=prompt("SwbBW"[m+m?C:f&&C+2]+b.map(v=>".Rr__Kk__Nn"[v]).join``),m+m;)m.includes(q)&&P(q,C^=3)

Try it online!

Board encoding

The board is stored as an array b[] of 8 entries.

Empty squares are encoded as 0. Pieces are encoded as TTCC nibbles, with:

TT = type  -> 00: rook, 01: king, 10: knight
CC = color -> 01: white, 10: black

which gives:

color type binary decimal
white rook 0001 1
white king 0101 5
white knight 1001 9
black rook 0010 2
black king 0110 6
black knight 1010 10

Some useful properties:

  • The color of the piece is v % 4.
  • Assuming v ≠ 0, a rook can be identified with v < 3.
  • A knight can be identified with v > 8.
  • The presence of a piece other than a king on the board can be detected by applying the regular expression /[129]/ to b.

Functions

The helper function P moves a piece from x to X:

P = ([x, X]) => b[x] ^= b[X] = b[x]

The helper function M generates all pseudo-legal moves for the color c and stores them in the array m[]. It also sets a flag k if one of these moves is the capture of a king (which may only happen when the moves of the opposite side are generated).

M = c =>           // c = color
b.map((v, x) =>    // for each square v at position x in b[]:
  h(d = ~(v > 8))  //   process moves to the left by setting
  |                //   d to -2 for a knight, or -1 otherwise
  h(d = -d),       //   process moves to the right
  k =              //   start with k zero'ish
  m = []           //   start with m[] = empty array
)                  // end of map()

The recursive function h is responsible for generating the moves in a direction d:

h = n =>           // n = signed distance from the source square
v & c &&           // if v is a piece of color c
b[                 // and the value on ...
  X = x + n        //   ... the target square X
] % 4 - c          // is not that of a piece of the same color
                   // (and we're not outside the board)
&&                 // then:
v < 3              //   test if the moving piece is a rook
> b[               //
  k |= b[X] & 4,   //   set k if this is the capture of a king
  m.push(x + [X]), //   push the move in m[] as a 2-character string
  X                //
] &&               // if it's a rook and the target square is empty:
  h(n + d)         //   do a recursive call with n + d

The helper function g tests whether the king of the current side is in check:

g = _ => M(C ^ 3) | k

Main program

Once the definitions of the above helper functions have been redacted, the main program looks like this:

for(                   // loop:
  b = [                //   initialize the board b[] and the color C:
    5, 9, C = 1,       //     white pieces
    0, 0,              //     empty squares
    2, 10, 6           //     black pieces
  ],                   //
  f = g(),             //   set the flag f if the king is in check
  M(C),                //   generate the moves for the current side
  m = m.filter(a =>    //   filter the moves:
    /[129]/.test(      //     keep this move if there's at least one
      B = [...b]       //     piece other than a king on the board
    ) >                //     (save a copy of the board in B[])
    g(P(a)) |          //     and the king is not left in check
    (b = [...B])       //     (restore the board afterwards)
  ),                   //   end of filter()
  q = prompt(          //   print the game state:
    "SwbBW"[           //     the first character is ...
      m + m ?          //       if there's at least one move to play:
        C              //         'b' or 'w'
      :                //       else:
        f &&           //         'S' if f = 0
        C + 2          //         'B' or 'W' otherwise
    ] +                //
    b.map(v =>         //     the next characters are taken
      ".Rr__Kk__Nn"[v] //     from this lookup table
    ).join``           //     and joined together
  ),                   //   end of prompt()
  m + m;               //   stop when there are no more moves to play
)                      //
  m.includes(q)        //   if the move q taken from prompt()
  &&                   //   exists in m[]:
    P(q, C ^= 3)       //     play the move and change the color
\$\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.