small medium large xlarge

Dave_gnome_head_isolated_pragsmall
16 Jul 2013, 02:25
Dave Thomas (387 posts)
  • I’m thinking of a number between 1 and 1000…

    The most efficient way to find the number is to guess halfway between the low and high numbers of the range. If our guess is too big, then the answer lies between the bottom of the range and one less than our guess. If it is too small, then the answer lies between one more than our guess and the end of the range.

    Code this up. Your API will be guess(actual, range), where range is an Elixir range.

    Your output should look similar to:

    iex> Chop.guess(273, 1..1000)
    Is it 500
    Is it 250
    Is it 375
    Is it 312
    Is it 281
    Is it 265
    Is it 273
    273
    

    Hints:

    • You may need to implement helper functions with an additional parameter (the currently guessed number).
    • the div(a,b) function performs integer division
    • guard clauses are your friends
    • patterns can match the low and high parts of a range (a..b=4..8) === {::comment} defmodule Chop do def guess(actual, range = low..high) do guess = div(low+high, 2) IO.puts “Is it #{guess}” guess(actual, guess, range) end

    def guess(actual, actual, _), do: actual def guess(actual, guess, _low..high) when guess < actual, do: guess(actual, guess+1..high) def guess(actual, guess, low.._high) when guess > actual, do: guess(actual, low..guess-1) end {:/comment}

</yourturn>

A Possible Solution</summary>

defmodule Chop do
  def guess(actual, range = low..high) do 
    guess = div(low+high, 2)
    IO.puts "Is it #{guess}?"
    _guess(actual, guess, range)
  end

  defp _guess(actual, actual, _), 
    do: IO.puts "Yes, it's #{actual}"

  defp _guess(actual, guess,  _low..high)
    when guess < actual,
    do: guess(actual, guess+1..high)

  defp _guess(actual, guess,  low.._high) 
    when guess > actual, 
    do: guess(actual, low..guess-1)
end

Chop.guess(273, 1..1000)

</details>

Generic-user-small
01 Aug 2013, 20:32
Luke Imhoff (6 posts)

My solution:


defmodule Chop do
  def guess(actual, range) do
    n = next_guess(range)
    check_guess(actual, range, n)
  end

  defp next_guess(low..high) do
    difference = high - low
    guess = div(difference, 2) + low
    
    IO.puts "Is it #{guess}"
    
    guess
  end
  
  defp check_guess(actual, _, current_guess) when current_guess == actual do
    actual
  end
  
  defp check_guess(actual, low.._, current_guess) when current_guess > actual do
    high = current_guess - 1
    n = next_guess(low..high)
    check_guess(actual, low..high, n)
  end
  
  defp check_guess(actual, _..high, current_guess) when current_guess < actual do
    low = current_guess + 1
    n = next_guess(low..high)
    check_guess(actual, low..high, n)
  end
end ---

P.S. What mark up do I use to make a hidden thing Dave like your “A Possible Solution”? It’s not standard Markdown, so it must be something specific to this forum.

Dave_gnome_head_isolated_pragsmall
02 Aug 2013, 14:09
Dave Thomas (387 posts)

I use details/summary tags

Generic-user-small
29 Aug 2013, 12:03
Nathan J Schunemann (1 post)

I can’t figure out how to hide a code block with details/summary tags. Elixir 0.10.1

defmodule Chop do
  def guess(actual, low..high)
    when actual == div(low+high, 2) do
      IO.puts "Is it #{actual}?"
      IO.puts "Yes, it's #{actual}."
  end
 
  def guess(actual, low..high)
    when actual < div(low+high, 2) do
      IO.puts "Is it #{div(low+high, 2)}?"
      guess(actual, low..div(low+high, 2))
  end
 
  def guess(actual, low..high)
    when actual > div(low+high, 2) do
      IO.puts "Is it #{div(low+high, 2)}?"
      guess(actual, div(low+high, 2)..high)
  end
end
Generic-user-small
15 Oct 2013, 15:08
Raoul JP Bonnal (1 post)

Hi Dave, your solution uses defp which is described later in chapter 7. I figured it out only looking the solution into this forum.

Generic-user-small
29 Nov 2013, 18:02
Kit Ko (3 posts)

The syntax of defining a function that calls itself is also described later in chapter 7.

Snapshot_2008101_248x248_pragsmall
24 Dec 2013, 06:26
Rafael Rosa (2 posts)

