
Vindo do blog Nome Do Jogo, fiquei sabendo do novo desafio do Ruby Quiz. Há um tempo atrás acompanhava cada novo desafio, alguns que eu achava interessante, tentava resolvê-los, mas nunca cheguei a enviar a solução pra lá. Mas esse desafio é simples e bastante divertido.
O desafio é criar um método que recebe dois argumentos, um deles é um valor que deve ser dividido em moedas fornecidas no segundo argumento, o método tem que retornar um array com a menor combinação possível de moedas. Imagine ter que dar 37 centavos em moedas de 25, 10, 5 e 1? O certo seria receber uma de 25, uma de 10 e duas de 1, veja o código pra entender melhor:
irb(main):005:0> make_change(37, [25, 10, 5, 1]) => [25, 10, 1, 1]
Entendeu?! Agora vamos implementar o método, somente o método, não farei nenhuma classe. Primeiro vamos fazer alguns testes antes de criar o método:
require "test/unit";
class ChangeTest < Test::Unit::TestCase
def test_should_raise_error_when_change_is_impossible
assert_raise(ChangeError) do
make_change(23, [10, 5]);
end
end
def test_should_accept_diferent_coins
assert_equal [17, 17, 4], make_change(38, [17, 4]);
assert_equal [52], make_change(52, [52]);
end
def test_should_give_minimun_number_of_coins
assert_equal [25, 10, 1, 1], make_change(37);
assert_equal [1, 1, 1], make_change(3);
assert_equal [3, 3], make_change(6, [3]);
end
end
Se a troca for impossível com as moedas fornecidas, o método vai devolver uma exceção do tipo ChangeError. O método também tem por default moedas de 25, 10, 5 e 1 para serem usadas. Feitos os testes, vamos partir para a implementação, para isso precisaremos adicionar um método sum na classe Array que soma os elementos de dentro do Array:
class Array
def sum
inject{|sum, n| sum + n;};
end
end
Pronto, agora podemos partir para a implementação:
class ChangeError < StandardError; end
def make_change(amount, coins=[25, 10, 5, 1])
change = coins.sort.reverse.inject([]) do |change, coin|
change << coin until change.sum + coin > amount;
change;
end
raise ChangeError unless change.sum == amount;
change;
end
Na linha 4, eu ordeno o Array de maior para menor e uso o método inject, que é basicamente responsável por reduzir o Array a um valor. Nesse caso dentro do bloco de código eu coloco as moedas no Array change até que elas ultrapassarem o valor total, e devolvo esse Array. Na linha 8 eu checo se a soma do Array change é igual ao valor pedido, se não for retorna uma exceção ChangeError.
Não foi muito difícil, tem desafios mais elaborados no site, vale a pena dar uma conferida. Fiquei sabendo também que parece que esse é um dos últimos desafios do Ruby Quiz.
Powered by ScribeFire.

Fevereiro, 2 - 2008 às 3:27 pm |
Interessante! Pena que sou péssimo em Ruby, senão eu tentaria. Sorte!
Fevereiro, 9 - 2008 às 8:10 am |
pts, eu dei uma acalmada nos meus estudos com ruby por causa do excesso de trabalho, mas creio que ainda esse final de mês eu já alivie e recomece!
Ah! Quanto ao basquete, curto muito! Até jogo de vez em quando, mas estava me referindo mesmo é ao trabalho :p
Um abraço mano!
Fevereiro, 25 - 2008 às 10:09 pm |
Falow pessoal!