A programozásban az iteráció egy kódrészlet többszöri megismétlését jelenti.
Ezt megteheted például while- és until-ciklusokkal.
Rekurzióval is megoldható, ami egy önmagát meghívó függvény.
Leggyakrabban azonban egy elemgyűjteményen szeretnél iterálni, például egy Array, Range vagy String objektumon.
A Crystalben az Array és a Range osztály is tartalmazza az Enumerable modult, ami számos metódust kínál az elemeken való iteráláshoz.
A String osztálynak eközben saját metóduskészlete van a karaktereken való iteráláshoz.
A Crystalben ráadásul nincs for utasítás, mint sok más nyelvben.
Helyette több metódus is használható az iteráláshoz.
A leggyakoribb módja a gyűjteményen való iterálásnak a each metódus használata, ami a gyűjtemény minden elemét átadja egy blokknak.
Ez egy Range segítségével könnyedén megtehető.
Tegyük fel, hogy 1 és 3 között szeretnél ciklust futtatni; ekkor az each metódussal iterálhatsz a tartományon.
(1..3).each do |n|
puts n
end
# Output:
# 1
# 2
# 3
Még egyszerűbb, ha csak adott számú alkalommal szeretnél iterálni: használhatod a times metódust, ami az Int osztályon érhető el.
3.times do |n|
puts n
end
# Output:
# 0
# 1
# 2
String-enA String karakterek sorozata, és nem tartozik az Enumerable modulhoz, ami azt jelenti, hogy saját metóduskészlete van a karaktereken való iteráláshoz.
A leggyakoribb módja a String-en való iterálásnak a each_char metódus használata, ami a String minden karakterét átadja egy blokknak.
Az each_char metódus egy Char objektumot ad át a blokknak, nem pedig egy String objektumot.
str = "hello"
str.each_char { |char| puts char }
# Output:
# h
# e
# l
# l
# o
A String-en való iterálás másik módja a each_line metódus használata.
Ezt a metódust főleg akkor használod, amikor egy fájlt soronként olvasol be.
str = "hello\nworld"
str.each_line do |line|
puts line
end
# Output:
# hello
# world
Enumerable modultAz Enumerable modul számos metódust kínál egy gyűjtemény elemein való iteráláshoz.
Gyűjtemények, amelyek tartalmazzák az Enumerable modult: Array, Range, Hash, Set és mások; az utóbbiakkal későbbi fogalmakban fogsz találkozni.
A leggyakoribb módja az Array-en való iterálásnak a each metódus használata, ami az Array minden elemét átadja egy blokknak.
arr = [5, 2, 3]
arr.each do |element|
puts element
end
# Output:
# 5
# 2
# 3
A map metódus egy másik módja az Array-en való iterálásnak: egy új Array-t ad vissza, amely a blokk minden elemre való alkalmazásának eredményeit tartalmazza.
Hasonlít az each metódushoz, de egy új Array-t ad vissza az átalakított elemekkel.
Az átalakítás nagyon hasznos, ha egy függvényt szeretnél alkalmazni a gyűjtemény minden elemére, ami gyakori művelet.
arr = [1, 2, 3]
new_arr = arr.map do |element|
element * 2
end
new_arr
# => [2, 4, 6]
Egy if-hez hasonló vezérlési szerkezettel azt is megválaszthatod, hogy mely elemeket alakítsd át.
arr = [1, 2, 3]
new_arr = arr.map do |element|
if element.odd?
element * 2
else
element
end
end
new_arr
# => [2, 2, 6]
Néha tudnod kell, hogy éppen melyik elemen iterálsz; erre az each_with_index vagy a map_with_index metódust használhatod.
Minden elemet és annak indexét átadja egy blokknak, és a metódus elfogad egy opcionális argumentumot is a kezdőindex megadásához.
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
Ne feledd, hogy az each_char_with_index metódus is elérhető String objektumokhoz.
A sum metódus a gyűjtemény összes elemének összegét adja vissza, és elfogad egy opcionális blokkot is, amellyel az elemeket az összegzés előtt átalakíthatod.
Egy opcionális argumentumot is elfogad az összeg kezdőértékének megadásához.
arr = [1, 2, 3]
arr.sum
# => 6
arr.sum(2) { |n| n * 2 }
# => 14
A reduce, amit más nyelvekben fold néven is ismernek, egy olyan metódus, amely egy összekapcsoló művelettel és egy kezdőértékkel az összes elemet összevonja a gyűjteményben.
A reduce metódusnál van egy akkumulátor, amit átad a blokknak; az akkumulátor az előző iteráció eredménye.
Ez egy rekurzív folyamattá válik, amely összevonja a gyűjtemény összes elemét.
arr = [1, 2, 3]
arr.reduce(0) do |acc, n|
acc + n
end
# => 6
A reduce hasonlíthat a sum-hoz, de rugalmasabb, mert megadhatod az akkumulátor kezdőértékét és az összekapcsoló műveletet.
A reduce segítségével megvalósíthatod a sum, count és más metódusokat.
A Spellbound Steel kártyajátékban a pakli kártyáin különféle karakterek, például warrior, mage és rogue, vagy különféle varázslatok, például fireball, ice storm és lightning bolt szerepelnek. A játékban kettő-négy játékos vesz részt, a cél pedig az, hogy legyőzd a többi játékost nagyobb erőszintű kártyák kijátszásával.
Szeretnéd átvenni az irányítást a játékban, ezért különféle metódusokat hozol létre a kártyák erőszintjének kiszámításához, rendezéséhez és összehasonlításához.
Nem vagy benne biztos, hogy egy kártya benne van-e a pakliban vagy sem. Ezért szeretnél egy metódust, ami megmondja, hol találod meg a pakliban az első olyan kártyát, amit keresel. Vagy ha a kártya nincs a pakliban, szeretnéd ezt is tudni.
Valósítsd meg a SpellboundSteel.find_card? metódust, amely egy String kártyákból álló Array-t és a megkeresendő String kártyát veszi át.
A metódus adja vissza annak az első kártyának az indexét a pakliban, amely megegyezik a keresett kártyával.
Ha a kártya nincs a pakliban, a metódus nil-t adjon vissza.
cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt", "Mage"]
SpellboundSteel.find_card?(cards, "Mage")
# => 1
Hogy a kártyák könnyebben olvashatók legyenek, a kártyanevekben az összes karaktert nagybetűvel szeretnéd írni. Így könnyen látod a kártyaneveket, amikor kijátszod a kártyákat.
Valósítsd meg a SpellboundSteel.capitalize_cards metódust, amely egy String kártyákból álló Array-t veszi át, és a kártyákat úgy adja vissza, hogy minden karakterük nagybetűvel van írva.
cards = ["warrior", "mage", "rogue", "fireball", "ice storm", "lightning bolt"]
SpellboundSteel.capitalize_cards(cards)
# => ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]
A játékban fontos, hogy kiszámítsd az összes kártya erőszintjét. Az összes kártya ereje a következő táblázatban látható:
| Card Type | Power Level |
|---|---|
| Warrior | 10 |
| Mage | 20 |
| Rogue | 30 |
| Fireball | 15 |
| Ice Storm | 25 |
| Lightning Bolt | 35 |
Valósítsd meg a SpellboundSteel.calculate_power_level metódust, amely egy String kártyákból álló Array-t veszi át, és visszaadja az összes kártya összesített erőszintjét.
cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]
SpellboundSteel.calculate_power_level(cards)
# => 135
A játékban vannak úgynevezett átkozott kártyák. Ezek rejtett kártyák, amelyeket csak az a játékos tud dekódolni, aki kijátszotta. A kártya dekódolásához a kártyanév minden második karakterét kell eltávolítanod. Így megkapod a kártya nevét.
Valósítsd meg a SpellboundSteel.decode_card metódust, amely egy String kártyát vesz át, és visszaadja a dekódolt kártyát.
SpellboundSteel.decode_card("Wbalrrrlimoqr")
# => "Warrior"
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Crystal nyelvet 26 fogalom142 feladat segítségével, valódi emberi mentorálással, mindez ingyen.