Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 22
  1. #1
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347

    [Java] problema NullPointerException

    allora, ho creato questa classe che mi dovrebbe risolvere un sudoku, quando è vuoto lo risolve ma se glielo do con numeri gia preimpostati, quando provo a stampare la matrice risolta mi da una null pointer exception(nel metodo toString), come se gli oggetti Cella di cui è costituita la matrice non fossero stati istanziati... mi aiutate a trovare dove sta l'errore?
    codice:
    package sudoku_solver;
    
    import util.Cella;
    
    public class SudokuSolver2{
    
    	private Cella[][] sudoku;
    	private Cella[][] tmp;
    	private Cella[][][] possibiliSoluzioni;
    	int numeroSoluzioni;
    
    	public SudokuSolver2(Cella[][] sudoku, int numeroSoluzioni){
    		if(sudoku.length != 9 || sudoku[0].length != 9 || numeroSoluzioni < 1)
    			throw new IllegalArgumentException();
    		this.sudoku = sudoku;
    		this.numeroSoluzioni = numeroSoluzioni;
    		this.possibiliSoluzioni = new Cella[numeroSoluzioni][9][9];
    	}
    	
    	public void risolvi(){
    		tmp = sudoku;
    		riempi(0,0);
    	}
    	
    	private void riempi(int row, int col){
    		boolean completato = false;
    		/*
    		 * primo caso di uscita
    		 */
    		if(row > 8){
    			completato = true;
    			return;
    		}
    		if(tmp [row][col].getState() == Cella.Stato.IMPOSTATO)
    			avanza(row, col);
    		else{
    			for(int n = 1; n< 10; n++){
    				/*
    				 * se un risolvi chiama una return, si ritorna qui,
    				 * quindi anche qui si deve controllare se il sudoku
    				 * è stato gia completato
    				 */
    				if(!completato && assegnabile(row, col, n)){
    					assegna(row, col, n);
    					avanza(row, col);
    				}else{
    					return;
    				}
    			}
    			deassegna(row, col);
    		}
    	}
    
    	private void avanza(int row, int col){
    		if(col < 8)
    			riempi(row, col + 1);// vai avanti sulla stessa riga
    		else
    			riempi(row + 1, 0);// altrimenti vai a capo
    	}
    
    	private void assegna(int row, int col, int n){
    		tmp[row][col].setVal(n);
    		tmp[row][col].setState(Cella.Stato.ASSEGNATO);
    	}
    
    	private void deassegna(int row, int col){
    		tmp[row][col].setVal(0);
    		tmp[row][col].setState(Cella.Stato.NON_ASSEGNATO);
    	}
    
    	private boolean assegnabile(int row, int col, int n){
    		// controllo sulla riga
    		for(int i = 0; i < 9; i++)
    			if(sudoku[row][i].getVal() == n)
    				return false;
    		// controllo sulla colonna
    		for(int i = 0; i < 9; i++)
    			if(sudoku[i][col].getVal() == n)
    				return false;
    		//@formatter:off
    		//determinamento del settore da controllare
    //		int r, c;
    //		if(row < 3)
    //			r = 0;// si trova nella prima riga
    //		else if(row >= 3 && row < 6)
    //			r = 3;// nella seconda
    //		else
    //			r = 6;// nella terza
    //		if(col < 3)
    //			c = 0;// si trova nella prima colonna
    //		else if(col >= 3 && col < 6)
    //			c = 3;// nella seconda
    //		else
    //			c = 6;// nella terza
    		//@formatter:on
    		row = (row / 3) * 3;// migliore del codice precedente,
    		col = (col / 3) * 3;// molto più sintetico
    		// controllo del settore
    		for(int i = row; i < row + 3; i++)
    			for(int j = col; j < col + 3; j++)
    				if(tmp[i][j].getVal() == n)
    					return false;
    		return true;
    	}
    
    	public Cella[][][] getSolutions(){
    		return possibiliSoluzioni;
    	}
    
    	public static String toString(Cella[][] m){
    		StringBuilder sb = new StringBuilder(500);
    		for(int i = 0; i < 9; i++){
    			sb.append("|  ");
    			for(int j = 0; j < 9; j++){
    				if(j == m[0].length - 1){
    					sb.append(m[i][j].toString());
    					sb.append("  |");
    					if(i == 2 || i == 5)
    						sb.append("\n------------------+-----------------+------------------\n");
    					else if(i != 8)
    						sb.append("\n|                 |                 |                 |\n");
    				}else{
    					sb.append(m[i][j].toString());
    					sb.append("  |  ");
    				}
    			}
    		}
    		return sb.toString();
    	}
    	public static void main(String[] args){
    		int[][] a = new int[][]{
    				{7, 3, 9, 1, 4, 2, 0, 8, 6},
    				{0, 5, 1, 9, 8, 6, 3, 4, 7},
    				{4, 6, 8, 0, 0, 0, 0, 0, 0},
    				{5, 1, 6, 0, 0, 7, 2, 3, 0},
    				{8, 4, 7, 2, 3, 5, 6, 1, 0},
    				{0, 0, 3, 0, 0, 0, 7, 5, 8},
    				{0, 0, 0, 0, 0, 8, 4, 7, 2},
    				{0, 8, 0, 0, 0, 0, 0, 6, 0},
    				{0, 0, 0, 5, 2, 3, 8, 9, 1}};
    		Cella[][] s = new Cella[9][9];
    		for(int i = 0; i < 9; i++)
    			for(int j = 0; j < 9; j++){
    				s[i][j] = new Cella(a[i][j]);
    				if(a[i][j] != 0)
    					s[i][j].setState(Cella.Stato.IMPOSTATO);
    			}
    //		for(int i = 0; i < 9; i++)
    //			for(int j = 0; j < 9; j++)
    //				s[i][j].setVal(0);
    		SudokuSolver2 solver = new SudokuSolver2(s, 1);
    		solver.risolvi();
    		Cella[][][] soluzioni = solver.getSolutions();
    		for(int i = 0; i < soluzioni.length; i++){			
    			System.out.println("Soluzione trovata " + (i + 1));
    			System.out.println(toString(soluzioni[i]));
    		}
    	}
    }

  2. #2
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347
    EDIT: ho aggiornato un po il metodo risolvi, e le parti della classe a esso relative, comunque è rimasto all'incirca lo stesso, e soprattutto il problema è lo stesso...
    codice:
     
    package sudoku_solver;
    
    import util.Cella;
    
    public class SudokuSolver3{
    
    	private Cella[][] sudoku;
    	private Cella[][][] possibiliSoluzioni;
    	int count = 0;
    
    	public SudokuSolver3(Cella[][] sudoku, int numeroSoluzioni){
    		if(sudoku.length != 9 || sudoku[0].length != 9 || numeroSoluzioni < 1)
    			throw new IllegalArgumentException();
    		this.sudoku = sudoku;
    		this.possibiliSoluzioni = new Cella[numeroSoluzioni][9][9];
    	}
    
    	public void risolvi(){
    		riempi(0, 0);
    	}
    
    	private void riempi(int row, int col){
    		if(sudoku[row][col].getState() == Cella.Stato.IMPOSTATO)
    			avanza(row, col);
    		else{
    			for(int n = 1; n < 10; n++){
    				if(assegnabile(row, col, n)){
    					assegna(row, col, n);
    					if(row == 8 && col == 8)
    						salvaSoluzione();
    					else
    						avanza(row, col);
    				}
    				deassegna(row, col);
    			}
    		}
    	}
    
    	private void salvaSoluzione(){
    		for(int i = 0; i < 9; i++)
    			for(int j = 0; j < 9; j++)
    				possibiliSoluzioni[count][i][j] = new Cella(sudoku[i][j]);
    	}
    
    	private void avanza(int row, int col){
    		if(col < 8)
    			riempi(row, col + 1);// vai avanti sulla stessa riga
    		else
    			riempi(row + 1, 0);// altrimenti vai a capo
    	}
    
    	private void assegna(int row, int col, int n){
    		sudoku[row][col].setVal(n);
    		sudoku[row][col].setState(Cella.Stato.ASSEGNATO);
    	}
    
    	private void deassegna(int row, int col){
    		sudoku[row][col].setVal(0);
    		sudoku[row][col].setState(Cella.Stato.NON_ASSEGNATO);
    	}
    
    	private boolean assegnabile(int row, int col, int n){
    		// controllo sulla riga
    		for(int i = 0; i < 9; i++)
    			if(sudoku[row][i].getVal() == n)
    				return false;
    		// controllo sulla colonna
    		for(int i = 0; i < 9; i++)
    			if(sudoku[i][col].getVal() == n)
    				return false;
    		//@formatter:off
    		//determinamento del settore da controllare
    //		int r, c;
    //		if(row < 3)
    //			r = 0;// si trova nella prima riga
    //		else if(row >= 3 && row < 6)
    //			r = 3;// nella seconda
    //		else
    //			r = 6;// nella terza
    //		if(col < 3)
    //			c = 0;// si trova nella prima colonna
    //		else if(col >= 3 && col < 6)
    //			c = 3;// nella seconda
    //		else
    //			c = 6;// nella terza
    		//@formatter:on
    		row = (row / 3) * 3;// migliore del codice precedente,
    		col = (col / 3) * 3;// molto più sintetico
    		// controllo del settore
    		for(int i = row; i < row + 3; i++)
    			for(int j = col; j < col + 3; j++)
    				if(sudoku[i][j].getVal() == n)
    					return false;
    		return true;
    	}
    
    	public Cella[][][] getSolutions(){
    		return possibiliSoluzioni;
    	}
    
    	public static String toString(Cella[][] m){
    		StringBuilder sb = new StringBuilder(500);
    		for(int i = 0; i < 9; i++){
    			sb.append("|  ");
    			for(int j = 0; j < 9; j++){
    				if(j == m[0].length - 1){
    					sb.append(m[i][j].toString());
    					sb.append("  |");
    					if(i == 2 || i == 5)
    						sb.append("\n------------------+-----------------+------------------\n");
    					else if(i != 8)
    						sb.append("\n|                 |                 |                 |\n");
    				}else{
    					sb.append(m[i][j].toString());
    					sb.append("  |  ");
    				}
    			}
    		}
    		return sb.toString();
    	}
    
    	public static void main(String[] args){
    		int[][] a = new int[][]{{7, 3, 9, 1, 4, 2, 0, 8, 6}, {0, 5, 1, 9, 8, 6, 3, 4, 7}, {4, 6, 8, 0, 0, 0, 0, 0, 0}, {5, 1, 6, 0, 0, 7, 2, 3, 0}, {8, 4, 7, 2, 3, 5, 6, 1, 0}, {0, 0, 3, 0, 0, 0, 7, 5, 8}, {0, 0, 0, 0, 0, 8, 4, 7, 2}, {0, 8, 0, 0, 0, 0, 0, 6, 0}, {0, 0, 0, 5, 2, 3, 8, 9, 0}};
    		Cella[][] s = new Cella[9][9];
    		for(int i = 0; i < 9; i++)
    			for(int j = 0; j < 9; j++){
    				s[i][j] = new Cella(a[i][j]);
    				if(a[i][j] != 0)
    					s[i][j].setState(Cella.Stato.IMPOSTATO);
    			}
    		// for(int i = 0; i < 9; i++)
    		// for(int j = 0; j < 9; j++)
    		// s[i][j].setVal(0);
    		SudokuSolver3 solver = new SudokuSolver3(s, 1);
    		solver.risolvi();
    		Cella[][][] soluzioni = solver.getSolutions();
    		for(int i = 0; i < soluzioni.length; i++){
    			System.out.println("Soluzione trovata " + (i + 1));
    			System.out.println(toString(soluzioni[i]));
    		}
    	}
    }

  3. #3
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347
    up

  4. #4
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    invece di fare UP con una NullPointerException (che significa debuggate voi per capire dove è l'errore), inizia a vedere dove si presenta e ricostruisci il ciclo di esecuzione, dall'avvio del programma a dove si presenta. NPE significa che non hai istanziato qualcosa, ergo controlla che tutto sia valorizzato (e i punti in cui lo fai) quando arrivi al toString()

    Mi parli del metodo toString() che è questo

    Codice PHP:
    public static String toString(Cella[][] m){
            
    StringBuilder sb = new StringBuilder(500);
            for(
    int i 09i++){
                
    sb.append("|  ");
                for(
    int j 09j++){
                    if(
    == m[0].length 1){
                        
    sb.append(m[i][j].toString());
                        
    sb.append("  |");
                        if(
    == || == 5)
                            
    sb.append("\n------------------+-----------------+------------------\n");
                        else if(
    != 8)
                            
    sb.append("\n|                 |                 |                 |\n");
                    }else{
                        
    sb.append(m[i][j].toString());
                        
    sb.append("  |  ");
                    }
                }
            }
            return 
    sb.toString();
        } 
    e non dici il punto in cui si trova l'eccezione.

    Ho la vaga impressione (non ho letto il tuo codice, per capire cosa succede dovrei debuggarlo) che quando hai delle caselle, dimentichi di assegnare il valore a queste.
    Controlla questo.
    RTFM Read That F*** Manual!!!

  5. #5
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347
    perchè dovete partire prevenuti? No, il mio up non significa quello che hai detto, ma significa: siccome ci sono stato almeno un paio di ore a capire da dove parte il problema, mi potete da una mano per favore? Comunque, chiudendo questa parentesi, l'eccezione viene generata a partire dall'istruzione sb.append(m[i][j]) ho provato a debuggare(non ho eseguito istruzione per istruzione dall'inizio perche essendo un algoritmo ricorsivo, dura parecchio) però pur impostando dei breakpoint un varie parti del programma non sono riuscito a capire da dove si genera.
    Come ho detto viene generata dall'istruzione sb.append(m[i][j]) del toString, infatti controllando in debug nella matrice tutti i valori sono null( e questo succede solo se gli passo un sudoku mezzo completo, se gliene passo uno con tutti valori a 0, lui lo completa normalmente)
    Mi sembra impossibile un'eccezione del genere perche io nel main istanzio gia la matrice di Celle con alcuni valori dentro e poi gliela passo.

  6. #6
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    se ci arriva vuole dire che la situazione è quella, c'è poco da fare.
    Visto che l'algoritmo è ricorsivo, logga su file.
    Scrivi ad ogni giro tutte le info per ricostruire il percorso, per facilitarti magari fallo su file il cui nome è relativo al giro in cui sei (almeno riduci il campo di azione).

    Se per te è problematico capire COSA succede (e hai scritto il codice), pensa per me.
    Ripeto, a naso, quando il vettore è mezzo vuoto hai delle mancate inizializzazioni (anche se l'input è concreto)

    sono solo 2 le vie: debug da quando inizi, passo dopo passo senza saltare niente (anche se lungo) oppure intanto scrivi su file, in modo da circoscrivere l'errore (se riesci a loggare le info giuste)

    ps metti la classe Cella
    RTFM Read That F*** Manual!!!

  7. #7
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347
    allora intanto ecco la classe cella, che poi non fa niente di speciale, rappresenta una cella con un valore e uno stato
    Codice PHP:
    package util;

    public class 
    Cella{

        public 
    enum Stato{
            
    IMPOSTATOASSEGNATONON_ASSEGNATO
        
    }

        private 
    int val;
        private 
    Stato state;

        public 
    Cella(){
            
    this(0Stato.NON_ASSEGNATO);
        }
    // costruttore default

        
    public Cella(int val){
            
    this(valnull);
        }
    // costruttore di base

        
    public Cella(int valStato state){
            if(
    val || val 9)
                throw new 
    IllegalArgumentException();
            
    this.val val;
            
    this.state state;
        }
    // costruttore normale

        
    public Cella(Cella c){
            
    this.val c.getVal();
            
    this.state c.getState();
        }
    // costruttore copia

        
    public int getVal(){
            return 
    val;
        }

        public 
    void setVal(int val){
            if(
    val || val 9)
                throw new 
    IllegalArgumentException();
            
    this.val val;
        }

        public 
    Stato getState(){
            return 
    state;
        }

        public 
    void setState(Stato state){
            
    this.state state;
        }

        public 
    String toString(){
            return 
    String.valueOf(val);
        }

    ma sul file che gere di informazioni devo scrivere?
    p.s.: comunque nell'algoritmo non c'è nessun assegnamento a null o qualcosa del genere, per questo non so proprio cosa andare a cercare...

  8. #8
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    presto detto, tu non chiami mai salvaSoluzioni

    codice:
    	private void riempi(int row, int col) {
    		if (sudoku[row][col].getState() == Stato.IMPOSTATO)
    			avanza(row, col);
    		else {
    			for (int n = 1; n < 10; n++) {
    				if (assegnabile(row, col, n)) {
    					assegna(row, col, n);
    					salvaSoluzione();
    					avanza(row, col);						
    				}
    				deassegna(row, col);
    			}
    		}
    	}
    si possono fare una marea di ottimizzazioni, ma così la stampa è andata, anche se la soluzione non è corretta.

    ps il vero sudoku ha sempre una e una sola soluzione

    pps ho messo Stato in una enum a parte (file a parte), più comodo per me
    RTFM Read That F*** Manual!!!

  9. #9
    Utente di HTML.it
    Registrato dal
    Oct 2011
    Messaggi
    347
    non capisco che vuoi dire... perchè non chiamo mai salvaSoluzione?
    io la soluzione corrente la salvo solo se ho assegnato l'ultimo valore, e cioè:
    if(row == 8 && col == 8)
    salvaSoluzione();

    ps: il fatto che calcoli più di una soluzione è per richiesta del progetto che mi hanno assegnato, e cioè se l'utente non inserisce niente nel sudoku potra vedere più di una soluzione

  10. #10
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    in realtà in quella funzione non ci arrivi mai, quindi ti trovi lo schema con le opzioni di default, che per un oggetto è null

    Poi non so se sei obbligato ad usare la ricorsione, quell'algoritmo non è ricorsivo (si ferma quasi subito), quindi così come è impostato non va.

    Bisogna fissare la ricorsione bene, difficile fissarla su 2 condizioni
    RTFM Read That F*** Manual!!!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.