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