I’m still on chapter 6, but when I looked at your proposed solution I was stunned with the matching of parameters on the right hand of the = sign (range = low..high), it’s amazing but it only works on parameter definition and I didn’t see any explanation on that so far. Granted, it isn’t necessary to answer the Chop exercise, but I would expect such explanation under “Function Calls and Pattern Matching” that starts on page 45.

As a side note, so far I’m enjoying the book very much, thanks a bunch.

Mva.2008.05_pragsmall
05 Feb 2014, 03:34
Manuel E Vidaurre Arenas (7 posts)

My solution:


defmodule Chop do
  def guess(x, a..b) when x == div(a+b, 2) do
    IO.puts "Is it #{x}"
    IO.puts "#{x}"
  end
  def guess(x, a..b) when x < div(a+b, 2) do
    n = div(a+b, 2)
    IO.puts "Is it #{n}"
    guess(x, a..n)
  end
  def guess(x, a..b) when x > div(a+b, 2) do
    n = div(a+b, 2)
    IO.puts "Is it #{n}"
    guess(x, n..b)
  end
end

It’s very similar to Nathan J Schunemann solution

Generic-user-small
26 Mar 2014, 18:01
Christian Broomfield (1 post)

My solution is virtually identical with Luke’s answer, but I didn’t use defp. Not sure if that’s important, but the program compiled just fine (0.12.5).

I tried to code a similar solution in Kotlin and ended up with this:

tailRecursive
fun guess(answer: Int, range: Range<Int>, candidate: Int = (range.end - range.start) / 2 + range.start): Int =
    when {
        answer == candidate -> candidate
        answer > candidate  -> guess(answer, (candidate + 1)..range.end)
        answer < candidate  -> guess(answer, range.start..(candidate - 1))
        else                -> throw IllegalArgumentException("Computational error occurred; check the math please.")
    }

I like this solution a lot and attempted to code this solution in Elixir:

defmodule Chop do
  def guess(answer, from..to, candidate \\ div(to - from, 2) + from) when candidate == answer do
    answer
  end

  def guess(answer, from..to, candidate \\ div(to - from, 2) + from) when candidate > answer do
    guess(answer, (candidate + 1)..to)
  end

  def guess(answer, from..to, candidate \\ div(to - from, 2) + from) when candidate < answer do
    guess(answer, from..(candidate - 1))
  end

  def guess(answer, from..to) do
    guess(answer, from..to)
  end
end

The first thing that struck me is, “There has to be an easier way” than defining four function and separating them with almost nothing but a different operator in the when clause. Secondly, the code fails with the error message:

** (CaseClauseError) no case clause matching: nil
    (elixir) src/elixir_scope.erl:22: :elixir_scope.translate_var/4
    (elixir) src/elixir_translator.erl:302: :elixir_translator.translate_arg/3
    (stdlib) lists.erl:1339: :lists.mapfoldl/3
    (elixir) src/elixir_translator.erl:209: :elixir_translator.translate/2
    (elixir) src/elixir_translator.erl:302: :elixir_translator.translate_arg/3
    (stdlib) lists.erl:1339: :lists.mapfoldl/3
    (elixir) src/elixir_translator.erl:209: :elixir_translator.translate/2
    (elixir) src/elixir_translator.erl:302: :elixir_translator.translate_arg/3
Me_pragsmall
05 Jun 2014, 16:23
Paul Barry (3 posts)

I can’t help uploading my solution for all to see, as - to be honest - I’m chuffed that it worked. :-) I’ve added a few additional messages on output to help show what’s going on:

defmodule Chop do

  def guess(target, x..y) do
    midpoint = halfway(x, y)
    match(target, x, y, midpoint)
  end

  defp halfway(x, y), do: div(y-x, 2) + x

  defp match(target, _x, _y, target), do: target

  defp match(target, x, _y, midpoint) when target < midpoint do
    IO.puts "Is it #{midpoint}?\tNo, lower."
    guess(target, x..midpoint)
  end
  
  defp match(target, _x, y, midpoint) do # in the upper range.
    IO.puts "Is it #{midpoint}?\tNo, higher."
    guess(target, midpoint..y)
  end

end

When you run my code, here’s what you see:

iex(1)> Chop.guess(273, 1..1000)
Is it 500?      No, lower.
Is it 250?      No, higher.
Is it 375?      No, lower.
Is it 312?      No, lower.
Is it 281?      No, lower.
Is it 265?      No, higher.
273
Generic-user-small
19 Jun 2014, 05:50
Rodrigo Salado Anaya (2 posts)

My solution based in the Dave T. solution.

