course-logo-text.png


Homework 1: Ruby Calisthenics

(batería de test que pasará tu código)

Instrucciones: Para la entrega,por favor, envíe un (1) archivo Ruby para cada parte con la solución para esa parte.Enviar el archivo desde "Output Submission" dejando en blanco "Addition Submission". Puede enviar la tarea tantas veces como desee antes dela fecha límite.Sólo la última entrega será utilizado para la evaluación.
Para ver el estado de sus envíos, haga clic en el marcador.Las entregas que hayan sido evaluadas tendrán retroalimentación.

HW 1: Ruby Calistenia

En esta tarea trendrás que realizar algunos ejercicios simples de programación para familiarizarse con el lenguaje Ruby. Se ofrecerán calificaciones detalladas automáticamente de tu código.
NOTA: Para todas las preguntas que involucran palabras o cadenas, se puede suponer que la definición de una "palabra" es "una secuencia de caracteres, cuyos límites se corresponden con el constructor \b en las expresiones regulares de Ruby."

Parte 1:divertirse con cadenas
a) Escribir un método que determine si una determinada palabra o frase es un palíndromo; es decir, que se lea igual hacia atrás que hacia adelante, ignorando mayúsculas y minúsculas, signos de puntuación y otro tipo de caracteres (un "carácter de otro tipo" para nuestro propósito en aquel "carácter que las expresiones regulares de Ruby tratarían como un carácter que no pertenece a una palabra (noword)".) La solución no debe usar bucles o iteraciones de ningún tipo. Encontrarás muy útil la sintaxis de las expresiones regulares, en el libro se hace una breve revisión y en //http://rubular.com// podrás probar las expresiones regulares de Ruby "en vivo". Los métodos que pueden resultar útiles (que podrá buscar en la documentación de Ruby, http://ruby-doc.org) son: String#downcase, String#gsub, String#reverse.
Sugerencia: una vez que su código funcione, intente hacerlo más vistoso utilizando técnicas como métodos de encadenamiento, como se describe en ELLS 3,2.
Ejemplos:
palindrome?("A man, a plan, a canal -- Panama") #=> true
palindrome?("Madam, I'm Adam!") # => true
palindrome?("Abracadabra") # => false (nil es también ok)

def palindrome?(string)
# tu código aquí
end

b) Dada una cadena de entrada, devuelve un hash cuyas claves son las palabras de la cadena y cuyos valores son el número de veces que cada palabra aparece. No utilice bucles. “Nowords” deben ser ignorados. No diferenciar entre mayúsculas y minúsculas. Una palabra se define como una cadena de caracteres entre los límites de palabra. (Pista: La secuencia \b en una expresión regular de Ruby significa "límite de palabra")
Ejemplo
count_words("A man, a plan, a canal -- Panama")
# => {'a' => 3, 'man' => 1, 'canal' => 1, 'panama' => 1, 'plan' => 1}
count_words "Doo bee doo bee doo" # => {'doo' => 3, 'bee' => 2}

def count_words(string)
# your code here
end

Parte 2: Piedra-Papel-Tijeras
En el juego “piedra-papel-tijeras”, cada jugador elige jugar con Piedra (Rock – R), Papel (Paper – P) o Tijeras (Scissors – S). Las reglas son: la roca gana a las tijeras, las tijeras ganan al papel y el papel gana a la roca.
El juego es codificado como una lista, donde los elementos son listados en pares para representar al jugador y la estrategia elegida.

[ [ "Armando", "P" ], [ "Dave", "S" ] ]
# => returns the list ["Dave", "S"] wins since S>P

(a) Escribir un método rps_game_winner que tome una lista con dos elementos y se comporte como sigue:
  • Si el número de jugadores no es igual a 2, lanzará WrongNumberOfPlayersError
  • Si la estrategia no es "R", "P" o "S" (insensible a mayústulas-minúsculas), lanzará NoSuchStrategyError
  • En otro caso, devolver el nombre y la estrategia del jugador ganador. Si ambos jugadores eligen la misma estrategia, el primer jugador es el ganador.

class WrongNumberOfPlayersError < StandardError ; end
class NoSuchStrategyError < StandardError ; end

def rps_game_winner(game)
raise WrongNumberOfPlayersError unless game.length == 2
# your code here
end

Nota: Salida
jugador
strategia

(b) Un torneo Piedra-Papel-Tijeras es codificado en un array de juegos, donde cada elemento es una partida entre varios jugadores.

[
[
[ ["Armando", "P"], ["Dave", "S"] ],
[ ["Richard", "R"], ["Michael", "S"] ],
],
[
[ ["Allen", "S"], ["Omer", "P"] ],
[ ["David E.", "R"], ["Richard X.", "P"] ]
]
]

