ΕΡΓΑΣΙΑ 3 Παίζοντας Sudoku Ημερομηνία Ανάρτησης: 16/03/2018 Ημερομηνία Παράδοσης: 03/04/2018, 09:00 Εισαγωγή Για την τρίτη εργασία χρειάζεται να κατασκευάσετε ένα πρόγραμμα το οποίο παίζει και λύνει το γνωστό παιχνίδι Sudoku. Ουσιαστικά, το πρόγραμμα θα λαμβάνει τα στοιχεία για κάποιο πίνακα Sudoku (με file redirection από αρχείο κειμένου) θα συμπληρώνει τον πίνακα και θα τον παρουσιάζει. Η συμπλήρωση του πίνακα βασίζεται στον κανόνα του παιχνιδιού ότι ένας πίνακας Sudoku 9 x 9 θα πρέπει να περιλαμβάνει σε κάθε σειρά του, σε κάθε στήλη του και σε κάθε ένα από τα 9 εσωτερικά 3 x 3 τμήματά του (που προκύπτουν από την ομαδοποίηση των σειρών και στηλών του σε τριάδες) τον κάθε ένα από τους αριθμούς {1, 2, 3,.., 9}. Νοείται ότι η αρχική τοποθέτηση αριθμών σε δεδομένες θυρίδες του πίνακα (όπως διαβάζονται στην είσοδο του προγράμματος) δεν μπορεί να αλλάξει. Αυτές θεωρούνται κλειστές, ενώ οι υπόλοιπες θυρίδες είναι ανοικτές. Συνεπώς εδώ έχουμε ένα πρόβλημα ικανοποίησης περιορισμών, όπου δοκιμάζονται επιλογές και απορρίπτονται αυτές για τις οποίες προκύπτει κάποια παραβίαση του πιο πάνω κανόνα, μέχρις ότου να συμπληρωθεί με έγκυρο τρόπο ο δεδομένος πίνακας. Είναι επίσης ένα πρόβλημα αναζήτησης, αφού αναζητούνται έγκυρες τιμές για τις ανοικτές θυρίδες. Τα στοιχεία εισάγονται στο πρόγραμμα από κάποιο αρχείο κειμένου, μέσα σε ένα πίνακα δύο διαστάσεων 9 x 9. Για την κράτηση εναλλακτικών επιλογών για τις διάφορες ανοικτές θυρίδες του πίνακα, προκύπτει η ανάγκη να κρατούμε διάφορους εναλλακτικούς πίνακες, μερικώς συμπληρωμένους ως προς τις ανοικτές θυρίδες τους. Ο σχετικός αλγόριθμος εξηγείται στη συνέχεια. Όπως θα δείτε ο αλγόριθμος αυτός αξιοποιεί ένα πίνακα, τα στοιχεία του οποίου είναι πίνακες 9 x 9, και επομένως είναι ένας τρισδιάστατος πίνακας, αλλά στην ουσία τον χειριζόμαστε ως ένα μονοδιάστατο πίνακα (μια στοίβα όπως θα δούμε) για την αποθήκευση εναλλακτικών (μερικώς ολοκληρωμένων) sudokus. Πριν εξηγηθεί ο εν λόγω αλγόριθμος, παρουσιάζονται κάποια παραδείγματα. Παραδείγματα Παράδειγμα 1 Το πιο κάτω παράδειγμα θεωρείται μέτριας δυσκολίας για τον άνθρωπο. Φυσικά για τον υπολογιστή όλα τα παραδείγματα είναι εξίσου εύκολα, συμπεριλαμβανομένων αυτών που θεωρούνται δύσκολα ή πολύ δύσκολα για τον άνθρωπο, όπως τα υπόλοιπα παραδείγματα που δίνονται. ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 1
1 9 7 9 6 5 5 2 6 1 2 9 7 4 4 5 2 6 3 4 7 3 7 5 Το πιο πάνω παράδειγμα αναπαρίσταται σε ένα αρχείο κειμένου, π.χ. το αρχείο sud.txt, ως ακολούθως: 1 0 0 9 0 0 0 0 7 0 9 6 0 5 0 0 0 0 5 0 2 0 0 0 0 6 0 0 0 0 0 0 0 0 1 0 0 2 9 0 0 0 7 4 0 0 4 0 0 0 0 0 0 0 0 5 0 0 0 0 2 0 6 0 0 0 0 3 0 4 7 0 3 0 0 0 0 7 0 0 5 Επομένως, η κάθε ανοικτή (διαθέσιμη για εισαγωγή) θυρίδα αντιπροσωπεύεται με το 0 και η κάθε κλειστή θυρίδα (μη διαθέσιμη για τροποποίηση από το χρήστη) με ένα μονοψήφιο αριθμό από 1 έως 9. Νοείται ότι ο αρχικός, μερικώς συμπληρωμένος πίνακας είναι έγκυρος, δηλαδή το ίδιο ψηφίο, εξαιρουμένου του 0, δεν εμφανίζεται πάνω από μια φορά στη σειρά, ή τη στήλη, ή το τμήμα 3 x 3, που το περιλαμβάνει. Το αποτέλεσμα του προγράμματος για το πιο πάνω παράδειγμα δίνεται πιο κάτω: ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 2
$ java PlaySudoku < sud.txt ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΥΠΡΟΥ - ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ 1 8 3 9 6 4 5 2 7 4 9 6 7 5 2 1 8 3 5 7 2 1 8 3 9 6 4 7 3 5 4 9 8 6 1 2 6 2 9 3 1 5 7 4 8 8 4 1 2 7 6 3 5 9 9 5 7 8 4 1 2 3 6 2 6 8 5 3 9 4 7 1 3 1 4 6 2 7 8 9 5 Παράδειγμα 2 4 9 9 1 2 8 1 4 7 8 1 7 8 1 3 2 5 9 5 8 7 3 6 5 ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 3
Αρχείο diffsud.txt 4 0 0 0 0 0 0 0 9 0 9 1 0 0 0 2 8 0 0 0 0 0 1 0 0 0 0 0 4 0 7 0 8 0 1 0 0 0 7 0 0 0 8 0 0 0 1 0 3 0 2 0 5 0 0 0 0 0 9 0 0 0 0 0 5 8 0 0 0 7 3 0 6 0 0 0 0 0 0 0 5 $ java PlaySudoku < diffsud.txt 4 8 5 2 3 6 1 7 9 3 9 1 4 7 5 2 8 6 7 6 2 8 1 9 5 4 3 5 4 9 7 6 8 3 1 2 2 3 7 9 5 1 8 6 4 8 1 6 3 4 2 9 5 7 1 7 4 5 9 3 6 2 8 9 5 8 6 2 4 7 3 1 6 2 3 1 8 7 4 9 5 ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 4
Παράδειγμα 3 4 2 9 2 4 6 3 7 4 6 3 8 6 9 8 9 7 5 3 4 1 6 5 7 Αρχείο verydiffsud.txt 0 0 0 4 0 2 0 0 0 9 0 0 0 0 0 0 0 2 0 0 4 0 6 0 3 0 0 0 7 0 0 4 0 0 6 0 0 0 3 8 0 6 9 0 0 0 8 0 0 9 0 0 7 0 0 0 5 0 3 0 4 0 0 1 0 0 0 0 0 0 0 6 0 0 0 5 0 7 0 0 0 ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 5
$ java PlaySudoku < verydiffsud.txt 3 6 8 4 5 2 7 9 1 9 5 1 7 8 3 6 4 2 7 2 4 1 6 9 3 5 8 5 7 9 2 4 1 8 6 3 4 1 3 8 7 6 9 2 5 6 8 2 3 9 5 1 7 4 2 9 5 6 3 8 4 1 7 1 3 7 9 2 4 5 8 6 8 4 6 5 1 7 2 3 9 Αλγόριθμος Όπως ήδη αναφέρθηκε η δομή δεδομένων πρέπει να είναι ένας τρισδιάστατος πίνακας που απεικονίζει μια στοίβα από sudokus: int[][][] sudostack = new int [100000][9][9]; Η πρώτη διάσταση αποτελείται από ένα μεγάλο πλήθος στοιχείων, π.χ. 100000 (το μέγεθος της στοίβας). Αρχικά το sudostack περιλαμβάνει μόνο το αρχικό Sudoku (οι 9x9 θέσεις του sudostack[0]) που διαβάζεται από το αρχείο εισόδου μέσω ανακατεύθυνσης. Σε κάθε βήμα το Sudoku που είναι το τελευταίο που μπήκε μέσα (για αυτό εξάλλου μιλούμε για στοίβα) αυτό που είναι στο πάνω μέρος της στοίβας αντικαθίσταται με όλες τις πιθανές έγκυρες επεκτάσεις του, στη βάση της πρώτης σε σειρά ανοικτής θυρίδας του, όπου η μέτρηση των θυρίδων μπορεί να γίνει ανά σειρές και ανά στήλες. Στο παράδειγμα 1 πιο πάνω (αρχείο sud.txt), η πρώτη σε σειρά ανοικτή θυρίδα είναι η θυρίδα [0][1]. Βάσει της σειράς της αποκλείονται οι τιμές 1, 7 και 9. Βάσει της στήλης της αποκλείονται οι τιμές 2, 4, 5, και 9. Τέλος, βάσει του σχετικού τμήματος 3 x 3 αποκλείονται οι τιμές 1, 2, 5, 6 και 9. Ως εκ τούτου, οι πιθανές εναλλακτικές τιμές για τη συγκεκριμένη θυρίδα είναι οι τιμές 3 και 8. Το τελευταίο Sudoku που μπήκε στη στοίβα (βασικά για την ώρα, η στοίβα είχε μόνο ένα Sudoku μέσα, αυτό που είχε τους αριθμούς που διαβάστηκαν από το αρχείο) αντικαθίσταται επομένως στη στοίβα υπάρχουν τώρα δύο νέα Sudoku, όπου στο ένα η συγκεκριμένη θυρίδα λαμβάνει την τιμή 3 και στο άλλο την τιμή 8, όπως διαφαίνεται στο πιο κάτω σχήμα (σε αυτή την περίπτωση η στοίβα έχει δύο στοιχεία, όπου το τελευταίο της στοιχείο είναι αυτό που δεικνύεται από τη δεύτερη σε σειρά θυρίδα της): ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 6
sudostack 1 8 0 9 0 0 0 0 7 0 9 6 0 5 0 0 0 0 5 0 2 0 0 0 0 6 0 0 0 0 0 0 0 0 1 0 0 2 9 0 0 0 7 4 0 0 4 0 0 0 0 0 0 0 0 5 0 0 0 0 2 0 6 0 0 0 0 3 0 4 7 0 3 0 0 0 0 7 0 0 5 1 0 1 3 0 9 0 0 0 0 7 0 9 6 0 5 0 0 0 0 5 0 2 0 0 0 0 6 0 0 0 0 0 0 0 0 1 0 0 2 9 0 0 0 7 4 0 0 4 0 0 0 0 0 0 0 0 5 0 0 0 0 2 0 6 0 0 0 0 3 0 4 7 0 3 0 0 0 0 7 0 0 5 Αν σε κάποια φάση, το τελευταίο Sudoku που μπήκε μέσα στη στοίβα δεν έχει έγκυρες επεκτάσεις (δεν μπορεί μπει κανένας αριθμός σε καμμιά θέση και να παραμείνει έγκυρο), τότε συνεχίζουμε (να ψάχνουμε για έγκυρες επεκτάσεις) με το προηγούμενο Sudoku (το ακριβώς από κάτω Sudoku στη στοίβα). Η πιο πάνω διαδικασία συνεχίζεται, μέχρις ότου να δημιουργηθεί πλήρως και με εγκυρότητα το επιδιωκόμενο Sudoku. Εκτός από την περαιτέρω εμπέδωση της δομής του πίνακα (πολλαπλών διαστάσεων) και μιας πρώτης επαφής με την έννοια της στοίβας, κύριος στόχος της τρέχουσας εργασίας είναι η άρθρωση και αφαιρετικότητα προγράμματος με τη χρήση ενός αριθμού βοηθητικών συναρτήσεων, οι οποίες στο σύνολό τους αντιπροσωπεύουν το πως έχει διασπαστεί το πρόβλημα σε υπό-προβλήματα. ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 7
Παράδοση Όταν έχετε τελειώσει με τον πηγαίο κώδικα, μεταγλωττίστε το και βεβαιωθείτε ότι τρέχει σωστά. Παραδώστε το αρχείο πηγαίου κώδικα (userid_ erg3.java) και μια λίστα δοκιμής (userid_erg3.txt) με ένα τρέξιμο του προγράμματος ηλεκτρονικά μέσω του submit assignment κάτω από το Ασκήσεις Εργασία 3 στην ιστοσελίδα του μαθήματος μέχρι τις 03/04/2018 και ώρα 09:00. Όπου userid βάλτε το username που σας δόθηκε από το τμήμα. Προσοχή: Το σύστημα ελέγχει το χρόνο παράδοσης εργασιών γι αυτό μην περιμένετε την τελευταία στιγμή να κάνετε submit την εργασία σας. Βαθμολογία Ένα πρόγραμμα για να πάρει όλες τις μονάδες είναι απαραίτητο να: χρησιμοποιεί σχόλια έχει ευθυγραμμισμένο κώδικας χρησιμοποιεί αυτό-επεξηγηματικά ονόματα για τις μεταβλητές δουλεύει σωστά κάνει όλους τους απαραίτητους ελέγχους χρησιμοποιεί μεθόδους (αρθρωτή σχεδίαση) Για όλα τα παραπάνω ακολουθήστε τις οδηγίες που περιγράφονται εδώ: http://introcs.cs.princeton.edu/java/11style/. Το αρχείο με το πηγαίο κώδικα πρέπει οπωσδήποτε να περιέχει μια συμπληρωμένη κατάλληλα επικεφαλίδα από σχόλια στην αρχή του αρχείου όπως: /** * Author: Γράψτε εδώ το όνομα σας * Written:../../2018 * Last updated:../../2018 * * Compilation: javac userid_erg3.java * Execution: java userid_erg3 * * Γράψτε εδώ πληροφορίες σχετικά με το τι κάνει * το πρόγραμμα * */ Κριτήρια αξιολόγησης Έγκυρη ανάγνωση δεδομένων μέσω ανακατεύθυνσης 5 ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 8
Έλεγχος εγκυρότητας Soduku για 30 γραμμές, στήλες και υπό-πίνακες 3x3 Έλεγχος ολοκλήρωσης παιχνιδιού 5 Έγκυρη διαδικασία εκτέλεσης παιχνιδιού 40 Εκτύπωση αποτελέσματος 5 Σχόλια Ονόματα μεταβλητών 15 αρθρωτή σχεδίαση (χρήση μεθόδων) ΣΥΝΟΛΟ 100 Η εργασία είναι ατομική. Μπορείτε να συζητήσετε για αυτήν με τους συμφοιτητές σας, ωστόσο ποτέ δεν είναι αποδεκτό για σας να δείτε τον κώδικα κάποιου άλλου ή να κάνετε από κοινού τον κώδικα. Φυσικά, αν έχετε οποιεσδήποτε ερωτήσεις σχετικά με την εργασία, είμαστε πάντα στη διάθεσή σας για βοήθεια. Ανίχνευση αντιγραφής θα τιμωρείται με μηδενισμό. Κώδικας που δε μεταγλωττίζει ή δεν τρέχει (crashes) παίρνει αυτόματα βαθμολογία 0. ΕΠΛ131 Εργασία 3. Υπεύθυνος Εργασίας: Παύλος Αντωνίου 9