Esercitazione di Laboratorio
Transcript
Esercitazione di Laboratorio
Esercitazione di Laboratorio - Sudoku Alberto Montresor 1 Marco Biazzini Introduzione Lo scopo principale di questa esercitazione di laboratorio è quello di scrivere un programma che sia in grado di risolvere il gioco del Sudoku tramite la tecnica del backtracking. Collegato a questo obiettivo minimo, è interessante valutare obiettivi diversi. Una breve introduzione alle regole del gioco è la seguente: si gioca su una griglia 9 × 9, divisa in 9 sottogriglie (blocchi) 3 × 3. Ogni cella di una griglia può assumere valori da 1 a 9. E’ possibile utilizzare il termine “linea virtuale” per fare riferimento alle 9 celle che stanno in una riga, colonna o blocco. All’inizio, alcune celle sono riempite con numeri da 1 a 9; l’obiettivo è completare la griglia in modo tale che ogni linea virtuale (riga, colonna, o blocco) contenga tutte le cifre esattamente una volta. In figura 1 è possibile vedere una griglia iniziale e la corrispondente griglia completata. Figura 1: Un esempio di sudoku Il fatto che la griglia sia 9 × 9, e che i simboli da inserire siano i numeri 1 . . . 9 è motivato dal fatto che il gioco è risolto da essere umani. Quando il gioco viene risolto da un calcolatore, qualunque dimensione n2 × n2 , con n2 blocchi di dimensione n × n è possibile; inoltre, qualunque insieme di n simboli distinti è accettabile. 2 Descrizione dell’input Il programma deve leggere la descrizione delle griglia iniziale da un file specificato da riga di comando. L’input è organizzato in questo modo. • Una linea contenente la dimensione n della griglia n × n. • Una linea contenente una stringa di n caratteri che rappresenta i simboli utilizzati; 1 • n linee di n caratteri contenente la griglia iniziale; per indicare una cella vuota si utilizza un carattere ’.’. Il programma deve essere ovviamente in grado di individuare input non corretti (valore n diverso da k 2 per qualche k, stringa di simboli di lunghezza diversa da n, caratteri ripetuti nella stringa di simboli, carattere ’.’ nella stringa di simboli, numeri di linee contenenti la griglia inferiore a n e numero di caratteri inferiore per linea inferiore a n, caratteri nella griglia diversi da quelli contenuti nella stringa di simboli). Un esempio di file di input potrebbe essere il seguente: 9 123456789 ..48..... .9.46..7. .5....614 21.6..5.. 58.7.9.41 ..7..8.69 345....9. .6..37.2. .....41.. 3 Esercizio base Scrivere un programma in grado di risolvere una griglia iniziale tramite la tecnica del backtracking. Il programma deve essere in grado di trovare tutte le soluzioni possibili. Una soluzione deve essere stampata in standard output e deve essere costituita da n linee di n caratteri. Se non ci sono soluzioni, non viene stampato nulla (nemmeno un warning). Se c’è una sola soluzione, questa viene stampata senza linee in testa o in coda. Se ci sono più soluzioni, queste vengono stampate separate da un ritorno a capo. Un esempio potrebbe essere il seguente: 123456789 456789123 789123456 345678912 678912345 912345678 234567891 567891234 891234567 123456789 789123456 456789123 345678912 912345678 678912345 234567891 891234567 567891234 Il main() deve essere contenuto in un file Java di nome RisolviSudoku. Una soluzione corretta di questa parte permette di ottenere una votazione sufficiente. 2 4 Generazione di griglie Normalmente, un Sudoku “apprezzabile” ha un’unica soluzione. Per ottenere una griglia iniziale che abbia un’unica soluzione si può agire in questo modo. 1. Si assegna un certo numero di numeri casuali ad un griglia vuota, ovviamente senza infrangere le regole. 2. Si utilizza il meccanismo di backtracking per ottenere una qualunque soluzione S (ovviamente ce ne possono essere più di una, ma noi possiamo scegliere una qualunque). 3. Si copia la griglia S in due griglie current e previous 4. Fino a quando current ha una soluzione univoca (ottenuta lanciando il meccanismo di bactracking), si eseguono i seguenti passi: • previous := current • current è ottenuto da previous svuotando una delle celle 5. La nostra griglia iniziale si trova in previous. Il programma che genera le griglie legge un file specificato su linea di comando contenente una linea che descrive la dimensione n di una griglia n × n e una linea che descrive l’insieme degli n caratteri distinti. Ad esempio: 16 0123456789ABCDEF Deve essere possibile passare l’output di questo programma a RisolviSudoku del punto precedente. Il main() deve essere contenuto in un file Java di nome GeneraSudoku. Una soluzione corretta di questa parte permette di ottenere una votazione buona. 3 5 Valutare la complessità di un Sudoku Assieme a questo documento, trovate un articolo scritto da Tom Davis intitolato “The Mathematics of Sudoku”, su cui è basato questo documento. Questo articolo descrive un certo numero di tecniche “per esseri umani” per risolvere il Sudoku. In ordine di complessità, più o meno: 1. Unique Missing Candidate 2. Naked Singles 3. Hidden Singles 4. Locked Candidates 5. X-Wings 6. Swordfish 7. XY-Wing 8. XYZ-Wing 9. XY-Chains 10. Simple coloring 11. Multi-coloring 12. Remote Naked Pairs 13. Unique Solution Constraints 14. Forcing Chains Lo scopo della terza parte dell’esercizio è valutare la complessità di un Sudoku ottenuto nella sezione precedente. Per valutare una soluzione, si lavora in questo modo. Ad ogni passo, si provano, in ordine di difficoltà crescente, le tecniche elencate. Non appena una di queste ha successo, si aggiunge il numero trovato e si ritorna all’inizio della lista. Si tiene traccia del numero di volte in cui una tecnica ha avuto successo; si ottiene cosı̀ un array di contatori, con un indice per ogni tecnica. Per questo esercizio, non è necessario implementare tutte le tecniche elencate sopra. Tuttavia, the more the better... Inoltre, non è necessario lavorare con ogni tipo di dimensione, ma è sufficiente lavorare con le dimensioni 9 × 9. Tuttavia, se vedete come estendere le tecniche a dimensioni superiori, fate pure. L’input è lo stesso dalle Sezione 1. L’output é una lista di tecniche implementate con il numero di volte che è stata utilizzata questa tecnica, più la stampa della soluzione ottenuta, se disponibile, o nient’altro, se le tecniche implementate non sono state sufficienti a risolvere la griglia. Ad esempio: Unique Missing Candidate: 32 Naked Singles: 12 Hidden Singles: 11 123456789 789123456 456789123 345678912 912345678 678912345 234567891 891234567 567891234 Il main() deve essere contenuto in un file Java di nome ValutaSudoku. Una soluzione corretta di questa parte permette di ottenere una votazione ottima. 4