Skip to content

Adding elixir solution #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
elixir_fizz/_build/
elixir_fizz/cover/
elixir_fizz/deps/
elixir_fizz/doc/
elixir_fizz/.fetch
elixir_fizz/erl_crash.dump
elixir_fizz/*.ez
elixir_fizz/elixir_fizz-*.tar
4 changes: 4 additions & 0 deletions elixir_fizz/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
102 changes: 102 additions & 0 deletions elixir_fizz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# FizzBot Elixir Solution

- Requirements for test this solution
- Download dependencies
- Run this solution
- How it works
- ElixirFizz module design

## Requirements for test this solution

1. Install in your computer Elixir (I used 1.8.1 version)

## Download dependencies

For this project I created a mix project because I needed two dependencies for make http requests *httpoison 1.0* and parser the responses *poison 3.1*, that's the reason that I'm using a mix project.

For download this dependencies you need an elixir installation in your computer, and in this directory *fizzbot/elixir_fizz* run:

> mix deps.get

## Run this solution

Elixir have a useful REPL, we should use it for test this project. For run a REPL with this mix project you have to run:

> iex -S mix

Then for test the solution, into the REPL run:

> ElixirFizz.start

```
$ iex -S mix

Erlang/OTP 21 [erts-10.3.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> ElixirFizz.start
```

## How it works

The next step is answer the questions in the REPL. If your answer is *correct* then you will have to answer the next question, but if your answer is *incorrect* you will have to answer again until your answer will be correct.

#### Correct Answer

```
iex(1)> ElixirFizz.start
What is your favorite programming language?
Mine is COBOL, of course.
POST your answer back to this URL in JSON format. If you are having difficulties, see the exampleResponse provided.

Write your answer::_ Elixir

Your answer is: Elixir

Answer Correct!!
Next question...
```

#### Incorrect Answer

```
Your numbers are:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

Write your answer::_ 1 2 Fizz 4 Buzz 6

Your answer is: 1 2 Fizz 4 Buzz 6
Answer is incorrect starting at position 16 ("6")
Try again!!

Write your answer::_
```

## ElixirFizz module design

The *ElixirFizz* elixir module contains many funcions.

The main funcion is *start()* and it's the only public function, this initialize the Fizzbot and start to make the request for answer to this bot.

This are the private functions:

Make the first request to Fizzbot
- `start_fizzbot_for_first_time(starter_uri)`

Ask and answer
- `ask_to_fizzbot(fizzbot)`
- `answer_to_fizzbot({fizzbot, question_uri})`

Input and output functions
- `getting_answer()`
- `show_rules(fizzbot)`

Retry answer when it's wrong
- `validate_answer({fizzbot_answer, fizzbot, question_uri})`

Make and parse requests
- `get(uri)`
- `post(uri)`

If you want to see it you could follow this simple guide for understand how it works, and if you have some questions you can find me at Twitter as @carlogilmar.
1 change: 1 addition & 0 deletions elixir_fizz/config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use Mix.Config
46 changes: 46 additions & 0 deletions elixir_fizz/lib/bot.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule ElixirFizz.Bot do

def answer({_fizzbot, false}), do: "Elixir"
def answer({fizzbot, true}), do: generate_answer(fizzbot, length(fizzbot["rules"]))

defp generate_answer(fizzbot, 2) do
[numberA, numberB] = fizzbot["rules"]
tokens =
for number <- fizzbot["numbers"] do
fizzbuzz({number, rem(number, numberA["number"])== 0, numberA["response"], rem(number, numberB["number"]) == 0, numberB["response"]})
end
Enum.join(tokens, " ")
end

defp generate_answer(fizzbot, 3) do
[numberA, numberB, numberC] = fizzbot["rules"]
tokens =
for number <- fizzbot["numbers"] do
fizzbot({ number,
rem(number, numberA["number"])== 0,
numberA["response"],
rem(number, numberB["number"]) == 0,
numberB["response"],
rem(number, numberC["number"]) == 0,
numberC["response"]
})
end
Enum.join(tokens, " ")
end

defp fizzbuzz({number, false, _numberA, false, _numberB}), do: "#{number}"
defp fizzbuzz({_number, true, numberA, false, _numberB}), do: numberA
defp fizzbuzz({_number, false, _numberA, true, numberB}), do: numberB
defp fizzbuzz({_number, true, numberA, true, numberB}), do: "#{numberA}#{numberB}"


defp fizzbot({_number, true, respA, true, respB, true, respC}), do: "#{respA}#{respB}#{respC}"
defp fizzbot({_number, true, respA, false, _respB, false, _respC}), do: respA
defp fizzbot({_number, false, _respA, true, respB, false, _respC}), do: respB
defp fizzbot({_number, false, _respA, false, _respB, true, respC}), do: respC
defp fizzbot({number, false, _respA, false, _respB, false, _respC}), do: number
defp fizzbot({_number, true, respA, true, respB, false, _respC}), do: "#{respA}#{respB}"
defp fizzbot({_number, true, respA, false, _respB, true, respC}), do: "#{respA}#{respC}"
defp fizzbot({_number, false, _respA, true, respB, true, respC}), do: "#{respB}#{respC}"

end
79 changes: 79 additions & 0 deletions elixir_fizz/lib/elixir_fizz.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
defmodule ElixirFizz do
alias ElixirFizz.Bot

@base_url "https://api.noopschallenge.com"

# Only you have to open the iEX in this project and:
#
# > iex -S mix
#
# Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)
# iex(1)> ElixirFizz.start
#
def start() do
start_time = :os.system_time(:millisecond)
"/fizzbot"
|> start_fizzbot_for_first_time()
|> ask_to_fizzbot()
end_time = :os.system_time(:millisecond)
duration = (end_time - start_time)/1000
IO.puts "Interview finalized in #{duration} seconds"
end

defp start_fizzbot_for_first_time(starter_uri), do: get(starter_uri)

defp ask_to_fizzbot(fizzbot) do
next_fizzbot = get(fizzbot["nextQuestion"])
show_rules(next_fizzbot)
answer = Bot.answer({next_fizzbot, Map.has_key?(next_fizzbot, "numbers")})
answer_to_fizzbot({next_fizzbot, fizzbot["nextQuestion"], answer})
end

defp answer_to_fizzbot({fizzbot, question_uri, answer}) do
IO.puts "\nSe generó la siguiente respuesta: #{answer}"
fizzbot_answer = post(question_uri, %{"answer" => answer})
validate_answer({fizzbot_answer, fizzbot, question_uri})
end

defp show_rules(fizzbot) do
validate_rules = fn
true ->
IO.puts ":: GitHub :: Meet the Noobs :: Fizzbot Message ::"
IO.puts fizzbot["message"]
IO.puts "The rules are:"
IO.inspect fizzbot["rules"]
IO.puts "\nYour numbers are:"
IO.inspect fizzbot["numbers"]
false ->
IO.puts fizzbot["message"]
end
validate_rules.(Map.has_key?(fizzbot, "rules"))
end

defp validate_answer({fizzbot_answer, fizzbot, question_uri}) do
validate_fizzbot = fn
"correct" ->
IO.puts "\nAnswer Correct!!"
IO.puts "Next question...\n"
ask_to_fizzbot(fizzbot_answer)
"incorrect" ->
IO.puts fizzbot_answer["message"]
IO.puts "Try again!!"
answer_to_fizzbot({fizzbot, question_uri})
"interview complete" ->
IO.puts " DONE "
end
validate_fizzbot.(fizzbot_answer["result"])
end

defp get(uri) do
{:ok, response} = HTTPoison.get("#{@base_url}#{uri}")
Poison.decode!(response.body)
end

defp post(uri, body) do
{:ok, response} = HTTPoison.post("#{@base_url}#{uri}", Poison.encode!(body), [{"Content-type", "application/json"}])
Poison.decode!(response.body)
end

end
26 changes: 26 additions & 0 deletions elixir_fizz/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule ElixirFizz.MixProject do
use Mix.Project

def project do
[
app: :elixir_fizz,
version: "0.1.0",
elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

def application do
[
extra_applications: [:logger]
]
end

defp deps do
[
{:httpoison, "~> 1.0", override: true},
{:poison, "~> 3.1"}
]
end
end
12 changes: 12 additions & 0 deletions elixir_fizz/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
%{
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
}