defmodule Game do
  def guess(resp, low..high)
  when resp < low or resp > high do
    IO.puts "[error] Use a value between #{low} and #{high}."
  end

  def guess(resp, low..high) do
    guess = div(low+high, 2)
    IO.puts "Is it #{guess}"
    _find(resp, guess, low, high)
  end

  defp _find(resp, resp, _, _), do: IO.puts "-> #{resp}"

  defp _find(resp, guess, low, _)
  when guess > resp do
    guess(resp, low..guess - 1)
  end 

  defp _find(resp, guess, _, high)
  when guess < resp do
    guess(resp, guess + 1..high)
  end
end

Game.guess(20, 0..100)
Game.guess(20, 50..100)
Game.guess(50, 50..100)
Game.guess(100, 50..100)
9863_pragsmall
05 Dec 2014, 21:15
Suraj Kurapati (8 posts)

My solution is to narrow down the range of possibilities with every guess and finally converge on the actual value.

defmodule Chop do
  def guess(actual, actual.._), do: actual
  def guess(actual, _..actual), do: actual
  def guess(actual, low..high) do
    midpoint = low + div(high - low, 2)
    IO.puts "Is it #{midpoint}?"
    if actual < midpoint do
      guess actual, low..midpoint
    else
      guess actual, midpoint..high
    end
  end
end
Blacksad-cov_sq_pragsmall
14 Sep 2014, 09:41
Porco Wong (3 posts)

This is my solution:

defmodule Chop do
  def guess(actual, low..high) when actual > low and actual< high do
    _guess(actual, low..high, div(low + high, 2))
  end

  defp _guess(actual, _, curr) when curr == actual do
    IO.puts "Is it #{curr}"
    IO.puts curr
  end

  defp _guess(actual, low..high, curr) when curr < actual do
    IO.puts "Is it #{curr}"
    _guess actual, curr..high, div(curr + high, 2)
  end

  defp _guess(actual, low..high, curr) when curr > actual do
    IO.puts "Is it #{curr}"
    _guess actual, low..curr, div(low + curr, 2)
  end
end
Generic-user-small
22 Nov 2014, 01:38
lv cheng peng (4 posts)
defmodule Chop do
  def guess(num, low..high) when num > div(high + low, 2) do
    IO.puts "Is it #{div(high + low, 2)}"
    guess(num, div(high + low, 2)..high)
  end
  def guess(num, low..high) when num < div(high + low, 2) do
    IO.puts "Is it #{div(high + low, 2)}"
    guess(num, low..div(high + low, 2))
  end
  def guess(num, low..high) do
    IO.puts num
  end  
end

Chop.guess(273, 1..1000)
Generic-user-small
24 Dec 2014, 01:09
Pierre Sugar (57 posts)

And another one

 
defmodule Guess do

  def is(number, guess, _a..b) when number > guess do
    it(number, (guess+1)..b)
  end

  def is(number, guess, a.._b) when number < guess do
    it(number, a..(guess-1))
  end

  def is(number, guess, _a.._b) when number == guess do
    IO.puts guess
  end

  def it(number, a..b = range) when a <= number and b >= number do
    guess = div(b-a,2) + a
    IO.puts "Is it #{guess}?"
    is(number, guess, range)
  end
end

4470516_pragsmall
25 Dec 2014, 08:32
Cifer Y (3 posts)
defmodule Chop do
  def guess(num, range) do
    guess(num, range, 0)
  end

  defp guess(num, range, guess) when num == guess do
    IO.puts "It is #{guess}!"
  end

  defp guess(num, range, guess) when guess > num do
    min.._ = range
    new_range = min..guess
    next_guess = mid(new_range)
    IO.puts "Is it #{next_guess}?"
    guess(num, new_range, next_guess)
  end

  defp guess(num, range, guess) when guess < num do
    _..max = range
    new_range = guess..max
    next_guess = mid(new_range)
    IO.puts "Is it #{next_guess}?"
    guess(num, new_range, next_guess)
  end

  defp mid(range) do
    min..max = range
    mid = div(min + max, 2)
    mid
  end
end

Generic-user-small
17 Jan 2015, 04:09
Anonymous (1 post)
defmodule Chop do
  def guess(actual, _, actual), do: IO.puts "Yes, it's #{actual}"
  def guess(actual, low.._, guess) when guess > actual, do: guess(actual, low..guess-1)
  def guess(actual, _..high, guess) when guess < actual, do: guess(actual, guess+1..high)
  def guess(actual, low..high) do
    guess = div(low+high, 2)
    IO.puts "Is it #{guess}?"
    guess(actual, low..high, guess)
  end
