Google Developer Day – Questão 5

E aí galera, tranquilo?

Eu queria postar sobre o DevQuiz do Google faz um tempinho, em particular a questão número 5 que era um pouco mais complexa, mas não achei correto publicar a minha solução enquanto as inscrições ainda rolavam, mas agora que já elvis, gostaria de publicá-la aqui.

A história na verdade começou quando na Agência, ao saber do questionário, a galera de Interface começou a resolver as questões, cada um usando a sua lógica. No final, alguns fizeram e compartilharam suas soluções.

Eu achei interessante isso, porque saiu um pouco da rotina meio “Fábrica de Pastel” e começamos a discutir as soluções propostas de cada um, percebemos que pensamos de forma muito diferente, não pior, não melhor, mas diferente.

Como o tempo contava na hora de responder as perguntas, não se pode criticar o código final seja lá qual for o problema, se de resolução, performance, design ou qualquer outro…

E como defensor ferrenho do Javascript, entusiasta, estudante e escritor do assunto ( já que tenho o blog ) acertei na mosca a resposta, certo?

BÉEEEEEEEEEE! FAIL!

Dog Fail

Meu script foi considerado o mais dificil de se entender ( o que é muito subjetivo ) e no final das contas não funcionou retornando a resposta certa =\.

DAMN!!!

Maaasssss felizmente acabei aprendendo coisas interessantes nos códigos alheios, o que valeu a brincadeira.

Claro, após revisto os erros, reescrevi o código envolvendo as funções soltas em um objeto e preservei TODA a lógica, removendo as redundâncias.

O primeiro código fail foi esse:

var double_n = function(string){
	    return !!string.match(/1{2}|2{2}|3{2}|4{2}|5{2}|6{2}|7{2}|8{2}|9{2}|0{2}/g)
	}

	var soma_n = function(string){
	    var cont = 0
	    string.replace(/\d/g, function(d){
	        cont += +d
	        return d
	    })
	    return !(!!(!cont % 2))
	}

	var last_first = function(string){
	    if (string.charAt(0) == string.charAt(string.length - 1)) 
	        return false
	    return true
	}

	//Telefone é o textarea com os números
	var array = $('#telefone').val().split(/\n/)
	//O último elemento vinha vazio por causa do último \n
		array.pop()
			
	var contador = 0
	$.each(array, function(i){
	    if (double_n(array[i]) && soma_n(array[i]) && last_first(array[i])) 
	        contador++
	})
	console.log(contador)

Meu erro foi a mania que tenho de querer me certificar de que o retorno de uma condição retorne um valor booleano de fato ao invés de um Truthy ou Falsy. Ou seja, num retorno de string vazia, tenho a mania de transformar antes em um boolean tipo: !!””

Com isso, errei ali no retorno da soma_n, na precedência dos operadores unários.

Mas acabei aprendendo com esse erro e além disso aprendi a melhorar minha RegExp verbosa, por uma bem mais simples na solução do líder técnico da área.

Aí vai o código reescrito com as modificações necessárias, removi algumas redundâncias, mas a lógica se mantém a mesma:

var Resolution = {

	of :function(array, cont){
		var el = null
		var i = 0
			with( this ) while( el = array[i++] )
				cont += if_hasnt_dup(el) && 
					if_sum_isnt_mod2(el) && 
					if_last_isnt_first(el) ? 1:0
		return cont
	},

	if_sum_isnt_mod2 :function(string){
		var cont = 0
		string.replace(/\d/g, function(d){ cont += +d })
		return !(cont % 2)
	},

	if_hasnt_dup :function(string){
		return !(!!string.match(/(\d)\1/g))
	},

	if_last_isnt_first :function(string){
		return !(string.charAt(0) == string.charAt(string.length - 1))
	}
}

alert( Resolution.of(arr, 0) )

Eu usei um with ali, vocês sabem que é horrível e que jamais devemos usar o with, mas eu coloquei ali para dificultar ainda mais o código rsrsrs.

