Kumite (ko͞omiˌtā) is the practice of taking techniques learned from Kata and applying them through the act of freestyle sparring.
You can create a new kumite by providing some initial code and optionally some test cases. From there other warriors can spar with you, by enhancing, refactoring and translating your code. There is no limit to how many warriors you can spar with.
A great use for kumite is to begin an idea for a kata as one. You can collaborate with other code warriors until you have it right, then you can convert it to a kata.
using System.Linq; public class Program { public static int FindSquaresInArray(int[] arr){ return arr.Sum(x => x * x); } }
- using System.Linq;
- public class Program
- {
public static int FindSquaresInArray(int[] arr) => arr.Sum(x => x * x);- public static int FindSquaresInArray(int[] arr){
- return arr.Sum(x => x * x);
- }
- }
print(f'{chr(72)}{chr(101)}{2 * chr(108)}{chr(111)}{chr(44)}{chr(32)}{chr(87)}{chr(111)}{chr(114)}{chr(108)}{chr(100)}{2 * chr(33)}')
print(chr(72) +chr(101) +2 * chr(108) +chr(111) +chr(44) +chr(32) +chr(87) +chr(111) +chr(114) +chr(108) +chr(100) +2 * chr(33))- print(f'{chr(72)}{chr(101)}{2 * chr(108)}{chr(111)}{chr(44)}{chr(32)}{chr(87)}{chr(111)}{chr(114)}{chr(108)}{chr(100)}{2 * chr(33)}')
import codewars_test as test # TODO Write tests import solution # or from solution import example # test.assert_equals(actual, expected, [optional] message) @test.describe("Brand New Triple A RPG Game") def test_group(): @test.it("Hello?") def test_case(): test.assert_equals(1 + 1, 2)
- import codewars_test as test
- # TODO Write tests
- import solution # or from solution import example
- # test.assert_equals(actual, expected, [optional] message)
@test.describe("Example")- @test.describe("Brand New Triple A RPG Game")
- def test_group():
@test.it("test case")- @test.it("Hello?")
- def test_case():
- test.assert_equals(1 + 1, 2)
Constructor situation is a bit better now. Thunks are now copyable and are more flexibly constructible.
Background
C++ recreation of the Thunk API from this Kata.
Test cases are included to verify if it works as expected. The full extent of the class is used in those test cases.
#include <tuple> #include <string> #include <vector> #include <utility> Describe(fixed_test_cases) { It(basic_thunk_tests) { // Currently stores 3. Thunk num1 = MakeThunk::now(3); // Represents the future result of multiplying num1's value by 2 (i.e., 3 * 2 ==> 6). Thunk num2 = num1.chain([](auto n) { return n * 2; }); // Delayed computation of the number formed by concatenating num1 and num2 as strings. // Note: Since the function captures by reference, it's impure. However, this can allow us to check if computation is actually delayed. const Thunk num3 = MakeThunk::delay([&] { return std::stoi(std::to_string(num1.get()) + std::to_string(num2.get())); }); Assert::That(num2.get(), Equals(6)); Assert::That(num1.get(), Equals(3)); // Change num2 to 0. num2 = MakeThunk::delay([] { return 0; }); // Since Thunks delay computation, it actually computes 30 (up to date) and not 36 (outdated). Assert::That(num3.get(), Equals(30)); // Change num1 to 4. num1 = MakeThunk::now(4); // Thunk only evaluated once - unaffected by change. Remains 30 instead of 40. Assert::That(num3.get(), Equals(30)); // Works with regular old functions (non-functors) too. const Thunk num4 = MakeThunk::delay(return_24); Assert::That(num4.get(), Equals(24)); } It(can_chain_different_types) { // First chain returns int, second returns std::pair<int, int>, third returns string. const Thunk birthday_msg = MakeThunk::now(24) .chain([](auto n) { return std::pair{ n, n + 1 }; }) .chain([](auto ages) { return "Do you know what is funnier than " + std::to_string(ages.first) + "? " + std::to_string(ages.second) + "!"; }); Assert::That(birthday_msg.get(), Equals("Do you know what is funnier than 24? 25!")); } It(allows_cyclic_ref) { using LazyPair = std::pair<int, Thunk<int>>; // Second item of pair is 5 times the first (i.e., 10 * 5 == 50). LazyPair lazy_pair{ 10, MakeThunk::delay([&] { return lazy_pair.first * 5; })}; Assert::That(lazy_pair.second.get(), Equals(50)); } It(successfully_extends_lifetime) { Thunk<int> remaining_thunk{}; // Scope to restrict the lifetime of `expiring_thunk`. `remaining_thunk` depends on its data. { Thunk expiring_thunk = MakeThunk::now(3); remaining_thunk = expiring_thunk.chain([](auto n) { return n * 2; }); } // Thunk class should successfully extend the lifetime of the data of other Thunks it depends on. Assert::That(remaining_thunk.get(), Equals(6)); } It(thunk_is_copyable) { Thunk<const char*> c_str_thunk = MakeThunk::now("Yooooo"); Thunk<std::string> str_thunk_1 = c_str_thunk; Assert::That(str_thunk_1.get(), Equals("Yooooo")); Assert::That(std::is_same_v<std::string, std::decay_t<decltype(str_thunk_1.get())>>); Assert::That(str_thunk_1.get().c_str() != c_str_thunk.get()); Thunk<std::string> str_thunk_2 = MakeThunk::now("yo"); Assert::That(str_thunk_2.get(), Equals("yo")); Assert::That(std::is_same_v<std::string, std::decay_t<decltype(str_thunk_2.get())>>); Thunk<std::string> str_thunk_cpy = str_thunk_1; // If the types are the same, reuse the same stored data. Assert::That(&str_thunk_cpy.get() == &str_thunk_1.get()); Assert::That(str_thunk_1.get().c_str() == str_thunk_cpy.get().c_str()); } It(all_thunk_constructors_work_correctly) { const Thunk<int> num5{ return_24 }; // return_24 is a regular non-functor function. Assert::That(num5.get(), Equals(24)); const auto default_thunk_1 = MakeThunk::now_in_place<std::pair<int, int>>(); const Thunk<std::pair<int, int>> default_thunk_2{}; const Thunk default_thunk_3 = MakeThunk::now(std::pair<int, int>{}); const Thunk<std::pair<int, int>> default_thunk_4{ std::in_place }; Assert::That(default_thunk_1.get() == default_thunk_2.get() and default_thunk_2.get() == default_thunk_3.get() and default_thunk_3.get() == default_thunk_4.get()); const auto str_thunk = MakeThunk::now_in_place<std::string>("hey"); Assert::That(str_thunk.get(), Equals("hey")); const auto three_b_thunk = MakeThunk::now_in_place<std::string>(3, 'B'); Assert::That(three_b_thunk.get(), Equals("BBB")); const auto vec_thunk = MakeThunk::now_in_place<std::vector<int>>(std::initializer_list<int>{ 1, 2, 3 }); Assert::That(vec_thunk.get(), Equals(std::vector{ 1, 2, 3 })); const Thunk<std::string> four_a_thunk{ std::in_place, 4, 'A' }; Assert::That(four_a_thunk.get(), Equals("AAAA")); const Thunk<std::pair<int, char>> pair_thunk{ std::in_place, 2, 'z' }; Assert::That(pair_thunk.get(), Equals(std::pair{ 2, 'z' })); const auto tuple_thunk = MakeThunk::now_in_place<std::tuple<int, char, int, int>>(-2, 'f', 2000, 9); Assert::That(tuple_thunk.get(), Equals(std::tuple{ -2, 'f', 2000, 9 })); } private: // Regular old function. static int return_24() { return 24; } };
- #include <tuple>
- #include <string>
- #include <vector>
- #include <utility>
- Describe(fixed_test_cases)
- {
- It(basic_thunk_tests)
- {
- // Currently stores 3.
- Thunk num1 = MakeThunk::now(3);
- // Represents the future result of multiplying num1's value by 2 (i.e., 3 * 2 ==> 6).
- Thunk num2 = num1.chain([](auto n) { return n * 2; });
- // Delayed computation of the number formed by concatenating num1 and num2 as strings.
- // Note: Since the function captures by reference, it's impure. However, this can allow us to check if computation is actually delayed.
- const Thunk num3 = MakeThunk::delay([&] { return std::stoi(std::to_string(num1.get()) + std::to_string(num2.get())); });
- Assert::That(num2.get(), Equals(6));
- Assert::That(num1.get(), Equals(3));
- // Change num2 to 0.
- num2 = MakeThunk::delay([] { return 0; });
- // Since Thunks delay computation, it actually computes 30 (up to date) and not 36 (outdated).
- Assert::That(num3.get(), Equals(30));
- // Change num1 to 4.
- num1 = MakeThunk::now(4);
// Thunk only computed once - unaffected by change. Remains 30 instead of 40.- // Thunk only evaluated once - unaffected by change. Remains 30 instead of 40.
- Assert::That(num3.get(), Equals(30));
- // Works with regular old functions (non-functors) too.
- const Thunk num4 = MakeThunk::delay(return_24);
- Assert::That(num4.get(), Equals(24));
- }
- It(can_chain_different_types)
- {
- // First chain returns int, second returns std::pair<int, int>, third returns string.
- const Thunk birthday_msg = MakeThunk::now(24)
- .chain([](auto n) { return std::pair{ n, n + 1 }; })
- .chain([](auto ages) { return "Do you know what is funnier than " + std::to_string(ages.first) + "? " + std::to_string(ages.second) + "!"; });
- Assert::That(birthday_msg.get(), Equals("Do you know what is funnier than 24? 25!"));
- }
- It(allows_cyclic_ref)
- {
- using LazyPair = std::pair<int, Thunk<int>>;
- // Second item of pair is 5 times the first (i.e., 10 * 5 == 50).
- LazyPair lazy_pair{ 10, MakeThunk::delay([&] { return lazy_pair.first * 5; })};
- Assert::That(lazy_pair.second.get(), Equals(50));
- }
- It(successfully_extends_lifetime)
- {
- Thunk<int> remaining_thunk{};
- // Scope to restrict the lifetime of `expiring_thunk`. `remaining_thunk` depends on its data.
- {
- Thunk expiring_thunk = MakeThunk::now(3);
- remaining_thunk = expiring_thunk.chain([](auto n) { return n * 2; });
- }
- // Thunk class should successfully extend the lifetime of the data of other Thunks it depends on.
- Assert::That(remaining_thunk.get(), Equals(6));
- }
- It(thunk_is_copyable)
- {
- Thunk<const char*> c_str_thunk = MakeThunk::now("Yooooo");
- Thunk<std::string> str_thunk_1 = c_str_thunk;
- Assert::That(str_thunk_1.get(), Equals("Yooooo"));
- Assert::That(std::is_same_v<std::string, std::decay_t<decltype(str_thunk_1.get())>>);
- Assert::That(str_thunk_1.get().c_str() != c_str_thunk.get());
- Thunk<std::string> str_thunk_2 = MakeThunk::now("yo");
- Assert::That(str_thunk_2.get(), Equals("yo"));
- Assert::That(std::is_same_v<std::string, std::decay_t<decltype(str_thunk_2.get())>>);
- Thunk<std::string> str_thunk_cpy = str_thunk_1;
- // If the types are the same, reuse the same stored data.
- Assert::That(&str_thunk_cpy.get() == &str_thunk_1.get());
- Assert::That(str_thunk_1.get().c_str() == str_thunk_cpy.get().c_str());
- }
- It(all_thunk_constructors_work_correctly)
- {
- const Thunk<int> num5{ return_24 }; // return_24 is a regular non-functor function.
- Assert::That(num5.get(), Equals(24));
- const auto default_thunk_1 = MakeThunk::now_in_place<std::pair<int, int>>();
- const Thunk<std::pair<int, int>> default_thunk_2{};
- const Thunk default_thunk_3 = MakeThunk::now(std::pair<int, int>{});
- const Thunk<std::pair<int, int>> default_thunk_4{ std::in_place };
- Assert::That(default_thunk_1.get() == default_thunk_2.get() and default_thunk_2.get() == default_thunk_3.get() and default_thunk_3.get() == default_thunk_4.get());
- const auto str_thunk = MakeThunk::now_in_place<std::string>("hey");
- Assert::That(str_thunk.get(), Equals("hey"));
- const auto three_b_thunk = MakeThunk::now_in_place<std::string>(3, 'B');
- Assert::That(three_b_thunk.get(), Equals("BBB"));
- const auto vec_thunk = MakeThunk::now_in_place<std::vector<int>>(std::initializer_list<int>{ 1, 2, 3 });
- Assert::That(vec_thunk.get(), Equals(std::vector{ 1, 2, 3 }));
- const Thunk<std::string> four_a_thunk{ std::in_place, 4, 'A' };
- Assert::That(four_a_thunk.get(), Equals("AAAA"));
- const Thunk<std::pair<int, char>> pair_thunk{ std::in_place, 2, 'z' };
- Assert::That(pair_thunk.get(), Equals(std::pair{ 2, 'z' }));
- const auto tuple_thunk = MakeThunk::now_in_place<std::tuple<int, char, int, int>>(-2, 'f', 2000, 9);
- Assert::That(tuple_thunk.get(), Equals(std::tuple{ -2, 'f', 2000, 9 }));
- }
- private:
- // Regular old function.
- static int return_24() { return 24; }
- };
This algorithm of 'sum()' is SFINAE-friendly. By first testing if the corresponding types can be added with the type trait 'has_plus' because some types doesn't have the 'operator+' defined. If for any reason, the types doesn't have the addition operator available, the function will be disabled via 'std::enable_if' and will be discarded by SFINAE. In constrast, if the types can be added, the 'std::enable_if' trait will enable the function and returning the corresponding type of add the two types with the 'plus_result' trait.
#include <vector> #include <numeric> #include <type_traits> #include <utility> namespace { template<typename, typename, typename = void> struct has_plus : std::false_type {}; template<typename T1, typename T2> struct has_plus<T1, T2, std::void_t<decltype(std::declval<T1>() + std::declval<T2>())>> : std::true_type {}; template<typename T1, typename T2> inline constexpr bool has_plus_v = has_plus<T1, T2>::value; template<typename T1, typename T2, bool = has_plus_v<T1, T2>> struct plus_result { using type = decltype(std::declval<T1>() + std::declval<T2>()); }; template<typename T1, typename T2> struct plus_result<T1, T2, false> {}; template<typename T1, typename T2> using plus_result_t = typename plus_result<T1, T2>::type; template<typename T = double, typename = std::enable_if_t<has_plus_v<T, T>>> plus_result_t<T, T> sum(const std::vector<T>& v) { return std::accumulate(v.cbegin(), v.cend(), T{}); } }
- #include <vector>
- #include <numeric>
- #include <type_traits>
- #include <utility>
template <typename T> using add_t=decltype(T() + T());- namespace
- {
- template<typename, typename, typename = void>
- struct has_plus : std::false_type {};
template <typename T = double>add_t<T> sum(const std::vector<T>& v) {return std::accumulate(v.cbegin(),v.cend(),add_t<T>{0});- template<typename T1, typename T2>
- struct has_plus<T1, T2, std::void_t<decltype(std::declval<T1>() + std::declval<T2>())>> : std::true_type {};
- template<typename T1, typename T2>
- inline constexpr bool has_plus_v = has_plus<T1, T2>::value;
- template<typename T1, typename T2, bool = has_plus_v<T1, T2>>
- struct plus_result
- {
- using type = decltype(std::declval<T1>() + std::declval<T2>());
- };
- template<typename T1, typename T2>
- struct plus_result<T1, T2, false> {};
- template<typename T1, typename T2>
- using plus_result_t = typename plus_result<T1, T2>::type;
- template<typename T = double, typename = std::enable_if_t<has_plus_v<T, T>>>
- plus_result_t<T, T> sum(const std::vector<T>& v)
- {
- return std::accumulate(v.cbegin(), v.cend(), T{});
- }
- }