end
Generic-user-small
22 Feb 2015, 12:11
Abdulaziz AlShetwi (1 post)
defmodule Chop do
  def guess actual, range = low..high do
    current = div(high+low, 2)
    IO.puts "Is it #{current}"
    isit(current, actual, range)
  end
  
  def isit(current, actual, low.._high )
  when current > actual do
    guess(actual, low..current-1)
  end

  def isit(current, actual, _low..high)
  when current < actual do
    guess(actual, current+1..high)
  end

  # borrow this idea from Mr. Dave .. this is so clever :)
  def isit(actual, actual, _) do
   IO.puts "Yes it is #{actual}"
  end
  
end

Chop.guess 273, 1..1000
Generic-user-small
28 Mar 2015, 18:47
philippe tseyen (4 posts)
defmodule Chop do
  def evaluate(actual, guess, _) when guess == actual do
    IO.puts "Is it #{guess}"
    guess
  end

  def evaluate(actual, guess, a..b) when guess < actual do
    IO.puts "Is it #{guess}"
    new_range = guess..b
    new_guess = mid(new_range)
    evaluate(actual, new_guess, new_range)
  end

  def evaluate(actual, guess, a..b) when guess > actual do
    IO.puts "Is it #{guess}"
    new_range = a..guess
    new_guess = mid(new_range)
    evaluate(actual, new_guess, a..guess)
  end

  def guess(actual, a..b) do
    first_guess = mid(a..b)
    evaluate(actual, first_guess, a..b)
  end

  def mid(a..b) do
    div(a+b,2)
  end
end
Generic-user-small
10 Jul 2015, 12:51
Michael Anthony (2 posts)

I think I might have messed up by using cond do since no one else did. It’s so concise though…

defmodule Chop do
  def guess(actual, h..t) do
    g = div((t - h), 2) + h
    IO.puts "Is it #{g}"
    cond do
      g == actual -> actual
      g < actual -> guess(actual, g + 1..t)
      g > actual -> guess(actual, h..g - 1)
    end
  end
end
iex> Chop.guess 783, 1..1000
Is it 500
Is it 750
Is it 875
Is it 812
Is it 781
Is it 796
Is it 788
Is it 784
Is it 782
Is it 783
783
20160310-gunnar_pragsmall
16 Jul 2015, 04:54
Felipe Juarez Murillo (9 posts)

My solution is not that elegant.. but still works but definitely I should swtich to Nathan J Schunemann solution

defmodule Chop do
  def guess(x, min..max) do
    guessing(x, min, max)
  end
  
  def guessing(x, min, max) when x < div(max+min, 2) do
    IO.puts "Is it #{div(max + min, 2)}"
    guessing(x, min, div(max + min, 2))
  end
  
  def guessing(x, min, max) when x > div(max+min, 2) do
    IO.puts "Is it #{div(max + min, 2)}"
    guessing(x, div(max + min, 2), max)
  end
  
  def guessing(x, min, max) when x == div(max+min, 2) do
    IO.puts "Is it #{div(max + min, 2)}"
    IO.puts "#{div(max + min, 2)}"
  end
end
Dsc_0232 - copy_pragsmall
22 Jul 2015, 18:46
Srikanth P Shreenivas (3 posts)

My first version was close to what Dave has proposed.

defmodule Chop do
	def guess(m, a..b) do		
		check_guess(div(a+b,2), m, a..b)
	end
	def check_guess(g, m, _a.._b) when m == g do
		IO.puts "It is #{g}"
	end
	def check_guess(g, m, _a..b) when m > g do
		IO.puts "Is it #{g}?"
		guess(m, g..b)
	end
	def check_guess(g, m, a.._b) when m < g do
		IO.puts "Is it #{g}?"
		guess(m, a..g)
	end
end

Chop.guess(273, 1..1000)
Generic-user-small
06 Aug 2015, 12:52
Justin Smead (1 post)

I came up with about the same answer as Srikanth: I’m really enjoying Elixir so far. An ex-coworker and I have plans to build a few websites using Aurelia and Elixir so this is my way of getting prepared for the task.

defmodule Chop do
  def guess(x, a..b), do: guess(x, a..b, div((a + b), 2))
  def guess(x, a..b, c) when c > x do
     IO.puts "Is it #{c} ... no to high"
     guess(x, a..(c-1))
  end
  def guess(x, a..b, c) when c < x do
    IO.puts "Is it #{c} ... no to low"
    guess(x, (c+1)..b)
  end
  def guess(x, a..b, c) when c == x do
    IO.puts "Is it #{c} ... Why yes it is!!"j
  end
