Tracks
/
Crystal
Crystal
/
Ejercicios
/
acero-encantado
acero-encantado

acero-encantado

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 usando conceptos como los bucles while y los bucles until. También se puede hacer usando recursión, que es una función que se llama a sí misma.

Sin embargo, la mayoría de las veces quieres 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 sentencia for como otros lenguajes. En su lugar, tiene varios métodos que puedes usar para iterar.

Iterar

La forma más común de iterar sobre una colección es usar el método each, que pasa cada elemento de la colección a un bloque. Esto se puede hacer fácilmente con un Range. Supón que quieres iterar entre 1 y 3; puedes usar el método each para iterar sobre el rango.

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

# Output:
# 1
# 2
# 3

Aún más simple: si solo quieres iterar una cantidad 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 común de iterar sobre un String es usar el método each_char, que pasa cada carácter del String a un bloque.

Note

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

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 común de iterar sobre un Array es usar el método each, que pasa 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 nuevo Array que contiene los resultados de aplicar el bloque a cada elemento. Es similar al método each, pero devuelve un nuevo Array 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 común.

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. Pasa 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 los 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. Además, 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 un mazo de cartas con distintos personajes, como warriors, mages y rogues, o distintos hechizos, como fireball, ice storm y lightning bolt. En el juego 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 sacar ventaja en el juego creando varios métodos para calcular, ordenar y comparar los niveles de poder de las cartas.

1. Encontrar una carta en el mazo

No sabes con certeza si una carta está en el mazo o no. Por eso quieres un método que te diga dónde puedes encontrar la primera carta del mazo del tipo que buscas. Y si la carta no está en el mazo, también quieres saberlo.

Implementa un método SpellboundSteel.find_card? que recibe un Array de cartas de tipo String y una carta de tipo String que hay que buscar. El método debe devolver el índice de la primera carta del mazo que coincida con la carta buscada. Si la carta no está en el mazo, 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 la primera letra de cada palabra

Para que las cartas sean más fáciles de leer, quieres poner en mayúscula la primera letra de cada palabra de los nombres de las cartas. Así podrás ver fácilmente los nombres de las cartas cuando las juegues.

Implementa un método SpellboundSteel.capitalize_cards que recibe un Array de cartas de tipo String y devuelve las cartas con la primera letra de cada palabra 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 recibe un Array de cartas de tipo String y devuelve 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, debes tomar cada segundo carácter del nombre de la carta y eliminarlo. Así obtendrás el nombre de la carta.

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

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

¿Todo listo para empezar acero-encantado?

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