paulfioravanti's solution

to Secret Handshake in the Elixir Track

Published at Aug 18 2019 · 0 comments
Instructions
Test suite
Solution

There are 10 types of people in the world: Those who understand binary, and those who don't.

You and your fellow cohort of those in the "know" when it comes to binary decide to come up with a secret "handshake".

``````1 = wink
1000 = jump

10000 = Reverse the order of the operations in the secret handshake.
``````

Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.

Here's a couple of examples:

Given the input 3, the function would return the array ["wink", "double blink"] because 3 is 11 in binary.

Given the input 19, the function would return the array ["double blink", "wink"] because 19 is 10011 in binary. Notice that the addition of 16 (10000 in binary) has caused the array to be reversed.

use Bitwise (or div/rem)

If you use Bitwise, an easy way to see if a particular bit is set is to compare the binary AND (`&&&`) of a set of bits with the particular bit pattern you want to check, and determine if the result is the same as the pattern you're checking.

Example:

Flags: 0b11011 Check: 0b11010

Flags &&& Check: 0b11010 (All checked bits are set)

Another:

Flags: 0b11011 Check: 0b10110

Flags &&& Check: 0b10010 (Third bit not set)

Running tests

Execute the tests with:

``````\$ mix test
``````

Pending tests

In the test suites, all but the first test have been skipped.

Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.

For example:

``````# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
``````

Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the test suite.

``````# ExUnit.configure exclude: :pending, trace: true
``````

If you're stuck on something, it may help to look at some of the available resources out there where answers might be found.

Source

Bert, in Mary Poppins http://www.imdb.com/title/tt0058331/quotes/qt0437047

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

secret_handshake_test.exs

``````defmodule SecretHandshakeTest do
use ExUnit.Case

describe "Create a handshake for a number" do
# @tag :pending
test "wink for 1" do
assert SecretHandshake.commands(1) == ["wink"]
end

@tag :pending
test "double blink for 10" do
end

@tag :pending
test "close your eyes for 100" do
assert SecretHandshake.commands(4) == ["close your eyes"]
end

@tag :pending
test "jump for 1000" do
assert SecretHandshake.commands(8) == ["jump"]
end

@tag :pending
test "combine two actions" do
assert SecretHandshake.commands(3) == ["wink", "double blink"]
end

@tag :pending
test "reverse two actions" do
assert SecretHandshake.commands(19) == ["double blink", "wink"]
end

@tag :pending
test "reversing one action gives the same action" do
assert SecretHandshake.commands(24) == ["jump"]
end

@tag :pending
test "reversing no actions still gives no actions" do
assert SecretHandshake.commands(16) == []
end

@tag :pending
test "all possible actions" do
end

@tag :pending
test "reverse all possible actions" do
end

@tag :pending
test "do nothing for zero" do
assert SecretHandshake.commands(0) == []
end

@tag :pending
test "do nothing if lower 5 bits not set" do
assert SecretHandshake.commands(32) == []
end
end
end``````

test_helper.exs

``````ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)``````
``````defmodule SecretHandshake do
use Bitwise

@actions [
{List, :insert_at, [0, "wink"]},
{List, :insert_at, [0, "close your eyes"]},
{List, :insert_at, [0, "jump"]},
{Enum, :reverse, []}
]

@doc """
Determine the actions of a secret handshake based on the binary
representation of the given `code`.

If the following bits are set, include the corresponding action in your list
of commands, in order from lowest to highest.

1 = wink
1000 = jump

10000 = Reverse the order of the operations in the secret handshake
"""
@spec commands(code :: integer) :: list(String.t())
def commands(0), do: []

def commands(code) do
@actions
|> Enum.with_index()
|> Enum.reduce([], &perform_secret_handshake(code, &1, &2))
|> Enum.reverse()
end

defp perform_secret_handshake(code, {{mod, fun, args}, index}, acc) do
if set?(code, index) do
apply(mod, fun, [acc | args])
else
acc
end
end

defp set?(code, index), do: (code &&& mask(index)) > 0

defp mask(number), do: 1 <<< number
end``````