En este escenario, Dave ganaría a Armando (ya que, S> P) y Richard superaría a Michael (R> S), y luego Dave y Richard jugarían y ganaría Richard (ya que, R> S). Del mismo modo, en el segundo ejemplo, Allen ganaría a Omer (S>P) y David E. le ganaría a Richard X., luego entre Allen y Richard X. ganaría Allen (S> P). Finalmente, Richard le ganaría a Allen; ya que R< P. Es decir, un torneo continúa hasta que sólo quede un solo ganador.
Escriba un método rps_tournament_winner que dado un torneo, codificado como una matriz entre corchetes devuelva el ganador y su estrategia (para el ejemplo anterior, debe devolver ["Richard", "R"]). Se debe suponer que el conjunto está bien formado (es decir, hay 2^n jugadores, y cada uno participa en exactamente un partido por ronda).

Parte 3. Anagrams
Un anagrama es una palabra que se obtiene reordenando las letras de otra palabra.Por ejemplo,"rats", "tars" and "star" son un grupo de anagramas, ya que están compuestas por las mismas letras en orden diferente.

Dado un array de cadenas, escribir un método que los agrupe en anagrama y devuelve el array de los grupos. Las mayúsculas-minúsculas no influyen en la clasificación delas cadenas (pero debe ser preservada en la salida), y el orden delos anagramas en los grupos tampoco importa.
Example:
# input: ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream']
# => output: [["cars", "racs", "scar"], ["four"], ["for"], ["potatoes"], ["creams", "scream"]]
# HINT: you can quickly tell if two words are anagrams by sorting their
# letters, keeping in mind that upper vs lowercase doesn't matter

def combine_anagrams(words)
# <YOUR CODE HERE>
end

Part 4: Basic OOP
(a) Crea una clase “Dessert” con sus “getters and setters” para los atributos “name” y “calories”. Define los métodos “healthy?”, el cual devuelve “true” si el postre tiene menos de 200 calorías, y “delicious?”, el cual devuelve “true” para todos los postres.
(b) Crea una clase “JellyBean” que herede de “Desert”, e incluye getter y setter para el atributo “flavor”. Sobreescribe el método “delicious?” para que devuelva false si el sabor (flavor) es “black licorice” (“delicious?” debe devolver “true” para todos los otros sabores y para el resto de los postres que no sean “JellyBean”).
Aquí está el framework (puedes definir métodos adicionales que te ayuden):

class Dessert
def initialize(name, calories)
# YOUR CODE HERE
end
def healthy?
# YOUR CODE HERE
end
def delicious?
# YOUR CODE HERE
end
end
class JellyBean < Dessert
def initialize(name, calories, flavor)
# YOUR CODE HERE
end
def delicious?
# YOUR CODE HERE
end
end


Part 5: advanced OOP with some metaprogramming
(Ejercicio 3.4 de ELLS)
Hemos visto como “attr_accessor” use metaprogramación para crear “getters y setters” para los atributos de un objeto.
Define un método “attr_accessor_with_history” con la misma funcionalidad que “attr_accessor” pero que también muestre un seguimiento de los valores que haya tenido alguna vez el atributo:
class Foo
attr_accessor_with_history :bar
end

f = Foo.new # => #<Foo:0x127e678>
f.bar = 3 # => 3
f.bar = :wowzo # => :wowzo
f.bar = 'boo!' # => 'boo!'
f.bar_history # => [nil, 3, :wowzo, 'boo!']
Para empezar. En primer lugar, si definimosattr_accessor_with_historyen la claseClass,podemos utilizarlacomo en elfragmento anterior. Esto es así porque, como se indica en ELL,en Rubyuna clasees simplementeun objeto dela clase Class. (Si aún no entiendes esto, no te preocupespor ahora. Ya lo entenderás). En segundo lugar, Rubyproporciona unmétodo class_evalque toma una cadenay lo evalúaen el contexto dela actual clase,es decir, laclase desde la que se está invocando attr_accessor_with_history. Esta cadenadeberá conteneruna definición del métodoque implementasetter-with-history para el atributo deseado attr_name.
  • No olvides que la primera vez que el atributo recibe un valor, su array histórico tiene que ser inicializado
  • No olvides que las variables de la clase son referenciadas como @bar dentro de los getters y setters, como explica en la sección 3.4 ELLS
  • Aunque el método attr_accessor puede manejar múltiples argumentos (p.e. attr_accessor :foo, :bar), tu versión sólo necesita manejar un único argumento.
  • Su aplicación debe ser general para funcionar en el context de cualquier clase y para atributos con cualquier nombre (legal) de variable.
  • El historico de las variables debe ser mantenido de forma separada para cada objeto. Esto es, si haces:

f = Foo.new
f.bar = 1
f.bar = 2
f = Foo.new
f. bar = 4
f.bar_history
el resultado de la última línea sería[nil,4], en vez de[nil,1,2,4]

Aquí está el esqueleto para que comenzar:
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name # create the attribute's getter
attr_reader attr_name+"_history" # create bar_history getter
class_eval "your code here, use %Q for multiline strings"

end
end

class Foo
attr_accessor_with_history :bar
end

f = Foo.new
f.bar = 1
f.bar = 2
f.bar_history # => if your code works, should be [nil,1,2]


[Atención: Si tienes dudas, consulta la tarea en inglés aquí]