341 lines
12 KiB
Lua
341 lines
12 KiB
Lua
-- Write a function which takes a description of a chess position and
|
|
-- returns a list of all legal captures from that position.
|
|
--
|
|
-- The position will be given as a table, containing the keys "turn",
|
|
-- indicating which player it is to move, "board", which will contain
|
|
-- a rank-major grid of pieces (that is, a list of ranks/rows). Each
|
|
-- piece will be indicated by its unicode symbol. The lack of a piece
|
|
-- will be indicated by nil. If the previous move was a pawn moving
|
|
-- two places, the key "en_passant_target" will be set to a table with
|
|
-- "rank" and "file" keys set to the (1-based) rank and file indices
|
|
-- of the square passed over by the pawn.
|
|
--
|
|
-- For example, the starting position would be given as:
|
|
--
|
|
-- {
|
|
-- turn = "white",
|
|
-- board = {
|
|
-- {"♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"},
|
|
-- {"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"},
|
|
-- {nil, nil, nil, nil, nil, nil, nil, nil},
|
|
-- {nil, nil, nil, nil, nil, nil, nil, nil},
|
|
-- {nil, nil, nil, nil, nil, nil, nil, nil},
|
|
-- {nil, nil, nil, nil, nil, nil, nil, nil},
|
|
-- {"♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎"},
|
|
-- {"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"},
|
|
-- },
|
|
-- }
|
|
--
|
|
-- Moves should be returned in figurine algebraic notation, without
|
|
-- indicators for en passant, check or checkmate (i.e. no "e.p.", "+"
|
|
-- or "#"). For example, "♞xc6" for a black night capturing on c6 and
|
|
-- "exd7" for an e-file pawn capturing on d7. For the sake of
|
|
-- simplicity, there's no requirement to disambiguate between two
|
|
-- pieces of the same type when the notation for the capture would
|
|
-- otherwise be the same (e.g. if two rooks can capture on the same
|
|
-- square). However, there should be duplicate entries in the results
|
|
-- list for each.
|
|
--
|
|
-- Solution --------------------------------------------------------------------
|
|
function legal_captures(position)
|
|
-- Your implementation here
|
|
end
|
|
|
|
-- Tests -----------------------------------------------------------------------
|
|
|
|
local luaunit = require("luaunit.luaunit")
|
|
|
|
function test_starting_position()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{"♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"},
|
|
{"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎", "♟︎"},
|
|
{"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"},
|
|
},
|
|
}
|
|
local expected = {}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_queens_gambit()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{"♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"},
|
|
{"♙", "♙", nil, nil, "♙", "♙", "♙", "♙"},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♙", "♙", nil, nil, nil, nil},
|
|
{nil, nil, nil, "♟︎", nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♟︎", "♟︎", "♟︎", nil, "♟︎", "♟︎", "♟︎", "♟︎"},
|
|
{"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"},
|
|
},
|
|
}
|
|
local expected = {"dxc4"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_scandinavian_defense()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{"♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"},
|
|
{"♙", "♙", "♙", "♙", nil, "♙", "♙", "♙"},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, "♙", nil, nil, nil},
|
|
{nil, nil, nil, "♟︎", nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♟︎", "♟︎", "♟︎", nil, "♟︎", "♟︎", "♟︎", "♟︎"},
|
|
{"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"},
|
|
},
|
|
}
|
|
local expected = {"exd5"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_knight_captures()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"},
|
|
{"♙", "♙", "♙", nil, "♙", "♙", "♙", "♙"},
|
|
{"♙", "♙", nil, nil, nil, "♙", "♙", "♙"},
|
|
{"♙", nil, nil, "♞", nil, nil, "♙", "♙"},
|
|
{"♙", "♙", nil, nil, nil, "♙", "♙", "♙"},
|
|
{"♙", "♙", "♙", nil, "♙", "♙", "♙", "♙"},
|
|
{"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"},
|
|
{"♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"},
|
|
},
|
|
}
|
|
local expected = {
|
|
"♞xb3", "♞xb5", "♞xc2", "♞xc6", "♞xe2", "♞xe6", "♞xf3", "♞xf5",
|
|
}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_knight_not_blocked()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♟︎", "♟︎", "♟︎", nil, nil},
|
|
{nil, nil, nil, nil, "♟︎", nil, nil, nil},
|
|
{nil, nil, "♟︎", "♟︎", "♘", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {"♘xd3", "♘xf3"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_bishop_captures()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♙", nil, nil, nil, nil, nil, "♙", nil},
|
|
{nil, nil, nil, "♙", nil, nil, "♙", nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♙", "♝", nil, nil, nil, "♙"},
|
|
{nil, nil, nil, nil, "♙", nil, nil, nil},
|
|
{nil, "♙", nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♙", nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {"♝xa2", "♝xb7", "♝xe6", "♝xg2"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_bishop_blocked()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, "♙", nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♞", nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, "♝", nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_rook_captures()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♟︎", nil, nil, nil, nil, nil, "♟︎", nil},
|
|
{nil, nil, nil, "♟︎", nil, nil, "♟︎", nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♟︎", "♖", nil, nil, nil, "♟︎"},
|
|
{nil, nil, nil, nil, "♟︎", nil, nil, nil},
|
|
{nil, "♟︎", nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♟︎", nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {"♖xc5", "♖xd3", "♖xd8", "♖xh5"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_rook_blocked()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, "♖", "♙", nil, nil, nil, "♟︎", nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_queen_captures()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{nil, "♙", "♙", "♙", "♙", "♙", nil, "♙"},
|
|
{"♙", "♙", "♙", nil, "♙", "♙", "♙", "♙"},
|
|
{"♙", "♙", nil, nil, nil, "♙", "♙", "♙"},
|
|
{"♙", nil, nil, "♛", nil, nil, "♙", nil},
|
|
{"♙", "♙", nil, nil, nil, "♙", "♙", "♙"},
|
|
{"♙", "♙", "♙", nil, "♙", "♙", "♙", "♙"},
|
|
{nil, "♙", "♙", "♙", "♙", "♙", nil, "♙"},
|
|
{"♙", "♙", "♙", nil, "♙", "♙", "♙", nil},
|
|
},
|
|
}
|
|
local expected = {
|
|
"♛xa4", "♛xb2", "♛xb6", "♛xd1", "♛xd7", "♛xf2", "♛xf6", "♛xg4",
|
|
}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_queen_blocked()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, "♟︎", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♙", nil, nil, nil, nil, nil},
|
|
{nil, "♕", "♙", nil, nil, nil, "♟︎", nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_king_captures()
|
|
local position = {
|
|
turn = "black",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♙", "♙", "♙", nil, nil, nil},
|
|
{nil, nil, "♙", "♚", "♙", nil, nil, nil},
|
|
{nil, nil, "♙", "♙", "♙", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
}
|
|
local expected = {"♚xc3","♚xc4","♚xc5","♚xd3","♚xd5","♚xe3","♚xe4","♚xe5",}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_en_passant()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♟︎", "♙", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
en_passant_target = {rank = 6, file = 4},
|
|
}
|
|
local expected = {"exd6"}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_cannot_capture_if_leads_to_check()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{nil, nil, nil, nil, "♔", nil, nil, nil},
|
|
{nil, nil, nil, nil, "♗", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, "♟︎", nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, "♜", nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
},
|
|
en_passant_target = {rank = 6, file = 4},
|
|
}
|
|
local expected = {}
|
|
luaunit.assertItemsEquals(legal_captures(position), expected)
|
|
end
|
|
|
|
function test_position_with_lots_of_captures()
|
|
local position = {
|
|
turn = "white",
|
|
board = {
|
|
{"♚", nil, nil, "♔", "♝", nil, nil, "♖"},
|
|
{nil, "♖", "♜", "♕", "♞", "♕", "♘", nil},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{"♗", "♛", "♕", "♝", "♕", "♛", "♕", "♞"},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, "♕", "♝", "♕", "♛", "♕", "♘", "♗"},
|
|
{nil, nil, nil, nil, nil, nil, nil, nil},
|
|
{nil, nil, nil, "♜", "♕", "♛", nil, nil},
|
|
},
|
|
en_passant_target = {rank = 6, file = 4},
|
|
}
|
|
local expected = {
|
|
"♔xe1", "♔xe2", "♔xc2", "♖xh4", "♖xe1",
|
|
"♖xb4", "♖xc2", "♕xf4", "♕xb4", "♕xe1",
|
|
"♕xd4", "♕xe2", "♕xc2", "♕xh4", "♕xd4",
|
|
"♕xe1", "♕xf4", "♕xe2", "♘xh4", "♘xf4",
|
|
"♘xe1", "♗xc6", "♗xc2", "♕xe6", "♕xe2",
|
|
"♕xc6", "♕xc2", "♕xd4", "♕xb4", "♕xc6",
|
|
"♕xc2", "♕xe6", "♕xe2", "♕xf4", "♕xd4",
|
|
"♕xe6", "♕xe2", "♕xh4", "♕xf4", "♕xd8",
|
|
"♕xd4", "♕xb4", "♕xc6", "♕xf8", "♕xf4",
|
|
"♕xb4", "♕xd8", "♕xd4", "♕xe6", "♕xc6",
|
|
"♕xd8", "♕xh4", "♕xd4", "♕xf8", "♕xf4",
|
|
"♕xe6", "♘xf8", "♘xh4", "♘xf4", "♗xf8",
|
|
"♗xf4", "♕xc6", "♕xe6", "♕xf8", "♕xd8",
|
|
}
|
|
local captures = legal_captures(position)
|
|
luaunit.assertItemsEquals(captures, expected)
|
|
end
|
|
|
|
os.exit(luaunit.LuaUnit.run())
|