Rutas
/
Crystal
Crystal
/
Ejercicios
/
Acero embrujado
Acero embrujado

Acero embrujado

Ejercicio de aprendizaje

Introducción

En programación, la iteración se refiere al proceso de repetir un bloque de código varias veces. Esto se puede hacer con conceptos como los bucles while y los bucles until. También se puede hacer con recursión, que es una función que se llama a sí misma.

Sin embargo, lo más habitual es que quieras iterar sobre una colección de elementos, como un Array, un Range o un String. Tanto la clase Array como la clase Range de Crystal incluyen el módulo Enumerable, que ofrece varios métodos para iterar sobre los elementos. Por su parte, la clase String tiene su propio conjunto de métodos para iterar sobre los caracteres.

Además, Crystal no tiene ninguna instrucción for como otros lenguajes. En su lugar, tiene varios métodos que se pueden usar para iterar.

Iterar

La forma más habitual de iterar sobre una colección es usar el método each, que cede cada elemento de la colección a un bloque. Esto se puede hacer fácilmente con un Range. Supongamos que quieres recorrer del 1 al 3; puedes usar el método each para iterar sobre el rango.

(1..3).each do |n|
  puts n
end

# Output:
# 1
# 2
# 3

Todavía más sencillo: si solo quieres iterar un número determinado de veces, puedes usar el método times, que existe en la clase Int.

3.times do |n|
  puts n
end

# Output:
# 0
# 1
# 2

Iterar sobre un String

Un String es una secuencia de caracteres y no pertenece al módulo Enumerable, lo que significa que tiene su propio conjunto de métodos para iterar sobre los caracteres. La forma más habitual de iterar sobre un String es usar el método each_char, que cede cada carácter del String a un bloque.

Note

El método each_char pasa al bloque un objeto Char, no un objeto String.

str = "hello"
str.each_char { |char| puts char }

# Output:
# h
# e
# l
# l
# o

Otra forma de iterar sobre un String es usar el método each_line. Este método se usa sobre todo cuando se lee un archivo línea por línea.

str = "hello\nworld"
str.each_line do |line|
  puts line
end

# Output:
# hello
# world

Iterar sobre un objeto que incluye el módulo Enumerable

El módulo Enumerable ofrece varios métodos para iterar sobre los elementos de una colección. Las colecciones que incluyen el módulo Enumerable son Array, Range, Hash, Set y otras; estas últimas se verán en conceptos posteriores.

La forma más habitual de iterar sobre un Array es usar el método each, que cede cada elemento del Array a un bloque.

arr = [5, 2, 3]
arr.each do |element|
  puts element
end

# Output:
# 5
# 2
# 3

Map

El método map es otra forma de iterar sobre un Array; devuelve un Array nuevo con los resultados de aplicar el bloque a cada elemento. Es similar al método each, pero devuelve un Array nuevo con los elementos transformados. La transformación es muy útil cuando quieres aplicar una función a cada elemento de la colección, que es una operación habitual.

arr = [1, 2, 3]
new_arr = arr.map do |element|
  element * 2
end

new_arr
# => [2, 4, 6]

Con un control de flujo como if también puedes filtrar qué elementos transformar.

arr = [1, 2, 3]
new_arr = arr.map do |element|
  if element.odd?
    element * 2
  else
    element
  end
end

new_arr
# => [2, 2, 6]

Con índice

A veces necesitas saber el índice del elemento sobre el que estás iterando; para eso puedes usar el método each_with_index o map_with_index. Cede cada elemento y su índice a un bloque; el método también acepta un argumento opcional para especificar el índice inicial.

arr = [1, 2, 3]
arr.each_with_index(4) do |element, index|
  puts "Element: #{element}, Index: #{index}"
end

# Output:
# Element: 1, Index: 4
# Element: 2, Index: 5
# Element: 3, Index: 6

Ten en cuenta que el método each_char_with_index también está disponible para objetos String.

sum

