Στον προγραμματισμό, η επανάληψη αναφέρεται στη διαδικασία επανάληψης ενός μπλοκ κώδικα πολλές φορές.
Αυτό μπορεί να γίνει χρησιμοποιώντας έννοιες όπως οι βρόχοι while και οι until βρόχοι.
Μπορεί επίσης να γίνει με αναδρομή, δηλαδή μια συνάρτηση που καλεί τον εαυτό της.
Ωστόσο, τις περισσότερες φορές θέλεις να επαναλάβεις πάνω σε μια συλλογή στοιχείων, όπως έναν Array, ένα Range ή μια String.
Τόσο η κλάση Array όσο και η κλάση Range στη Crystal περιλαμβάνουν το module Enumerable, το οποίο παρέχει έναν αριθμό μεθόδων για επανάληψη πάνω στα στοιχεία.
Εν τω μεταξύ, η κλάση String έχει το δικό της σύνολο μεθόδων για επανάληψη πάνω στους χαρακτήρες.
Η Crystal επίσης δεν έχει καμία εντολή for όπως οι άλλες γλώσσες.
Αντ' αυτού, έχει αρκετές μεθόδους που μπορούν να χρησιμοποιηθούν για επανάληψη.
Ο πιο συνηθισμένος τρόπος για να επαναλάβεις πάνω σε μια συλλογή είναι να χρησιμοποιήσεις τη μέθοδο each, η οποία περνάει κάθε στοιχείο της συλλογής σε ένα μπλοκ.
Αυτό μπορεί να γίνει εύκολα με ένα Range.
Ας πούμε ότι θέλεις να κάνεις βρόχο από το 1 έως το 3, μπορείς να χρησιμοποιήσεις τη μέθοδο each για να επαναλάβεις πάνω στο Range.
(1..3).each do |n|
puts n
end
# Output:
# 1
# 2
# 3
Ακόμα πιο απλά, αν θέλεις απλώς να επαναλάβεις έναν αριθμό φορών, μπορείς να χρησιμοποιήσεις τη μέθοδο times, η οποία υπάρχει στην κλάση Int.
3.times do |n|
puts n
end
# Output:
# 0
# 1
# 2
String
Μια String είναι μια ακολουθία χαρακτήρων και δεν ανήκει στο module Enumerable, που σημαίνει ότι έχει το δικό της σύνολο μεθόδων για επανάληψη πάνω στους χαρακτήρες.
Ο πιο συνηθισμένος τρόπος για να επαναλάβεις πάνω σε μια String είναι να χρησιμοποιήσεις τη μέθοδο each_char, η οποία περνάει κάθε χαρακτήρα της String σε ένα μπλοκ.
Η μέθοδος each_char περνάει ένα αντικείμενο Char και όχι ένα αντικείμενο String στο μπλοκ.
str = "hello"
str.each_char { |char| puts char }
# Output:
# h
# e
# l
# l
# o
Ένας άλλος τρόπος για να επαναλάβεις πάνω σε μια String είναι να χρησιμοποιήσεις τη μέθοδο each_line.
Αυτή η μέθοδος χρησιμοποιείται κυρίως όταν διαβάζεις ένα αρχείο γραμμή προς γραμμή.
str = "hello\nworld"
str.each_line do |line|
puts line
end
# Output:
# hello
# world
Enumerable
Το module Enumerable παρέχει έναν αριθμό μεθόδων για επανάληψη πάνω στα στοιχεία μιας συλλογής.
Οι συλλογές που περιλαμβάνουν το module Enumerable είναι οι Array, Range, Hash, Set και άλλες, οι οποίες θα καλυφθούν σε επόμενες έννοιες.
Ο πιο συνηθισμένος τρόπος για να επαναλάβεις πάνω σε έναν Array είναι να χρησιμοποιήσεις τη μέθοδο each, η οποία περνάει κάθε στοιχείο του Array σε ένα μπλοκ.
arr = [5, 2, 3]
arr.each do |element|
puts element
end
# Output:
# 5
# 2
# 3
Η μέθοδος map είναι ένας άλλος τρόπος για να επαναλάβεις πάνω σε έναν Array, επιστρέφει έναν νέο Array που περιέχει τα αποτελέσματα της εφαρμογής του μπλοκ σε κάθε στοιχείο.
Είναι παρόμοια με τη μέθοδο each, αλλά επιστρέφει έναν νέο Array με τα μετασχηματισμένα στοιχεία.
Ο μετασχηματισμός είναι πολύ χρήσιμος όταν θέλεις να εφαρμόσεις μια συνάρτηση σε κάθε στοιχείο της συλλογής, κάτι που είναι μια συνηθισμένη λειτουργία.
arr = [1, 2, 3]
new_arr = arr.map do |element|
element * 2
end
new_arr
# => [2, 4, 6]
Με μια ροή ελέγχου όπως η if μπορείς επίσης να φιλτράρεις ποια στοιχεία θα μετασχηματίσεις.
arr = [1, 2, 3]
new_arr = arr.map do |element|
if element.odd?
element * 2
else
element
end
end
new_arr
# => [2, 2, 6]
Μερικές φορές χρειάζεται να ξέρεις τη θέση του στοιχείου πάνω στο οποίο επαναλαμβάνεις, μπορείς να χρησιμοποιήσεις τη μέθοδο each_with_index ή τη μέθοδο map_with_index γι' αυτό.
Περνάει κάθε στοιχείο και τη θέση του σε ένα μπλοκ, η μέθοδος δέχεται επίσης ένα προαιρετικό όρισμα για να ορίσεις τη θέση από την οποία ξεκινά.
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
Σημείωσε ότι η μέθοδος each_char_with_index είναι επίσης διαθέσιμη για αντικείμενα String.
Η μέθοδος sum επιστρέφει το άθροισμα όλων των στοιχείων της συλλογής, δέχεται επίσης ένα προαιρετικό μπλοκ για να μετασχηματίσεις τα στοιχεία πριν τα αθροίσεις.
Δέχεται επίσης ένα προαιρετικό όρισμα για να ορίσεις την αρχική τιμή του αθροίσματος.
arr = [1, 2, 3]
arr.sum
# => 6
arr.sum(2) { |n| n * 2 }
# => 14
Η reduce, ή fold όπως είναι γνωστή σε άλλες γλώσσες, είναι μια μέθοδος που, με μια μέθοδο συνδυασμού και μια αρχική τιμή, θα συνδυάσει όλα τα στοιχεία της συλλογής.
Η μέθοδος reduce έχει έναν συσσωρευτή που περνάεται στο μπλοκ, ο συσσωρευτής είναι το αποτέλεσμα της προηγούμενης επανάληψης.
Αυτό γίνεται μια αναδρομική διαδικασία που θα συνδυάσει όλα τα στοιχεία της συλλογής.
arr = [1, 2, 3]
arr.reduce(0) do |acc, n|
acc + n
end
# => 6
Η reduce μπορεί να φαίνεται παρόμοια με τη sum, αλλά η reduce είναι πιο ευέλικτη γιατί σου επιτρέπει να ορίσεις την αρχική τιμή του συσσωρευτή και τη μέθοδο συνδυασμού.
Η reduce μπορεί να χρησιμοποιηθεί για να υλοποιήσεις τη sum, τη count και άλλες μεθόδους.
Στο παιχνίδι με κάρτες Spellbound Steel, έχεις μια τράπουλα με κάρτες που έχουν είτε διαφορετικούς χαρακτήρες, όπως warriors, mages και rogues, είτε διαφορετικά ξόρκια, όπως fireball, ice storm και lightning bolt. Στο παιχνίδι παίζουν δύο έως τέσσερις παίκτες και ο στόχος είναι να νικήσεις τους άλλους παίκτες παίζοντας κάρτες με υψηλότερα επίπεδα ισχύος.
Θέλεις να αποκτήσεις το πάνω χέρι στο παιχνίδι δημιουργώντας διάφορες μεθόδους για να υπολογίζεις, να ταξινομείς και να συγκρίνεις τα επίπεδα ισχύος των καρτών.
Δεν είσαι σίγουρος αν μια κάρτα βρίσκεται στην τράπουλα ή όχι. Γι' αυτό θέλεις μια μέθοδο που να σου λέει πού μπορείς να βρεις την πρώτη κάρτα στην τράπουλα του είδους που ψάχνεις. Ή, αν η κάρτα δεν βρίσκεται στην τράπουλα, θέλεις να το ξέρεις κι αυτό.
Υλοποίησε μια μέθοδο SpellboundSteel.find_card? που παίρνει έναν Array από String κάρτες και μια String κάρτα προς εύρεση.
Η μέθοδος πρέπει να επιστρέφει τη θέση της πρώτης κάρτας στην τράπουλα που ταιριάζει με την κάρτα προς εύρεση.
Αν η κάρτα δεν βρίσκεται στην τράπουλα, η μέθοδος πρέπει να επιστρέφει nil.
cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt", "Mage"]
SpellboundSteel.find_card?(cards, "Mage")
# => 1
Για να γίνουν οι κάρτες πιο ευανάγνωστες, θέλεις να μετατρέψεις όλους τους χαρακτήρες στα ονόματα των καρτών σε κεφαλαίους. Έτσι θα βλέπεις εύκολα τα ονόματα των καρτών όταν παίζεις τις κάρτες.
Υλοποίησε μια μέθοδο SpellboundSteel.capitalize_cards που παίρνει έναν Array από String κάρτες και επιστρέφει τις κάρτες με όλους τους χαρακτήρες κεφαλαίους.
cards = ["warrior", "mage", "rogue", "fireball", "ice storm", "lightning bolt"]
SpellboundSteel.capitalize_cards(cards)
# => ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]
Στο παιχνίδι είναι σημαντικό να υπολογίζεις το επίπεδο ισχύος όλων των καρτών. Η ισχύς όλων των καρτών φαίνεται στον παρακάτω πίνακα:
| Τύπος κάρτας | Επίπεδο ισχύος |
|---|---|
| Warrior | 10 |
| Mage | 20 |
| Rogue | 30 |
| Fireball | 15 |
| Ice Storm | 25 |
| Lightning Bolt | 35 |
Υλοποίησε μια μέθοδο SpellboundSteel.calculate_power_level που παίρνει έναν Array από String κάρτες και επιστρέφει το συνολικό επίπεδο ισχύος όλων των καρτών.
cards = ["Warrior", "Mage", "Rogue", "Fireball", "Ice Storm", "Lightning Bolt"]
SpellboundSteel.calculate_power_level(cards)
# => 135
Στο παιχνίδι υπάρχουν οι λεγόμενες καταραμένες κάρτες. Αυτές οι κάρτες είναι κρυφές κάρτες που μπορεί να τις αποκωδικοποιήσει μόνο ο παίκτης που τις έπαιξε. Για να αποκωδικοποιήσεις την κάρτα, πρέπει να πάρεις κάθε δεύτερο χαρακτήρα στο όνομα της κάρτας και να τον αφαιρέσεις. Έτσι θα πάρεις το όνομα της κάρτας.
Υλοποίησε μια μέθοδο SpellboundSteel.decode_card που παίρνει μια String κάρτα και επιστρέφει την αποκωδικοποιημένη κάρτα.
SpellboundSteel.decode_card("Wbalrrrlimoqr")
# => "Warrior"
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Crystal με 26 έννοιες142 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.