From bfec737c009bc4e761d348c6b05c94c44d4d1acd Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Fri, 17 Jul 2026 19:03:20 +1000 Subject: [PATCH] add `secret-handshake` exercise --- config.json | 20 ++++++++ .../secret-handshake/.docs/instructions.md | 48 +++++++++++++++++++ .../secret-handshake/.docs/introduction.md | 7 +++ .../secret-handshake/.meta/config.json | 19 ++++++++ .../secret-handshake/.meta/example.factor | 10 ++++ .../secret-handshake/.meta/generator.jl | 10 ++++ .../secret-handshake/.meta/tests.toml | 43 +++++++++++++++++ .../exercism-tools/exercism-tools.factor | 35 ++++++++++++++ .../secret-handshake-tests.factor | 48 +++++++++++++++++++ .../secret-handshake/secret-handshake.factor | 5 ++ 10 files changed, 245 insertions(+) create mode 100644 exercises/practice/secret-handshake/.docs/instructions.md create mode 100644 exercises/practice/secret-handshake/.docs/introduction.md create mode 100644 exercises/practice/secret-handshake/.meta/config.json create mode 100644 exercises/practice/secret-handshake/.meta/example.factor create mode 100644 exercises/practice/secret-handshake/.meta/generator.jl create mode 100644 exercises/practice/secret-handshake/.meta/tests.toml create mode 100644 exercises/practice/secret-handshake/exercism-tools/exercism-tools.factor create mode 100644 exercises/practice/secret-handshake/secret-handshake/secret-handshake-tests.factor create mode 100644 exercises/practice/secret-handshake/secret-handshake/secret-handshake.factor diff --git a/config.json b/config.json index 57b1d95..e3fd0b8 100644 --- a/config.json +++ b/config.json @@ -1566,6 +1566,26 @@ ], "difficulty": 4 }, + { + "slug": "secret-handshake", + "name": "Secret Handshake", + "uuid": "ab56856e-c5e2-467c-952e-7f7afa15c7f5", + "practices": [ + "bitwise-operations" + ], + "prerequisites": [ + "numbers", + "sequences", + "arrays", + "higher-order-sequences", + "indexed-iteration", + "bitwise-operations", + "combinators", + "curry-compose-fry", + "locals" + ], + "difficulty": 4 + }, { "slug": "sieve", "name": "Sieve", diff --git a/exercises/practice/secret-handshake/.docs/instructions.md b/exercises/practice/secret-handshake/.docs/instructions.md new file mode 100644 index 0000000..d2120b9 --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/instructions.md @@ -0,0 +1,48 @@ +# Instructions + +Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake. + +The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. +Start at the right-most digit and move left. + +The actions for each number place are: + +```plaintext +00001 = wink +00010 = double blink +00100 = close your eyes +01000 = jump +10000 = Reverse the order of the operations in the secret handshake. +``` + +Let's use the number `9` as an example: + +- 9 in binary is `1001`. +- The digit that is farthest to the right is 1, so the first action is `wink`. +- Going left, the next digit is 0, so there is no double-blink. +- Going left again, the next digit is 0, so you leave your eyes open. +- Going left again, the next digit is 1, so you jump. + +That was the last digit, so the final code is: + +```plaintext +wink, jump +``` + +Given the number 26, which is `11010` in binary, we get the following actions: + +- double blink +- jump +- reverse actions + +The secret handshake for 26 is therefore: + +```plaintext +jump, double blink +``` + +~~~~exercism/note +If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. + +[intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa +~~~~ diff --git a/exercises/practice/secret-handshake/.docs/introduction.md b/exercises/practice/secret-handshake/.docs/introduction.md new file mode 100644 index 0000000..176b92e --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You are starting a secret coding club with some friends and friends-of-friends. +Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. +You don't want anyone who isn't in the know to be able to crack the code. + +You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. diff --git a/exercises/practice/secret-handshake/.meta/config.json b/exercises/practice/secret-handshake/.meta/config.json new file mode 100644 index 0000000..f92f1e6 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "secret-handshake/secret-handshake.factor" + ], + "test": [ + "secret-handshake/secret-handshake-tests.factor" + ], + "example": [ + ".meta/example.factor" + ] + }, + "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", + "source": "Bert, in Mary Poppins", + "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" +} diff --git a/exercises/practice/secret-handshake/.meta/example.factor b/exercises/practice/secret-handshake/.meta/example.factor new file mode 100644 index 0000000..d3fb101 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/example.factor @@ -0,0 +1,10 @@ +USING: combinators kernel math sequences ; +IN: secret-handshake + +CONSTANT: actions { "wink" "double blink" "close your eyes" "jump" } + +: commands ( number -- actions ) + [ actions swap [ swap bit? [ ] [ drop f ] if ] curry map-index sift ] + [ 4 bit? ] + bi + [ reverse ] when ; diff --git a/exercises/practice/secret-handshake/.meta/generator.jl b/exercises/practice/secret-handshake/.meta/generator.jl new file mode 100644 index 0000000..16df0e0 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/generator.jl @@ -0,0 +1,10 @@ +module SecretHandshake + +function gen_test_case(case) + number = to_int_str(case["input"]["number"]) + expected = case["expected"] + actions = isempty(expected) ? "{ }" : format_string_array(expected) + return "{ $(actions) }\n[ $(number) commands ] unit-test" +end + +end diff --git a/exercises/practice/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml new file mode 100644 index 0000000..f318e52 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b8496fbd-6778-468c-8054-648d03c4bb23] +description = "wink for 1" + +[83ec6c58-81a9-4fd1-bfaf-0160514fc0e3] +description = "double blink for 10" + +[0e20e466-3519-4134-8082-5639d85fef71] +description = "close your eyes for 100" + +[b339ddbb-88b7-4b7d-9b19-4134030d9ac0] +description = "jump for 1000" + +[40499fb4-e60c-43d7-8b98-0de3ca44e0eb] +description = "combine two actions" + +[9730cdd5-ef27-494b-afd3-5c91ad6c3d9d] +description = "reverse two actions" + +[0b828205-51ca-45cd-90d5-f2506013f25f] +description = "reversing one action gives the same action" + +[9949e2ac-6c9c-4330-b685-2089ab28b05f] +description = "reversing no actions still gives no actions" + +[23fdca98-676b-4848-970d-cfed7be39f81] +description = "all possible actions" + +[ae8fe006-d910-4d6f-be00-54b7c3799e79] +description = "reverse all possible actions" + +[3d36da37-b31f-4cdb-a396-d93a2ee1c4a5] +description = "do nothing for zero" diff --git a/exercises/practice/secret-handshake/exercism-tools/exercism-tools.factor b/exercises/practice/secret-handshake/exercism-tools/exercism-tools.factor new file mode 100644 index 0000000..df5f692 --- /dev/null +++ b/exercises/practice/secret-handshake/exercism-tools/exercism-tools.factor @@ -0,0 +1,35 @@ +USING: accessors command-line continuations debugger io kernel + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; +IN: exercism-tools + +SYNTAX: STOP-HERE + lexer get [ text>> length ] keep line<< ; + +SYNTAX: TASK: + lexer get next-line ; + +! Label the test that follows with its description. +: description ( str -- ) + "###DESC### " write print ; + +! Print one failure block in a stable, parser-friendly form. +:: print-failure ( failure -- ) + "###FAIL_BEGIN###" print + failure error-location print + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits + "###FAIL_END###" print + flush ; + +: print-failures ( -- ) + test-failures get [ print-failure ] each ; + +: run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global + command-line get first + [ require ] [ test ] bi + test-failures get empty? + [ 0 exit ] [ print-failures 1 exit ] if ; + +MAIN: run-exercism-tests diff --git a/exercises/practice/secret-handshake/secret-handshake/secret-handshake-tests.factor b/exercises/practice/secret-handshake/secret-handshake/secret-handshake-tests.factor new file mode 100644 index 0000000..e4ffae8 --- /dev/null +++ b/exercises/practice/secret-handshake/secret-handshake/secret-handshake-tests.factor @@ -0,0 +1,48 @@ +USING: exercism-tools io kernel secret-handshake tools.test unicode ; +IN: secret-handshake.tests + +"wink for 1" description +{ { "wink" } } +[ 1 commands ] unit-test + +STOP-HERE + +"double blink for 10" description +{ { "double blink" } } +[ 2 commands ] unit-test + +"close your eyes for 100" description +{ { "close your eyes" } } +[ 4 commands ] unit-test + +"jump for 1000" description +{ { "jump" } } +[ 8 commands ] unit-test + +"combine two actions" description +{ { "wink" "double blink" } } +[ 3 commands ] unit-test + +"reverse two actions" description +{ { "double blink" "wink" } } +[ 19 commands ] unit-test + +"reversing one action gives the same action" description +{ { "jump" } } +[ 24 commands ] unit-test + +"reversing no actions still gives no actions" description +{ { } } +[ 16 commands ] unit-test + +"all possible actions" description +{ { "wink" "double blink" "close your eyes" "jump" } } +[ 15 commands ] unit-test + +"reverse all possible actions" description +{ { "jump" "close your eyes" "double blink" "wink" } } +[ 31 commands ] unit-test + +"do nothing for zero" description +{ { } } +[ 0 commands ] unit-test diff --git a/exercises/practice/secret-handshake/secret-handshake/secret-handshake.factor b/exercises/practice/secret-handshake/secret-handshake/secret-handshake.factor new file mode 100644 index 0000000..d80b1a9 --- /dev/null +++ b/exercises/practice/secret-handshake/secret-handshake/secret-handshake.factor @@ -0,0 +1,5 @@ +USING: kernel ; +IN: secret-handshake + +: commands ( number -- actions ) + "unimplemented" throw ;