end

Generic-user-small
06 Aug 2015, 16:14
Agung Prasetyo (2 posts)

This is my version, elixir so surprising me :)

defmodule Chop do
  def guess(n, range) do
    determine n, middle(range), range
  end

  def determine(current, guessed, range) when current < guessed do
    IO.puts "It is #{guessed}"
    first..last = range
    determine current, middle(first..guessed), first..guessed
  end

  def determine(current, guessed, range) when current > guessed do
    IO.puts "It is #{guessed}"
    first..last = range
    determine current, middle(guessed..last), guessed..last
  end

  def determine(current, guessed, _) when current == guessed do
    IO.puts current
  end

  defp middle(range) do
    first..last = range
    div((first + last), 2)
  end
end

Generic-user-small
28 Aug 2015, 22:52
Pete Nicholls (1 post)

My naive version:

defmodule Chop do
  def guess(answer, low..high) do
    guess(answer, high, low, high)
  end

  def guess(answer, answer, _, _) do
    IO.puts "It is #{answer}!"
  end

  def guess(answer, number, low, high) when answer < number do
    IO.puts "It's lower than #{number}, but higher than #{low}"
    guess(answer, number - div(number - low, 2), low, number)
  end

  def guess(answer, number, low, high) when answer > number do
    IO.puts "It's higher than #{number}, but lower than #{high}"
    guess(answer, number + div(high - number, 2), number, high)
  end
end
Avatar_pragsmall
01 Dec 2015, 02:14
Jaroslaw Zabiello (6 posts)
defmodule Chop do
  def guess(actual, low..high) do
    n = div(low+high, 2)
    IO.puts "Is it #{n}?"
    cond do
      actual > n  -> guess(actual, n..high)
      actual < n  -> guess(actual, low..n)
      true        -> IO.puts "It's #{actual}!"
    end
  end
end

Chop.guess 273, 1..1000
Generic-user-small
20 Dec 2015, 14:19
Nathan Hornby (5 posts)

I needed to have a quick look at the recommended solution to get a general gist of the logic - but I just about managed a slightly less efficient solution on (almost) my own. It’s the maths/logic I struggle with more than the language!

After bringing it in line I ended up building in some more protection, as you say;

Guard clauses are your friends.

def guess(actual, range = low..high) when is_number(actual) and is_map(range) do
    if(actual >= low and actual <= high) do
      guess = div(low + high, 2)
      IO.puts "Is it… #{guess}?"
      guess_attempt(actual, guess, range)
    else
      IO.puts "Nice try, Neo."
    end
  end

This allows for negative numbers, but NOT Chop.guess(-37, 5..27).

Generic-user-small
25 Dec 2015, 21:52
Donald Kelly (2 posts)

It’s easier to check for valid calls with a “when actual in low..high” clause on the main guess function. That rejects any cases of type mismatches as well as actual values outside the supplied range.

Generic-user-small
15 Jan 2016, 11:19
Gorav Bhootra (1 post)

My Solution:

defmodule Chop do
  def guess(n, low..high)  do
    match(n, low..high, midpoint(low..high))
  end

  def match(n, _, mid) when n == mid do
    IO.puts "Is it #{n}"
    IO.puts n
  end

  def match(n, low.._, mid) when n < mid do
    IO.puts "Is it #{mid}"
    match(n, low..mid, midpoint(low..mid))
  end

  def match(n, _..high, mid) when n > mid do
    IO.puts "Is it #{mid}"
    match(n, mid..high, midpoint(mid..high))
  end

  def midpoint(low..high), do: div((high+low),2)
end
Generic-user-small
17 Jan 2016, 04:49
Makoto Abe (1 post)

defmodule Chop do

    def guess(actual,_..actual) do
        IO.puts "#{actual}"
    end
    def guess(actual,min..max) when div(max+min,2) >= actual do
        max = div(max+min,2)
        IO.puts "Is it #{max}"
        guess(actual,min..max)
    end    
    def guess(actual,min..max) when div(max+min,2) < actual do
        min = div(max+min,2)
        IO.puts "Is it #{min}"
        guess(actual,min..max)
    end
end
Generic-user-small
03 Feb 2016, 07:26
Stefan Houtzager (8 posts)

I found this the nicest excersise till now (I’m in chapter 6). I had to use a combination of the knowledge gained in previous chapters. Working with the tutorial for 1.2, only using the language learned till the exercise:

defmodule Chop do:
   def guess(prevguess \\ 0, nr, range) 

   def guess(prevguess, nr, first..last) when nr === last do
     IO.puts "It is #{last}"
   end

   def guess(prevguess, nr, first..last) when nr in first..last do
     g = last - div(last - first, 2) - 1
     IO.puts "Is it#{g}?"
     guess(last, nr, first..g)
   end    

   def guess(prevguess, nr, first..last) when nr > last do
     g = prevguess - div(last - first, 2) - 1
     IO.puts "Is it#{g}?"
     guess(prevguess, nr, (last + 1)..g)
   end    
end
Generic-user-small
13 Feb 2016, 17:43
Alex Deva (4 posts)

Here’s mine. The “Is it…?” is only printed once. I’m not sure how appropriately “functional” my solution is; it would work fine in Ruby with some word-to-word translations.

defmodule Chop do
  def continue(number, middle, _..b) when number > middle, do: guess(number, middle..b)

  def continue(number, middle, a.._) when number < middle, do: guess(number, a..middle)

  def continue(number, middle, _) when number == middle, do: IO.puts number

  def guess(number, a..b) do
    middle = div(a+b, 2)
    IO.puts "Is it #{middle}"

    continue(number, middle, a..b)
  end
end
Generic-user-small
14 Feb 2016, 17:44
Nathan Hessler (10 posts)

Here is my solution. I’m adding it because I added a guard clause to the main guess/2 method to validate that actual is in the range. this took a while to figure out as you can’t just say actual in range you must make the range explicit using low..high.

defmodule Chop do
  def guess(actual, low..high) when actual in low..high do
    candidate = div(low + high, 2)
    IO.puts "Is it #{candidate}"
    _guess(actual, candidate, low..high)
  end

  def _guess(actual, candidate, _low..high) when candidate < actual do
    new_low = candidate + 1
    guess(actual, new_low..high)
  end

  def _guess(actual, candidate, low.._high) when candidate > actual do
    new_high = candidate - 1
    guess(actual, low..new_high)
  end

  def _guess(_actual, candidate, _low.._high), do: candidate
end
Generic-user-small
28 Feb 2016, 22:31
Dorian Iacobescu (1 post)

My solution:

defmodule Chop do
  def guess(initial, a..b) do
    guessing(initial, a, b)
  end

  def guess(initial, _, actual) when initial == actual do
    actual
  end

  def guess(initial, a.._b, actual) when initial < actual do
    guessing(initial, a, actual-1)
  end

  def guess(initial, _a..b, actual) when initial > actual do
    guessing(initial, actual+1, b)
  end

  defp guessing(initial, a, b) do
    actual = div(a+b,2)
    IO.puts "is it #{actual} ?"
    guess(initial, a..b, actual)
  end
end
Generic-user-small
01 Mar 2016, 04:54
Joseph Lozano (1 post)
defmodule Chop do
  def guess(actual, lower..upper) do
    half = div((upper + lower), 2)
    IO.puts "Is it #{half}"
    cond do
      actual < half  -> guess(actual, lower..half)
      actual > half  -> guess(actual, half..upper)
      actual == half -> actual
    end
  end
end
Dariuszgawdzikphoto_pragsmall
18 Apr 2016, 01:39
Dariusz Gawdzik (1 post)

If we don’t use conditional statements:

defmodule BinarySearch do

  def guess(n, n..n), do: IO.puts n # Base Case: n could be matched.

  def guess(n, low..high) when n > high or n < low, do: nil # Base Case: n is outside of the range.

  def guess(n, low..high) do # Recursive Case: Find middle and recursively call with two subranges.
      middle = div(high - low, 2) + low
      IO.puts "Is it #{middle}?"
      guess(n, low..middle) || guess(n, middle+1..high)
  end

end

Generic-user-small
29 Apr 2016, 14:44
Felix Schmiedecke (1 post)

My solution

defmodule Chop do
    def guess(actual, range) do
        first..last = range
        center = div (first + last), 2
        IO.puts "Is it #{center}"
        cond do 
             actual == last -> IO.puts actual
             actual == center -> IO.puts actual
             actual < center -> last = center
                                guess(actual, first..last)
             actual > center -> first = center
                                guess(actual, first..last)     
        end
    end
end
Generic-user-small
30 Apr 2016, 12:51
Filipe Dias (1 post)

Here’s my solution. It’s similar to Dave Thomas’ solution and so many others already here. The main diference is to check if the range is the correct order and revert it if not.