El método sum devuelve la suma de todos los elementos de la colección; también acepta un bloque opcional para transformar los elementos antes de sumarlos. También acepta un argumento opcional para especificar el valor inicial de la suma.

arr = [1, 2, 3]
arr.sum
# => 6

arr.sum(2) { |n| n * 2 }
# => 14

reduce

reduce, o fold como se conoce en otros lenguajes, es un método que, con un método de combinación y un valor inicial, combina todos los elementos de la colección. El método reduce tiene un acumulador que se pasa al bloque; el acumulador es el resultado de la iteración anterior. Esto se convierte en un proceso recursivo que combina todos los elementos de la colección.

arr = [1, 2, 3]
arr.reduce(0) do |acc, n|
  acc + n
end
# => 6

reduce puede parecer similar a sum, pero reduce es más flexible porque te permite especificar el valor inicial del acumulador y el método de combinación. reduce se puede usar para implementar sum, count y otros métodos.

Instrucciones

En el juego de cartas Spellbound Steel, tienes una baraja de cartas con distintos personajes, como guerreros, magos y pícaros, o distintos hechizos, como bola de fuego, tormenta de hielo y rayo. En la partida participan de dos a cuatro jugadores, y el objetivo es derrotar a los demás jugadores jugando cartas con niveles de poder más altos.

Quieres obtener la ventaja en la partida creando varios métodos para calcular, ordenar y comparar los niveles de poder de las cartas.

1. Encontrar una carta en la baraja

No estás seguro de si una carta está en la baraja o no. Por lo tanto, quieres un método que te diga dónde puedes encontrar la primera carta de la baraja del tipo que buscas. O, si la carta no está en la baraja, también quieres saberlo.

Implementa un método SpellboundSteel.find_card? que reciba un Array de cartas de tipo String y una carta de tipo String que haya que encontrar. El método debe devolver el índice de la primera carta de la baraja que coincida con la carta que hay que encontrar. Si la carta no está en la baraja, el método debe devolver nil.

cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt", "Mage"]
SpellboundSteel.find_card?(cards, "Mage")
# => 1

2. Poner en mayúscula todos los caracteres

Para que las cartas sean más fáciles de leer, quieres poner en mayúscula todos los caracteres de los nombres de las cartas. Así puedes ver fácilmente los nombres de las cartas cuando juegas con ellas.

Implementa un método SpellboundSteel.capitalize_cards que reciba un Array de cartas de tipo String y devuelva las cartas con todos los caracteres en mayúscula.

cards = ["warrior", "mage", "rogue", "fireball", "ice storm", "lightning bolt"]
SpellboundSteel.capitalize_cards(cards)
# => ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]

3. Calcular el nivel de poder de todas las cartas

En el juego es importante calcular el nivel de poder de todas las cartas. El poder de todas las cartas se puede ver en la siguiente tabla:

Tipo de carta Nivel de poder
Warrior 10
Mage 20
Rogue 30
Fireball 15
Ice Storm 25
Lightning Bolt 35

Implementa un método SpellboundSteel.calculate_power_level que reciba un Array de cartas de tipo String y devuelva el nivel de poder total de todas las cartas.

cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]
SpellboundSteel.calculate_power_level(cards)
# => 135

4. Descifrar una carta

En el juego existen las llamadas cartas malditas. Estas cartas son cartas ocultas que solo puede descifrar el jugador que las jugó. Para descifrar la carta, hay que eliminar cada segundo carácter del nombre de la carta. Eso dará el nombre de la carta.

Implementa un método SpellboundSteel.decode_card que reciba una carta de tipo String y devuelva la carta descifrada.

SpellboundSteel.decode_card("Wbalrrrlimoqr")
# => "Warrior"
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Crystal Exercism

¿Listo para empezar Acero embrujado?

Regístrate en Exercism para aprender y dominar Crystal con 26 conceptos142 ejercicios y mentoría humana real, todo gratis.