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