defmodule Chop do
  def guess(actual, _, actual) do
    actual
  end

  def guess(actual, _..max, gvalue) when actual > gvalue do
    guess(actual, gvalue..max)
  end

  def guess(actual, min.._, gvalue) when actual < gvalue do
    guess(actual, min..gvalue)
  end

  def guess(actual, min..max) when max >= min and actual in min..max do
    gvalue = div(max - min,2) + min
    IO.puts "Is it #{gvalue}"
    guess(actual, min..max, gvalue)
  end

  def guess(actual, min..max) when min > max and actual in min..max do
    guess(actual, max..min)
  end
end
Generic-user-small
05 May 2016, 03:08
Jason Douglas Brown (1 post)

Solution with ugly repetition

How can this be refactored to get rid of repeated div(low + high, 2)?

defmodule Chop do
  def guess(actual, low..high) when (actual == low) or (actual == high), do: (
    IO.puts "got it! - #{actual}")

  def guess(actual, low..high) when actual >= div(low + high, 2), do: (
    IO.puts "#{actual} - #{low} - #{high}"
    guess(actual, div(low + high,2)..high))

  def guess(actual, low..high) when actual <= div(low + high, 2), do: (
    IO.puts "#{actual} - #{low} - #{high}"
    guess(actual, low..div(low + high,2)))
end

Generic-user-small
07 May 2016, 18:09
Wioleta Jemieljańczuk (2 posts)
defmodule Chop do

  def guess(actual, a..b) do
    guess(actual, div(a+b,2), a..b)
  end

  def guess(actual, guess, actual.._) do
    IO.puts "Funny... #{actual}"
  end

  def guess(actual, guess, _..actual) do
    IO.puts "Funny... #{actual}"
  end

  def guess(actual, actual, a..b) do
    IO.puts "It's #{actual}!"
  end

  def guess(actual, guess, a..b) when actual < guess do
    IO.puts "It's #{guess}!"
    guess(actual, a..guess)
  end

  def guess(actual, guess, a..b) when actual > guess do
    IO.puts "It's #{guess}!"
    guess(actual, guess..b)
  end

end

probably needs some cleaning up, but I’m not sure how to do that yet ;D

10835006_10205472057993947_8823512831789168903_o_pragsmall
29 May 2016, 16:01
Yedhu Krishnan (1 post)

My Solution:

defmodule Chop do
  def guess(actual, min..max) when actual == div(max + min, 2) do
    IO.puts("No, it is #{actual}")
  end

  def guess(actual, min..max) when actual > div(max + min, 2) do
    IO.puts("Is it #{div(max + min, 2)}?")
    guess(actual, (div(max + min, 2)..max))
  end

  def guess(actual, min..max) when actual < (min + div(max - min, 2)) do
    IO.puts("Is it #{div(max + min, 2)}?")
    guess(actual, min..div(max + min, 2))
  end
end

The hints were actually useful. It took some time for me to come up with this version of solution, but it was worth solving it.

Generic-user-small
29 May 2016, 21:51
Nico Ritsche (1 post)
defmodule Chop do

  def guess(actual, a..b) when actual == div(a+b,2) do
    IO.puts div(a+b,2)
  end

  def guess(actual, a..b) when actual < div(a+b,2) do
    guess = div(a+b,2)
    IO.puts "Is it #{guess}?"
    guess(actual, a..guess-1)
  end

  def guess(actual, a..b) when actual > div(a+b,2) do
    guess = div(a+b,2)
    IO.puts "Is it #{guess}?"
    guess(actual, guess+1..b)
  end

end
Generic-user-small
07 Jun 2016, 13:06
prasanna joshi (2 posts)

My initial naive solution :-/

defmodule Chop do
  def guess(n, low..high) do
    guess = div(low + high, 2)

    if n == low || n == high do
      n
    else
      IO.puts("Is it #{guess}?")

      if n <= guess do
        guess(n, low..guess)
      else
        guess(n, guess..high)
      end
    end
  end
end

After a quick peek, I could arrive at almost the same solution, except I added a guard on the public function to avoid guessing out of bound numbers.

def guess(actual, range = low..high) when actual in low..high do

Looks like I cannot use when actual in range as a guard.

Love the beauty pattern-matching & guarded functions have brought to the solution!