Para quem programa em Javascript, a resolução do problema foi bem rápida, uma porque a própria linguagem permite isso a outra porque era só botar o código no firebug e executar! Que foi o que eu fiz e imagino que muitos outros fizeram também.

Também fiz em Ruby, usando a mesma lógica que usei em Javascript:

require 'jcode'
		def sum_isnt_mod2?(string) 
			cont = 0
			string.each_char { |c| cont+= c.to_i }
			(cont%2).zero?
		end
		
		def hasnt_dup?(string)
			!(string =~ /(\d)\1/) 
		end
		
		def last_isnt_first?(string)
			!(string[0,1] == string[-1,1])
		end
		
		def answer (arr,count)
			arr.each do |v|
				count += 1 if sum_isnt_mod2?(v) && hasnt_dup?(v) && last_isnt_first?(v) 			
			end
			count
		end	
	
	puts answer(array, 0)

Em ambas as linguagens, resolvi considerando os números de telefones como strings ao invés de números, porque achei muito mais fácil.

Você que está lendo o blog agora, resolveu a questão? Acertou ? Errou ?
Posta sua solução nos comentários, acertando ou não tenho certeza que há algo para aprender no código, sempre há…

Se resolveu usando outra linguagem de programação, MELHOR AINDA, poste para mostrarmos as diferenças das linguagens, seria muito interessante. 😉

Obrigado mais uma vez pela atenção galera, um grande abraço!

[Update]
A Carmen Sachetto que faz o Curso de Ciência da Computação comigo no Mackenzie, fez esta solução em Scheme!!

Muito foda, olha só:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 		No peculiar condado de Compiladorshire, todos os telefones têm 6 dígitos.            ; 
; 		A companhia telefônica estabelece as seguintes regras sobre os números:              ;
;		Não pode haver dois dígitos consecutivos idênticos, porque isso é chato;             ;
;		A soma dos dígitos tem que ser par, porque isso é legal;                             ;
;		O último dígito não pode ser igual ao primeiro, porque isso dá azar.                 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   	função principal        ;
; entrada: uma lista com listas ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (Principal lista)
  (if (null? lista) '()
  (if (= (Verifica (car lista)) 0) (cons (car lista) (Principal (cdr lista)))
  (Principal (cdr lista)))))

  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;    Verifica se um numero de telefone é valido   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (Verifica lista)
  (if (= (Iguais (cdr lista) (car lista)) 
         (Epar (somaElem lista 0)) 
         (PrimUlt (cdr lista) (car lista) (car lista)) 
         0) 0
  (if (not (= (Iguais (cdr lista) (car lista)) 
         (Epar (somaElem lista 0)) 
         (PrimUlt (cdr lista) (car lista) (car lista)) 
         0) ) 1)))    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   verifica se ultimo elemento é igual a primeiro                         ;
;   se ultimo elemento for igual ao primeiro, retorna 1, senão retorna 0   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (PrimUlt lista primeiro anterior)
  (if (null? lista) (comparaElem primeiro anterior)
  (PrimUlt (cdr lista) primeiro (car lista))))

  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;     compara dois elementos    ;
;   se forem iguais, retorna 1  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (comparaElem a b)
(if ( = a b) 1
(if (not ( = a b)) 0)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  soma elementos de uma lista  ;
;       retorna soma            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (somaElem lista soma)
(if (null? lista) soma
(somaElem (cdr lista) (+ soma (car lista)))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;     verifica se um número é par ou não     ;
;    se for par retorna 0, senão retorna 1   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (EPar numero)
  (if (= (remainder numero 2) 0) 0
  (if (not (= (remainder numero 2) 0)) 1)))

  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   verifica se há dois dígitos consecutivos idênticos  ;
;                 se houver, retorna 1                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (Iguais lista anterior)
  (if (null? lista) 0
  (if (= anterior (car lista)) 1
  (Iguais (cdr lista) (car lista)))))

Bem legal né ?!?!?!

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s