SUDOKU
Il gioco:
dato n >2 , si considera una matrice
n2); nella figura che segue n=3;
n2 x n2 (le righe e le colonne le numeriamo da 1 a
alcune caselle vengono riempite con dei valori iniziali (qui non ci preoccupiamo di
come si scelgono questi valori .....); nella figura sono i numeri "grandi";
il gioco consiste nel completare la matrice in modo tale che:
o ogni riga ed ogni colonna della matrice contenga (una ed una volta sola) tutti
i numeri da 1 a n2;
o lo stesso per gli n2 "quadranti" di dimensione n x n; nella figura sono i 9
riquadri con bordo spesso, ciascuno contenente 9 caselle.
Algoritmo per soluzione su carta
1. si parte con la matrice contenente i valori iniziali; per chiarezza coloriamo le caselle
contenenti questi valori iniziali;
2. nelle altre caselle si scrivono tutti i numeri che possono starci, compatibilmente con i
valori iniziali e le regole (vedi figura);
Ciclo:
si ripetono i passi successivi 3 e 4 fino a che la matrice non è tutta colorata, oppure fino
a quandoci si trova bloccati .....
3. si controlla se tra le caselle non colorate c'è una casella, sia (riga, col), che contiene un
solo valore, sia val; nella figura: riga = 6, col = 7, val = 5;
allora val diventa valore definitivo per la casella (riga, col), che quindi viene colorata;
inoltre si vanno ad aggiornare tutte le caselle non colorate che stanno sulla riga riga,
sulla colonna col, nel quadrante che contiene (riga, col), cancellando val dai valori
possibili;
4
si compone di 4a, 4b, 4c
4a per ciascuna riga, si controlla se su quella riga c'e' un valore, sia val, che compare in
una sola casella non colorata, sia (riga, col); nella figura, ad es. : riga=2, col=7, val=4;
allora val diventa definitivo per la casella (riga, col), che quindi viene colorata;
inoltre si vanno ad aggiornare tutte le caselle non colorate che stanno sulla colonna col
e nel quadrante che contiene (riga, col), cancellando val dai valori possibili;
4b come 4a, ma per ciascuna colonna
4c come 4a, ma per ciascun quadrante
Figura
possono esserci errori, però questo non crea problemi .....
1
7
2 5
8
2 5
8
4
1 3
6 9
1 3
5 9
1 5
6 9
1 2
3
1 2
3 5
6
3
9
7
2
1 5
1 4
5
1 5
8
1
2 4
2 4
5
1
8
3 6
9
3
5
7
2 3
5 9
2 3
4 5
5
2 6
7 8
2 7
8
1 2
6 9
1 6
7 9
1 2
9
3
4
1 2
3
2
2 7
5
8
4
1 9
1 2
7 9
6
1
4
2 3
6
3 6
7
2 3
5
2 5
7
8
4 5
7 9
6
1 3
9
1 3
4 9
8
2
1 3
5
1 3
4 5
1 2
4
2 4
2 3
1 2
3
5
7
8
6
9
1 2
4 8
2 4
589
2 3
5 8
1 2
3 9
1 3
4 9
6
1 4
5
1 3
5
7
9
1
9
4
7
9
5
Programma per l'algoritmo di sopra:
definisce la costante n (che non sarà certo un numero molto grande; es n=3, 4, ...) e
mette in piedi le strutture dati necessarie (vedere sotto);
legge da (tastiera o file) i valori iniziali e "colora le caselle" corrispondenti;
nel file i valori sono forniti nella forma
riga colonna valore
esegue il passo 2 descritto sopra; vedere sotto
esegue il ciclo detto sopra, utilizzando delle procedure/funzioni, per i punti 3 e 4;
stampa il risultato (anche incompleto)
Strutture dati
Per la matrice uso un array a tre dimensioni, che si descrive meglio pensando ad un array
a due dimensioni (da 1 a n*n) i cui elementi sono a loro volta array unidimensionali con
indici da 0 a n2 e valori interi.
Negli array unidimensionali:
la posizione 0 è per colore+valore definitivo: valore 0 = non colorato, valore non
zero, sia v, allora: colorato e v è il valore definitivo;
2
le rimanenti posizioni servono solo per per le caselle non colorate e rappresentano,
stile bit-vector, i valori possibili.
Quindi
const n = 3 ;
NN = n*n
type Vettore = array [ 0 .. NN ] of integer
var mat : array [1 ..NN, 1 .. NN] of Vettore
inizializzazione:
per j = 1,2,3, ... ,NN :
per k= 1,2,3, ... ,NN :
{
mat [j , k] [0] <---- 0
per i = 1, ... NN :
mat [j , k] [i] <--- 1
// vedi
Nota [ $ ]
}
Nota [ $ ]
se mat [j , k] [ i ] è 1 allora i è un valore possibile per la cella [j, k] ;
se invece è 0 allora i non è un valore possibile per la cella [j, k] ;
nelle celle colorate, il valore di
mat [j , k] [i] è irrilevante
per le altre, al passo due è comodo procedere "per sottrazione": per ogni cella
"colorata", si lavora sulla sua riga, poi sulla colonna, poi sul quadrante, togliendo da
tutte le celle non colorate il valore trovato in quella colorata.
Lettura dei dati:
Banale.
Passo due
Lavorare sulle righe o sulle colonne è abbastanza banale.
Il problema è lavorare sui quadranti ... Ma non e` troppo complicato.
Supponiamo di essere posizionati sulla cella [riga, col];
la prima cosa da fare è individuare gli indici della cella in alto a sinistra del quadrante cui
appartiene la cella [riga, col]; questi indici sono:
baseriga = 1+((riga-1) div n)*n
e
basecol = 1+ ((col-1) div n)*n
[ qui viene meglio in C dove si numera da 0 a NN-1 ]
Allora, per percorrere tutto il quadrante (inclusa le cella stessa) basta fare:
per k = 1, 2, , n :
per j = 1, 2, ..., n :
matrice[baseriga+k, basecol+j] ......
Ciclo
si controlla con due condizioni:
3
abbiamo colorato tutto: si usa un contatore conta che parte da zero all'inizio del
programma; ogni volta che si colora una casella (anche nella fase di lettura dati) si
incrementa il contatore; sappiamo che il limite è NN * NN
non facciamo progressi: nel ciclo, per prima cosa si prova ad usare la regola 3 e poi si
passa alla 4; se non produce nulla, allora siamo bloccati (servono altre tecniche che non
vediamo).
Quindi, il ciclo è del tipo
progresso <--- vero
while (conta< NN*NN) and progresso do {
progresso <--- falso
prova ad applicare la regola 3
se ci riesci, allora
(vedi sotto);
progresso <---- vero
(inoltre conta sarà incrementato)
if (conta = NN*NN) then break
[ else ] prova regola 4 ........ (vedi sotto)
}
Prova ad applicare regola 3
Ovviamente, ci sono varie alternative ....
Mi sembra piu' facile usare una procedura, chiamando
tre (matrice, conta, progresso)
La procedura, applica la regola 3 con un for che spazza tutte le caselle; quindi può
colorare tante caselle; ogni volta modifica la matrice, incrementa conta e mette progresso a
vero.
Prova ad applicare regola 4
Si prova 4a per tutte le righe; si controlla conta; se non siamo alla fine, si passa ad
applicare la 4b a tutte le colonne; si controlla conta; se non siamo alla fine, si passa ad
applicare la 4c a tutti i quadranti;
per comodità si usano tre procedure: quattro_a, quattro_b, quattro_c.
FINE
4