Compare commits
8 Commits
873ab82b19
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ed15159576 | |||
| 0ec0d19e65 | |||
| fa33a7bdf7 | |||
| 2317033e75 | |||
| 45c27ba067 | |||
| 5f57627225 | |||
| ec9d9b2a38 | |||
| 126064340b |
64
14_vigenere.lua
Normal file
64
14_vigenere.lua
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
-- The Vigenère cipher is a way to encrypt text, where a key is
|
||||||
|
-- repeated for the length of the plaintext and the alphabetical
|
||||||
|
-- position of the keyword letter determines the amount the letter of
|
||||||
|
-- the plaintext is shifted by. For example, for plaintext "FOO" and
|
||||||
|
-- key "BAR", the first letter of the cipher text would be G, the
|
||||||
|
-- result of shifting the letter F (first letter of the plaintext)
|
||||||
|
-- over by 1 (the zero-based alphabetical position of B, first letter
|
||||||
|
-- of the key).
|
||||||
|
--
|
||||||
|
-- Implement a function to encode a message with a given keyword. The
|
||||||
|
-- message should be converted to upper-case and any non-alphabetical
|
||||||
|
-- characters should be discarded.
|
||||||
|
--
|
||||||
|
-- Solution --------------------------------------------------------------------
|
||||||
|
local a_value = 65
|
||||||
|
|
||||||
|
function apply_shift(letter, shift)
|
||||||
|
local shifted = (letter - a_value + shift) % 26
|
||||||
|
return a_value + shifted
|
||||||
|
end
|
||||||
|
|
||||||
|
function vigenere_encode(plaintext, keyword)
|
||||||
|
local key = {}
|
||||||
|
for i = 1, #keyword do
|
||||||
|
local shift = string.byte(keyword, i) - a_value
|
||||||
|
table.insert(key, shift)
|
||||||
|
end
|
||||||
|
|
||||||
|
plaintext = string.gsub(string.upper(plaintext), "%A+", "")
|
||||||
|
ciphertext = ""
|
||||||
|
for i = 1, #plaintext do
|
||||||
|
local letter = string.byte(plaintext, i)
|
||||||
|
local shift = key[(i - 1) % #key + 1]
|
||||||
|
local shifted = apply_shift(letter, shift)
|
||||||
|
ciphertext = ciphertext .. string.char(shifted)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ciphertext
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local luaunit = require("luaunit.luaunit")
|
||||||
|
|
||||||
|
function test_encoding_of_foo_with_key_BAR()
|
||||||
|
luaunit.assertEquals(vigenere_encode("FOO", "BAR"), "GOF")
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_encoding_of_the_quick_brown_fox_with_key_JUMPSOVER()
|
||||||
|
local plaintext = "The quick brown fox"
|
||||||
|
local key = "JUMPSOVER"
|
||||||
|
local expected = "CBQFMWXOSAIICXCS"
|
||||||
|
luaunit.assertEquals(vigenere_encode(plaintext, key), expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_encoding_longer_phrase_with_key_LEAR()
|
||||||
|
local plaintext =
|
||||||
|
"They dined on mince and slices of quince, which they ate with a runcible spoon."
|
||||||
|
local key = "LEAR"
|
||||||
|
local expected = "ELEPOMNVOSNDTRCVLRDJWMCVDSFHFMNTPAHZNLTYPCAKPAIKSERLYGISWISGZSN"
|
||||||
|
luaunit.assertEquals(vigenere_encode(plaintext, key), expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
os.exit(luaunit.LuaUnit.run())
|
||||||
50
17_prime_factors.lua
Normal file
50
17_prime_factors.lua
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
-- Write a function which determines the prime factors of a given
|
||||||
|
-- number, returning them in a list. You may assume that none of the
|
||||||
|
-- prime factors are above 10000
|
||||||
|
--
|
||||||
|
-- Solution --------------------------------------------------------------------
|
||||||
|
function prime_factors(n)
|
||||||
|
-- Your implementation here
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local luaunit = require("luaunit.luaunit")
|
||||||
|
|
||||||
|
function test_prime_factors_of_42()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(42), {2, 3, 7})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_70()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(70), {2, 5, 7})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_253()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(253), {11, 23})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_245()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(245), {5, 7, 7})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_36()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(36), {2, 2, 3, 3})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_1337()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(1337), {7, 191})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_4321()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(4321), {29, 149})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_57812834()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(57812834), {2, 29, 113, 8821})
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_prime_factors_of_8894220()
|
||||||
|
luaunit.assertItemsEquals(prime_factors(8894220), {2, 2, 3, 5, 271, 547})
|
||||||
|
end
|
||||||
|
|
||||||
|
os.exit(luaunit.LuaUnit.run())
|
||||||
81
18_towers_of_hanoi.lua
Normal file
81
18_towers_of_hanoi.lua
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
-- The Towers of Hanoi is a mathematical puzzle consisting of three
|
||||||
|
-- rods and a number of disks of various diameters which can slide
|
||||||
|
-- onto any rod. Initially, all the disks are stacked in decreasing
|
||||||
|
-- size order so that they form a conical shape. The objective to
|
||||||
|
-- move the entire stack to one of the other two rods, with each move
|
||||||
|
-- consisting of taking the uppermost disk from one of the rods and
|
||||||
|
-- placing it on top of the stack on another one. A disk cannot be
|
||||||
|
-- placed on top of a disk of smaller diameter.
|
||||||
|
--
|
||||||
|
-- Write a function which generates an optimal solution to the puzzle.
|
||||||
|
-- The rods are numbered 1-3, with the stack starting on rod 1. Your
|
||||||
|
-- function should return a list of {from = <rod>, to = <rod>} tables,
|
||||||
|
-- and will receive the number of disks in the original stack as its
|
||||||
|
-- argument.
|
||||||
|
--
|
||||||
|
-- Solution --------------------------------------------------------------------
|
||||||
|
function towers_of_hanoi_solution(disk_count)
|
||||||
|
-- Your implementation here
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local luaunit = require("luaunit.luaunit")
|
||||||
|
|
||||||
|
local function disk_stack(count)
|
||||||
|
local stack = {}
|
||||||
|
for i = count, 1, -1 do table.insert(stack, i) end
|
||||||
|
return stack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_valid(state)
|
||||||
|
for _, rod in ipairs(state) do
|
||||||
|
local previous = rod[1]
|
||||||
|
for _, disk in ipairs(rod) do
|
||||||
|
luaunit.assertTrue(disk <= previous)
|
||||||
|
previous = disk
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_solved(state, disk_count)
|
||||||
|
luaunit.assertEquals(state[1], {})
|
||||||
|
if #state[2] ~= 0 then
|
||||||
|
luaunit.assertEquals(state[2], disk_stack(disk_count))
|
||||||
|
luaunit.assertEquals(state[3], {})
|
||||||
|
else
|
||||||
|
luaunit.assertEquals(state[2], {})
|
||||||
|
luaunit.assertEquals(state[3], disk_stack(disk_count))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_is_solution(solution, disk_count)
|
||||||
|
local state = {disk_stack(disk_count), {}, {}}
|
||||||
|
for i, move in ipairs(solution) do
|
||||||
|
local disk = table.remove(state[move.from])
|
||||||
|
table.insert(state[move.to], disk)
|
||||||
|
assert_valid(state)
|
||||||
|
end
|
||||||
|
assert_solved(state, disk_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function test_with_count(disk_count)
|
||||||
|
local solution = towers_of_hanoi_solution(disk_count)
|
||||||
|
assert_is_solution(solution, disk_count)
|
||||||
|
luaunit.assertEquals(#solution, 2 ^ disk_count - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_with_1_disk()
|
||||||
|
test_with_count(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_with_7_disks()
|
||||||
|
test_with_count(7)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_with_12_disks()
|
||||||
|
test_with_count(12)
|
||||||
|
end
|
||||||
|
|
||||||
|
os.exit(luaunit.LuaUnit.run())
|
||||||
105
19_dependencies.lua
Normal file
105
19_dependencies.lua
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
-- Write a function to generate a valid order for a number of jobs
|
||||||
|
-- that depend upon each other. Your input is a jobs table; each key
|
||||||
|
-- is a job number, with its the values being a list jobs it depends
|
||||||
|
-- on. You may assume that there are no circular dependencies.
|
||||||
|
--
|
||||||
|
-- Return a list of job numbers, so that performing the jobs in that
|
||||||
|
-- order ensures that all jobs are exactly once, and all dependencies
|
||||||
|
-- of a job are done before prior to it.
|
||||||
|
--
|
||||||
|
-- Solution --------------------------------------------------------------------
|
||||||
|
function schedule(jobs)
|
||||||
|
-- Your implementation here
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local luaunit = require("luaunit.luaunit")
|
||||||
|
|
||||||
|
local function keys(t)
|
||||||
|
local results = {}
|
||||||
|
for key, _ in pairs(t) do table.insert(results, key) end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
local function contains(list, target)
|
||||||
|
for _, item in ipairs(list) do if item == target then return true end end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function deep_copy(original)
|
||||||
|
local copy = {}
|
||||||
|
if type(original) == "table" then
|
||||||
|
for key, value in pairs(original) do
|
||||||
|
local key_copy = deep_copy(key)
|
||||||
|
local value_copy = deep_copy(value)
|
||||||
|
copy[key_copy] = value_copy
|
||||||
|
end
|
||||||
|
else
|
||||||
|
copy = original
|
||||||
|
end
|
||||||
|
return copy
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_valid(order, jobs)
|
||||||
|
local done = {}
|
||||||
|
for _, job in ipairs(order) do
|
||||||
|
for _, dependency in ipairs(jobs[job]) do
|
||||||
|
luaunit.assertTrue(contains(done, dependency))
|
||||||
|
end
|
||||||
|
table.insert(done, job)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function test_case(jobs)
|
||||||
|
local order = schedule(deep_copy(jobs))
|
||||||
|
luaunit.assertItemsEquals(order, keys(jobs))
|
||||||
|
assert_valid(order, jobs)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_sequential_dependencies()
|
||||||
|
local jobs = {[1] = {2}, [2] = {3}, [3] = {}}
|
||||||
|
test_case(jobs)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_converging_dependencies()
|
||||||
|
local jobs = {
|
||||||
|
[1] = {5},
|
||||||
|
[2] = {5},
|
||||||
|
[3] = {6},
|
||||||
|
[4] = {6},
|
||||||
|
[5] = {7},
|
||||||
|
[6] = {7},
|
||||||
|
[7] = {},
|
||||||
|
}
|
||||||
|
test_case(jobs)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_diverging_dependencies()
|
||||||
|
local jobs = {
|
||||||
|
[1] = {2, 3},
|
||||||
|
[2] = {4, 5},
|
||||||
|
[3] = {6, 7},
|
||||||
|
[4] = {},
|
||||||
|
[5] = {},
|
||||||
|
[6] = {},
|
||||||
|
[7] = {}
|
||||||
|
}
|
||||||
|
test_case(jobs)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_compound_dependencies()
|
||||||
|
local jobs = {
|
||||||
|
[1] = {2, 3, 4},
|
||||||
|
[2] = {5, 6},
|
||||||
|
[3] = {7},
|
||||||
|
[4] = {7},
|
||||||
|
[5] = {},
|
||||||
|
[6] = {8},
|
||||||
|
[7] = {8},
|
||||||
|
[8] = {}
|
||||||
|
}
|
||||||
|
test_case(jobs)
|
||||||
|
end
|
||||||
|
|
||||||
|
os.exit(luaunit.LuaUnit.run())
|
||||||
340
20_legal_captures.lua
Normal file
340
20_legal_captures.lua
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
-- 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())
|
||||||
36
README.md
36
README.md
@@ -1,12 +1,36 @@
|
|||||||
# Lua Exercises
|
# Lua Exercises
|
||||||
|
|
||||||
This repo contains some Lua exercises along with automated tests for
|
This repo contains some Lua exercises along with automated tests for
|
||||||
their solutions. Each file contains a description of the problem and
|
solutions. Each file contains a description of the problem and an
|
||||||
an area for your solution as well as the tests. Feel free to define
|
area for a solution as well as the tests.
|
||||||
as many functions and constants as you need in the solution area, but
|
|
||||||
do not modify the tests. It's recommended that you roughly stick to
|
## Set Up
|
||||||
the defined order of the exercises, but feel free to deviate if you
|
|
||||||
wish.
|
To get started, create a fork of this repo on your own account (with
|
||||||
|
the "Fork" button in the top-left of the Gitea page"), then clone it,
|
||||||
|
passing the `--recursive` flag. If you already cloned it without
|
||||||
|
passing `--recursive`, you can run `git submodule update --init` to
|
||||||
|
fix it.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone --recursive git@git.wip.sh:<your-username>/lua-exercises.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Doing the Exercises
|
||||||
|
|
||||||
|
It's recommended that you roughly stick to the defined order of the
|
||||||
|
exercises, but feel free to deviate if you wish. Some of the
|
||||||
|
exercises are relatively easy, whereas some of them (especially the
|
||||||
|
last few) are quite challenging; do not be disheartened if solving a
|
||||||
|
particular exercise takes you a long time, and feel free to ask for
|
||||||
|
help in the Discord server if you feel you are stuck.
|
||||||
|
|
||||||
|
You can define as many functions and constants as you need in the
|
||||||
|
solution area. You might find it useful to temporarily comment out
|
||||||
|
some of the tests to work through the cases one by one (especially on
|
||||||
|
the more complex exercises), but do not modify the test code other
|
||||||
|
than this, and make sure all the cases are un-commented again before
|
||||||
|
considering the exercise solved.
|
||||||
|
|
||||||
To run the tests and check your solution for a given exercise, simply
|
To run the tests and check your solution for a given exercise, simply
|
||||||
run `lua <the-file>`. For example, if you were working on the
|
run `lua <the-file>`. For example, if you were working on the
|
||||||
|
|||||||
Reference in New Issue
Block a user