16 Jul 2013, 02:25 Dave Thomas (338 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} A Possible Solution ```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) ``` 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. 02 Aug 2013, 14:09 Dave Thomas (338 posts) I use details/summary tags 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 `````` 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. 29 Nov 2013, 18:02 Kit Ko (2 posts) The syntax of defining a function that calls itself is also described later in chapter 7. 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. 05 Feb 2014, 03:34 Manuel E Vidaurre Arenas (6 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 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, 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 `````` 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 `````` 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) `````` 31 Aug 2014, 19:03 Suraj Kurapati (2 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 `````` You must be logged in to comment