Generic-user-small
25 Jun 2016, 16:30
Karlo Smid (11 posts)
defmodule Chop do
  def guess(actual,_..b) when actual>b, do: IO.puts "You naughty hacker, your number is out of range!"
  def guess(actual,a.._) when actual<a, do: IO.puts "You naughty hacker, your number is out of range!"
  def guess(actual,a..b) when div(a+b,2)>actual do
    IO.puts "Is it #{div(a+b,2)}?"
    guess(actual,a..div(a+b,2))
  end
  def guess(actual,a..b) when div(a+b,2)<actual do
    IO.puts "Is it #{div(a+b,2)}?"
    guess(actual,div(a+b,2)+1..b)
  end
  def guess(_,a..b), do: IO.puts "It is #{div(a+b,2)}"
end
Generic-user-small
18 Aug 2016, 18:54
Damon (1 post)
def guess(n, lower..upper) do
  _guess(n, _next_guess(lower, upper), lower..upper)
end

def _guess(actual, current, _lower.._upper) when actual == current, do: actual
def _guess(actual, current, _lower..upper) when actual > current do
  _guess_log(current)
  _guess(actual, _next_guess(current, upper), current..upper)
end
def _guess(actual, current, lower.._upper) when actual < current do
  _guess_log(current)
  _guess(actual, _next_guess(lower, current), lower..current)
end

def _next_guess(lower, upper), do: div(lower+upper, 2)
def _guess_log(n), do: IO.puts "Is it #{n}?"
Generic-user-small
20 Aug 2016, 15:27
Chintan Thakkar (7 posts)

My solution without private functions …

defmodule Chop do
  def guess(actual, actual.._) do
    IO.puts("Yes, it's #{actual}.")
  end

  def guess(actual, low..high) when actual < div(high+low,2) do
    IO.puts("Is it #{div(high+low,2)}?")
    guess(actual, low..div(high+low,2))
  end

  def guess(actual, low..high)do
    IO.puts("Is it #{div(high+low,2)}?")
    guess(actual, div(high+low,2)..high)
  end

end

Looking at Dave’s solution, made me rethink the problem…

Generic-user-small
09 Sep 2016, 05:19
Arman Jon Villalobos (4 posts)

I was confused before because I did not understand the low and high problem and run into infinite loops. Here’s my final code:

defmodule Chop do
  def guess(actual, range = low..high) do
    attempt = div(low+high, 2)
    IO.puts "Is it #{attempt}"
    check_guess(actual, attempt, range)
  end

  def check_guess(actual, attempt, _) when attempt == actual do
    IO.puts "You got it! It's #{actual}"
  end
  def check_guess(actual, attempt, low.._high) when attempt > actual do
    guess(actual, low..attempt - 1)
  end
  def check_guess(actual, attempt, _low..high) when attempt < actual do
    guess(actual, attempt + 1..high)
  end
end

Chop.guess(273, 1..1000)

I love the code range = low..high, it saves me another line to explicitly say low..high = range. I did not think it first because for me = is still assignment.

Generic-user-small
23 Oct 2016, 18:45
Derek O'Connell (2 posts)
defmodule Chop do
  def guess(actual, low..high) when actual > div(low+high,2) do
    IO.puts "Is it: #{n = div(low+high,2)}"
    guess(actual, n+1..high)
  end

  def guess(actual, low..high) when actual < div(low+high,2) do
    IO.puts "Is it: #{n = div(low+high,2)}"
    guess(actual, low..n-1)
  end

  def guess(actual, _), do: IO.puts actual

end
Generic-user-small
10 Nov 2016, 20:48
Elias Perez (2 posts)

Just wanted to share my approach. Would like to know your thoughts

defmodule Chop do
  def guess(n, a..b) when (n == 0), do: 0
  def guess(n, a..b) when (a == 0 or b == 0), do: "Error: Range"
  def guess(n, a..b) when (n < a or n > b), do: "Error: Out of Range"
  def guess(n, a..b) when (a == n or b == n), do: print(n)
  def guess(n, a..b) when (n > a and n < b) do
    y = div(a+b, 2)
    print(y)
    cond do
      n == y -> IO.puts "Yes, it's #{y}"
      n > y  -> guess(n, y+1..b)
      n < y  -> guess(n, a..y-1)
    end
  end
  defp print(n), do: IO.puts "Is it #{n}?"
end
Generic-user-small
23 Nov 2016, 21:44
Mario Blokland (2 posts)

I have to say, I struggled with this one since functional programming is very new too me. In the end, I took Chintan’s solution and tried to understand what’s happening there.

Generic-user-small
26 Nov 2016, 22:13
Garcia Vincent (1 post)

It’s new for me too, I agree that in the meaning of the book, the Nathan Solution is the closest solution on the training

You must be logged in to comment