Σκακιέρα

Σκακιέρα

Άσκηση εκμάθησης

Εισαγωγή

Στη Go, μπορείς να κάνεις επανάληψη πάνω σε ένα slice χρησιμοποιώντας το for και μια θέση, ή μπορείς να χρησιμοποιήσεις το range. Το range σου επιτρέπει επίσης να κάνεις επανάληψη πάνω σε ένα map.

Κάθε επανάληψη επιστρέφει δύο τιμές: τη θέση/κλειδί και ένα αντίγραφο του στοιχείου σε αυτή τη θέση/κλειδί.

Επανάληψη σε ένα slice

Πανεύκολο: η επανάληψη σε ένα slice γίνεται με τη σειρά που περιμένεις.

xi := []int{10, 20, 30}
for i, x := range xi {
  fmt.Println(i, x)
}
// outputs:
// 0, 10
// 1, 20
// 2, 30

Επανάληψη σε ένα map

Η επανάληψη σε ένα map δημιουργεί ένα νέο πρόβλημα. Η σειρά τώρα είναι τυχαία.

hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
  fmt.Println(k, v)
}
// outputs, for example:
// 99 20
// 999 30
// 9 10
Note

Μπορεί να φαίνεται ότι η παραπάνω έξοδος είναι λανθασμένη, αφού κανείς θα περίμενε το πρώτο ζεύγος κλειδιού/τιμής στη δήλωση του map 9 10 να είναι το πρώτο που τυπώνεται και όχι το τελευταίο. Ωστόσο, τα map δεν έχουν σειρά από τη φύση τους: δεν υπάρχει πρώτο ή τελευταίο ζεύγος κλειδιού/τιμής. Γι' αυτό, όταν κάνεις επανάληψη στις καταχωρήσεις ενός map, η σειρά με την οποία θα επισκεφθούν οι καταχωρήσεις είναι τυχαία και δεν ακολουθεί κάποιο συγκεκριμένο μοτίβο. Αυτό σημαίνει ότι η παραπάνω έξοδος είναι πιθανή, αλλά μπορεί να διαφέρει από αυτό που θα πάρεις αν δοκιμάσεις να το τρέξεις μόνος σου. Για να μάθεις περισσότερα γι' αυτό, δες Προδιαγραφή της γλώσσας Go: ρήτρα range.

Επανάληψη παραλείποντας το κλειδί ή την τιμή

Στη Go, μια μεταβλητή που δεν χρησιμοποιείται θα πετάξει σφάλμα κατά τη μεταγλώττιση. Κάποιες φορές χρειάζεσαι μόνο την τιμή, όπως στο πρώτο παράδειγμα:

xi := []int{10, 20, 30}
for i, x := range xi {
  fmt.Println(x)
}
// Go build failed: i declared but not used

Μπορείς να αντικαταστήσεις το i με _, που λέει στον μεταγλωττιστή ότι δεν χρησιμοποιούμε αυτή την τιμή:

xi := []int{10, 20, 30}
for _, x := range xi {
  fmt.Println(x)
}
// outputs:
// 10
// 20
// 30

Αν θέλεις να τυπώσεις μόνο τη θέση, μπορείς να αντικαταστήσεις το x με _, ή απλώς να παραλείψεις τη δήλωση:

xi := []int{10, 20, 30}
// for i, _ := range xi {
for i := range xi {
  fmt.Println(i)
}
// outputs:
// 0
// 1
// 2

Ορισμός τύπων

Ο ορισμός τύπου δημιουργεί έναν νέο επώνυμο τύπο, διακριτό από κάθε άλλον τύπο, ακόμη και από έναν με τον ίδιο υποκείμενο τύπο.

type File []bool

Εδώ το File αναφέρεται σε μία μόνο κάθετη στήλη μιας σκακιέρας, που συνήθως χαρακτηρίζεται με γράμματα από το A έως το H. Κάθε τετράγωνο αυτής της στήλης αναπαρίσταται από μια τιμή Boolean (λογική τιμή) που δείχνει αν είναι κατειλημμένο ή όχι. Τώρα που το File έχει οριστεί, μπορούμε να το χρησιμοποιήσουμε μέσα σε άλλους ορισμούς:

