Reputation: 54
I am working on writing a code for cows and bulls game. Here is my code so far.
defmodule Demo do
def game() do
guess = 1234
secret = Enum.take_random(1..9, 4)
count(guess, secret)
end
defp count(guess, secret) do
Enum.zip(guess, secret)
|> Enum.reduce({0, 0}, fn {g, s}, {c, b} ->
cond do
g == s -> {c, b + 1}
g in secret -> {c + 1, b}
true -> {c, b}
end
end)
end
end
When I am running the file using IO.puts Demo.game
I am getting the following error
(Protocol.UndefinedError) protocol Enumerable not implemented for 1234
(elixir) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) lib/enum.ex:141: Enumerable.reduce/3
(stdlib) lists.erl:1338: :lists.foreach/2
(elixir) lib/stream.ex:1157: Stream.do_zip/3
(elixir) lib/enum.ex:2802: Enum.zip/1
prog.ex:10: Demo.count/2
prog.ex:20: (file)
Help me understand where I went wrong and how to clear the error
Edit:
I changed the cond condition to how you suggested. But instead of using Integer.digits I converted the randomly generated list to string to make it enumerable but I am facing an error. The code looks like this.
defmodule Demo do
def game() do
guess = Integer.digits(1234)
secret = Enum.take_random(1..9, 4) |> Enum.map(&to_string/1)
numOfBullsCows(guess, secret)
end
def numOfBullsCows(guess, secret) do
Enum.zip(guess, secret)
|> Enum.reduce({0, 0}, fn
{g, g}, {c, b} -> {c, b + 1}
{g, _}, {c, b} when g in secret -> {c + 1, b}
_, {c, b}-> {c, b}
end)
end
end
The error:
(ArgumentError) invalid args for operator "in", it expects a compile-time proper list or compile-time range on the right side when used in guard expressions, got: secret
(elixir) expanding macro: Kernel.in/2
prog.ex:14: Demo.numOfBullsCows/2
(elixir) expanding macro: Kernel.|>/2
prog.ex:12: Demo.numOfBullsCows/2
I have also tried it in another way where I created two seperate functions to check for duplicates and then to generate a random number with no duplicate digit in it.
defmodule Main do
def noDuplicates(num) do
num_li = Integer.digits(num)
length(num_li) == length(Enum.uniq(num_li))
end
def generateNum() do
num = Enum.random(1000, 9999)
if noDuplicates(num) == true do
IO.puts(num)
else
generateNum()
end
end
end
But I am getting an error like this
(UndefinedFunctionError) function Enum.random/2 is undefined or private. Did you mean one of:
* random/1
(elixir) Enum.random(1000, 9999)
prog.ex:8: Main.generateNum/0
prog.ex:17: (file)
(elixir) lib/code.ex:767: Code.require_file/2
Upvotes: 0
Views: 346
Reputation: 121010
Enum.zip/2
expects two enumerables as arguments and you pass 1234, [3, 5, 1, 6]
or like (the latter is randomly generated secret
, the list of size 4
) there.
Use Integer.digits/2
to split the integer into digits so that Enum.zip/2
was happy.
Sidenote: instead of using cond/1
, it’s more idiomatic to use several function clauses
...
|> Enum.reduce({0, 0}, fn
# ⇓ ⇓ same name matches when they are equal
{g, g}, {c, b} -> {c, b + 1}
# ⇓⇓⇓⇓ guard
{g, _}, {c, b} when g in secret -> {c + 1, b}
# catch-all
_, {c, b} -> {c, b}
end)
Upvotes: 2