Compare commits
1 Commits
main
...
1acded5363
| Author | SHA1 | Date | |
|---|---|---|---|
| 1acded5363 |
@@ -1,43 +0,0 @@
|
|||||||
-- Write a function which takes a limit and returns a list of every
|
|
||||||
-- prime number below that limit. It is recommended that you use the
|
|
||||||
-- "Sieve of Eratosthenes" algorithm, but you can try a different
|
|
||||||
-- prime sieve algorithm if you want.
|
|
||||||
--
|
|
||||||
-- Solution --------------------------------------------------------------------
|
|
||||||
function lesser_primes(limit)
|
|
||||||
-- Your implementation here
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Tests -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
local luaunit = require("luaunit.luaunit")
|
|
||||||
|
|
||||||
function test_primes_below_2048()
|
|
||||||
local primes = {
|
|
||||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
|
||||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
|
|
||||||
157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
|
|
||||||
239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
|
|
||||||
331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
|
|
||||||
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
|
|
||||||
509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
|
|
||||||
613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
|
|
||||||
709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
|
|
||||||
821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
|
|
||||||
919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
|
|
||||||
1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
|
|
||||||
1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
|
|
||||||
1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
|
|
||||||
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409,
|
|
||||||
1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487,
|
|
||||||
1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579,
|
|
||||||
1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
|
|
||||||
1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777,
|
|
||||||
1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
|
|
||||||
1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
|
|
||||||
1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039
|
|
||||||
}
|
|
||||||
luaunit.assertEquals(lesser_primes(2048), primes)
|
|
||||||
end
|
|
||||||
|
|
||||||
os.exit(luaunit.LuaUnit.run())
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
-- 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())
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
-- Run length encoding is a simple data compression technique where a
|
|
||||||
-- "run" of the same value is replaced with a count and a single copy.
|
|
||||||
-- In this exercise we will use the notation "#<count>:<value>" to
|
|
||||||
-- indicate such a run; however, this should only be put into the
|
|
||||||
-- output if it is strictly shorter than the string it is replacing.
|
|
||||||
-- The input will consist only of alphanumeric characters.
|
|
||||||
--
|
|
||||||
-- Solution --------------------------------------------------------------------
|
|
||||||
function run_length_encode(input)
|
|
||||||
-- Your implementation here
|
|
||||||
end
|
|
||||||
-- Tests -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
local luaunit = require("luaunit.luaunit")
|
|
||||||
|
|
||||||
function test_encoding_of_aaaaaaaa22bbbbbbssssfffffff67eee66666asdfff()
|
|
||||||
local input = "aaaaaaaa22bbbbbbssssfffffff67eee66666asdfff"
|
|
||||||
local expected = "#8:a22#6:bssss#7:f67eee#5:6asdfff"
|
|
||||||
luaunit.assertEquals(run_length_encode(input), expected)
|
|
||||||
end
|
|
||||||
|
|
||||||
function test_encoding_of_wwwwwfffff1223566666666bbbbbbbbbbb78b99asasdfbnfasdafffffff99()
|
|
||||||
local input = "wwwwwfffff1223566666666bbbbbbbbbbb78b99asasdfbnfasdafffffff99"
|
|
||||||
local expected = "#5:w#5:f12235#8:6#11:b78b99asasdfbnfasda#7:f99"
|
|
||||||
luaunit.assertEquals(run_length_encode(input), expected)
|
|
||||||
end
|
|
||||||
|
|
||||||
os.exit(luaunit.LuaUnit.run())
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
-- Postfix notation is an alternative to the normal "infix" notation
|
|
||||||
-- used in mathematical expressions. Instead of writing the operator
|
|
||||||
-- between the operands, the operator comes after them. For example,
|
|
||||||
-- "1 + 2" is notated as "1 2 +". This removes the need for operator
|
|
||||||
-- precedence and parentheses: rather than having to resolve the
|
|
||||||
-- ambiguity of an expression like "1 + 2 * 3" with convention or
|
|
||||||
-- parentheses, the evaluation order is explicit -- multiplication-
|
|
||||||
-- first is "1 2 3 * +" and addition-first is "1 2 + 3 *".
|
|
||||||
--
|
|
||||||
-- As well as this notational convenience, postfix can be easily
|
|
||||||
-- evaluated using a stack. Whenever an operand is encountered, the
|
|
||||||
-- value is pushed onto the stack, and whenever an operator is
|
|
||||||
-- encountered, two values are popped from the stack and the result of
|
|
||||||
-- the operation is pushed on in their place. Finally, the value left
|
|
||||||
-- on the top of the stack is the result of the operation.
|
|
||||||
--
|
|
||||||
-- Write a function that will evaluate a postfix expression and return
|
|
||||||
-- the result. You can assume that the expression is valid, and not
|
|
||||||
-- worry about handling error cases. The operators will be "+", "-",
|
|
||||||
-- "*" and "/".
|
|
||||||
--
|
|
||||||
-- Solution --------------------------------------------------------------------
|
|
||||||
function evaluate_postfix(expression)
|
|
||||||
-- Your implementation here
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Tests -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
local luaunit = require("luaunit.luaunit")
|
|
||||||
|
|
||||||
function test_1_2_plus_3_times_is_9()
|
|
||||||
luaunit.assertEquals(evaluate_postfix("1 2 + 3 *"), 9)
|
|
||||||
end
|
|
||||||
|
|
||||||
function test_1_2_3_times_plus_is_7()
|
|
||||||
luaunit.assertEquals(evaluate_postfix("1 2 3 * +"), 7)
|
|
||||||
end
|
|
||||||
|
|
||||||
function test_4_6_plus_5_divide_2_1_minus_minus_is_1()
|
|
||||||
luaunit.assertEquals(evaluate_postfix("4 6 + 5 / 2 1 - -"), 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function test_12_2_times_6_divide_10_times_2_plus_is_42()
|
|
||||||
luaunit.assertEquals(evaluate_postfix("12 2 * 6 / 10 * 2 +"), 42)
|
|
||||||
end
|
|
||||||
|
|
||||||
os.exit(luaunit.LuaUnit.run())
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
-- 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())
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
-- 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())
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
-- 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())
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
-- 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,39 +1,13 @@
|
|||||||
# 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
|
||||||
solutions. Each file contains a description of the problem and an
|
their solutions. Each file contains a description of the problem and
|
||||||
area for a solution as well as the tests.
|
an area for your solution as well as the tests. Feel free to define
|
||||||
|
as many functions and constants as you need in the solution area, but
|
||||||
## Set Up
|
do not modify the tests.
|
||||||
|
|
||||||
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
|
||||||
anagrams exercise, you would run `lua 08_anagrams.lua`. For each
|
anagrams exercise, you would run `lua xxx_anagrams.lua`. For each
|
||||||
exercise, the tests should run in well under a tenth of a second; if
|
exercise, the tests should run in well under a tenth of a second; if
|
||||||
it takes longer than this you should try to speed up your solution.
|
it takes longer than this you should try to speed up your solution.
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
-- The greatest common divisor (GCD) of two numbers is, as the name
|
-- The greatest common divisor (GCD) of two numbers X and Y is, as the
|
||||||
-- suggests, the largest number which evenly divides both. Implement
|
-- name suggests, the largest number which evenly divides both X and
|
||||||
-- the function below to calculate this. It's recommended that you
|
-- Y. Implement the function below to calculate this.
|
||||||
-- use Euclid's algorithm but feel free to use another approach if you
|
|
||||||
-- want.
|
|
||||||
--
|
--
|
||||||
-- Solution --------------------------------------------------------------------
|
-- Solution --------------------------------------------------------------------
|
||||||
function greatest_common_divisor(x, y)
|
function greatest_common_divisor(x, y)
|
||||||
Reference in New Issue
Block a user