type Chessboard map[string]File

board := Chessboard{
    "A": File{true, false, true},
    "B": File{false, true, false},
}

Το Chessboard αντιστοιχίζει αναγνωριστικά στηλών σε τιμές File. Κάθε File είναι ένα slice από Boolean που αναπαριστά τα τετράγωνα μιας στήλης της σκακιέρας. Χωρίς αυτούς τους ορισμούς τύπων, το board θα ήταν ένα map[string][]bool, που θα έκανε πιο δύσκολο να καταλάβεις τι αναπαριστούμε.

Οδηγίες

Ως λάτρης του σκακιού, θα ήθελες να γράψεις τη δική σου εκδοχή του παιχνιδιού. Ναι, μπορεί να υπάρχουν ήδη πολλές υλοποιήσεις του σκακιού διαθέσιμες στο διαδίκτυο, αλλά η δική σου θα είναι μοναδική!

Κάθε τετράγωνο της σκακιέρας προσδιορίζεται από ένα ζεύγος γράμματος και αριθμού:

  • Οι οριζόντιες σειρές τετραγώνων, που ονομάζονται ranks, αριθμούνται από το 1 έως το 8.
  • Οι κάθετες στήλες τετραγώνων, που ονομάζονται files, φέρουν ετικέτες από το A έως το H.
   A B C D E F G H
 8 # _ _ _ # _ _ # 8
 7 _ _ _ _ _ _ _ _ 7
 6 _ _ _ _ # _ _ # 6
 5 _ # _ _ _ _ _ # 5
 4 _ _ _ _ _ _ # # 4
 3 # _ # _ _ _ _ # 3
 2 _ _ _ _ _ _ _ # 2
 1 # _ _ _ _ _ _ # 1
   A B C D E F G H

1. Δεδομένης μιας σκακιέρας και ενός file, μέτρησε πόσα τετράγωνα είναι κατειλημμένα

Υλοποίησε τη συνάρτηση CountInFile(board Chessboard, file string) int. Θα πρέπει να μετράει τον συνολικό αριθμό των κατειλημμένων τετραγώνων διατρέχοντας ένα map. Επίστρεψε έναν ακέραιο. Επίστρεψε πλήθος μηδέν (0) αν το file που δόθηκε δεν βρίσκεται στο map.

CountInFile(board, "A")
// => 3

2. Δεδομένης μιας σκακιέρας και ενός rank, μέτρησε πόσα τετράγωνα είναι κατειλημμένα

Υλοποίησε τη συνάρτηση CountInRank(board Chessboard, rank int) int. Θα πρέπει να μετράει τον συνολικό αριθμό των κατειλημμένων τετραγώνων διατρέχοντας το rank που δόθηκε. Επίστρεψε έναν ακέραιο. Επίστρεψε πλήθος μηδέν (0) αν το rank που δόθηκε δεν είναι έγκυρο (όχι μεταξύ 1 και 8, συμπεριλαμβανομένων).

CountInRank(board, 2)
// => 1

3. Μέτρησε πόσα τετράγωνα υπάρχουν στη σκακιέρα που δόθηκε

Υλοποίησε τη συνάρτηση CountAll(board Chessboard) int. Θα πρέπει να μετράει πόσα τετράγωνα υπάρχουν στη σκακιέρα και να επιστρέφει έναν ακέραιο. Εφόσον δεν χρειάζεται να ελέγξεις το περιεχόμενο των τετραγώνων, σκέψου να χρησιμοποιήσεις range παραλείποντας και το index και το value.

CountAll(board)
// => 64

4. Μέτρησε πόσα τετράγωνα είναι κατειλημμένα στη σκακιέρα που δόθηκε

Υλοποίησε τη συνάρτηση CountOccupied(board Chessboard) int. Θα πρέπει να μετράει πόσα τετράγωνα είναι κατειλημμένα στη σκακιέρα. Επίστρεψε έναν ακέραιο.

CountOccupied(board)
// => 15
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Go Exercism

Έτοιμος να ξεκινήσεις την άσκηση Σκακιέρα;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Go με 34 έννοιες166 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.