You know how many and which kinds of chess pieces were murdered. Can you come up with any possibility for who killed whom and how?
Background
During the course of a game of chess, there are between 2 and 32 pieces on the board. Call the collection of all pieces on the board (both white and black), without regard to position, the material content of the board.
The game begins with 16 pieces per side, often represented together as KQRRBBNNPPPPPPPPkqrrbbnnpppppppp
. (Capital letters represent white, lowercase letters represent black. The pieces are King, Queen, Rook, Bishop, kNight, and Pawn.)
The challenge
Write a program that receives as input a possible material content of the board, and produces as output a legal sequence of moves that achieves this content at the end of the sequence of moves.
The program need only work for subcollections of the initial 32 pieces (that include the white king K
and the black king k
). In other words, there is no need to consider crazy situations like multiples queens per side. That also means that promotion is not necessary, but it is still allowed.
Input format
You may take input in a format convenient to you. For example, the following formats are acceptable:
- A string like
KQRRBBNPPPPPPPPkqrrbbnpppppp
orQRRBBNPPPPPPPPqrrbbnpppppp
(kings implied).
A list like
['Q', 'R', 'R', 'B', 'B', 'N', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'q', 'r', 'r', 'b', 'b', 'n', 'p', 'p', 'p', 'p', 'p', 'p']
.A tuple of piece counts like \$(1,2,2,1,8,1,2,2,1,6)\$ representing \$(Q,R,B,N,P,q,r,b,n,p)\$ or like \$(1,1,2,2,2,2,1,1,8,6)\$ representing \$(Q,q,R,r,B,b,N,n,P,p)\$.
A dictionary of piece counts like
{'K': 1, 'Q': 1, 'R': 2, 'B': 2, 'N': 1, 'P': 8, 'k': 1, 'q': 1, 'r': 2, 'b': 2, 'n': 1, 'p': 6}
(or without the implied kings).A string like
Nnpp
(or list['N','n','p','p']
, or tuple \$(0,0,0,1,0,0,0,0,1,2)\$, or dictionary) representing which pieces are missing, or in line with the title, have been murdered!
Output format
The output format is also flexible, but it must be parseable by a standard game engine. That means that the following are acceptable formats:
Standard algebraic notation, like
Nf3 e5 Nxe5 Ne7 Nxd7 Nec6 Nxb8 Nxb8
."UCI" long algebraic notation, like
g1f3 e7e5 f3e5 g8e7 e5d7 e7c6 d7b8 c6b8
.
(These sample outputs are solutions to the sample inputs before. These games appear to leave the original pieces in their starting squares, but this is not necessary nor in fact the case here.)
The output can be a string or a list, or it can be output to the screen. There is no need to number your moves, but you may if you want. (However, they must of course alternate between white and black, as well as follow other rules of chess!)
Scoring
This is almost a standard code-golf question, meaning that submissions are scored by the length of the program in bytes.
However, in case not all subcollections are solved correctly (whether intentionally or unintentionally), that does not invalidate a submission. Instead, an additional one byte penalty will be assessed per subcollection of pieces that is not solved correctly.
Note that because white could have 0 or 1 queens; 0, 1, or 2 rooks; and so forth, there are \$2\cdot 3\cdot 3\cdot 3\cdot 9 = 486\$ possible material contents per color, and thus \$486^2 = 236196\$ total possible material content inputs. Thus it is strongly advisable to solve the vast majority of inputs correctly! The following program enumerates the possible inputs, and also produces the various example input formats listed above:
count = 0
for Q in range(2):
for R in range(3):
for B in range(3):
for N in range(3):
for P in range(9):
for q in range(2):
for r in range(3):
for b in range(3):
for n in range(3):
for p in range(9):
s1 = ("K" + "Q" * Q + "R" * R + "B" * B + "N" * N + "P" * P +
"k" + "q" * q + "r" * r + "b" * b + "n" * n + "p" * p)
s2 = ("Q" * Q + "R" * R + "B" * B + "N" * N + "P" * P +
"q" * q + "r" * r + "b" * b + "n" * n + "p" * p)
l1 = [piece for piece in s1]
l2 = [piece for piece in s2]
t1 = (Q, R, B, N, P, q, r, b, n, p)
t2 = (Q, q, R, r, B, b, N, n, P, p)
d1 = {"K": 1, "Q": Q, "R": R, "B": B, "N": N, "P": P,
"k": 1, "q": q, "r": r, "b": b, "n": n, "p": p}
d2 = {"Q": Q, "R": R, "B": B, "N": N, "P": P,
"q": q, "r": r, "b": b, "n": n, "p": p}
murders = ("Q" * (1-Q) + "R" * (2-R) + "B" * (2-B) +
"N" * (2-N) + "P" * (8-P) +
"q" * (1-q) + "r" * (2-r) + "b" * (2-b) +
"n" * (2-n) + "p" * (8-p))
murderl = [piece for piece in murders]
murdert1 = (1-Q, 2-R, 2-B, 2-N, 8-P,
1-q, 2-r, 2-b, 2-n, 8-p)
murdert2 = (1-Q, 1-q, 2-R, 2-r, 2-B, 2-b,
2-N, 2-n, 8-P, 8-p)
murderd = {"Q": 1-Q, "R": 2-R, "B": 2-B, "N": 2-N, "P": 8-P,
"q": 1-q, "r": 2-r, "b": 2-b, "n": 2-n, "p": 8-p}
count += 1
print(count)
Verifier
The following Python3.7+ sample demonstrates how to check that a game achieves a given collection of pieces:
import chess
import chess.pgn
import io
pieces = "KQRBNPkqrbnp"
def piece_key(x):
return pieces.find(x)
def sort_pieces(ps):
return sorted(ps, key=piece_key)
def only_pieces(s):
return filter(lambda x: piece_key(x) >= 0, s)
def final_pieces(moves):
board = chess.Board()
for move in moves:
board.push(move)
return "".join(sort_pieces(only_pieces(str(board))))
def moves_from_pgn_string_parser(s):
pgn = io.StringIO(s)
game = chess.pgn.read_game(pgn)
return game.main_line()
def moves_from_uci_list(l):
return [chess.Move.from_uci(x) for x in l]
def moves_from_uci_string(s):
return moves_from_uci_list(s.split())
print(final_pieces(moves_from_pgn_string_parser(
"1. Nf3 e5 2. Nxe5 Ne7 3. Nxd7 Nec6 4. Nxb8 Nxb8")))
# KQRRBBNPPPPPPPPkqrrbbnpppppp
print(final_pieces(moves_from_uci_list(
["g1f3", "e7e5", "f3e5", "g8e7", "e5d7", "e7c6", "d7b8", "c6b8"])))
# KQRRBBNPPPPPPPPkqrrbbnpppppp
Potential clarifications
Pieces with the same name and color, such as the two white rooks, are indistinguishable. That is, you need not ensure that the a1 rook specifically be killed.
The input format is quite flexible. If you wish to have the black pieces before the white, or the pieces in alphabetical order, you're welcome to.
The output games need not be the simplest or shortest possible in any sense; they must merely be legal. Intricacies like the fifty-move/seventy-five-move rule, draw by threefold/fivefold repetition, and insufficient material may be ignored. Key rules like check, checkmate, and stalemate may not be ignored.
The output game need not terminate with mate. It can just end after an arbitrary move.
You may use chess libraries available in your language or platform.