View Full Version : [Java] Problema grave!
Izmailov
22-09-2008, 18:31
Ho appena iniziato a studiare Java ed ho cercato di realizzare un piccolo programmino che crei un mazzo di carte mescolato in maniera diversa ogni volta! Però mi segnala sempre un errore in fase di esecuzione!
Vi posto il codice sperando possiate aiutarmi!
La classe Partita semplicemente crea l'oggetto uno della classe Mazzo
public class Partita
{
public static void main(String args[])
{
Mazzo uno = new Mazzo();
}
}
La classe Carta definisce come è fatta una carta da gioco come ad esempio "Cavallo di Bastoni"public class Carta
{
private int numero;
private String seme;
public Carta(int numero, String seme)
{
this.setCarta(numero, seme);
}
public void setCarta(int numero, String seme)
{
this.setNumero(numero);
this.setSeme(seme);
}
public void setNumero(int numero)
{
this.numero = numero;
}
public void setSeme(String seme)
{
this.seme=seme;
}
public int getNumero()
{
return this.numero;
}
public String getSeme()
{
return this.seme;
}
}
La classe Mazzo invece crea una array di oggetti della classe Carta e in modo casuale crea le carte dell'array! Fino a qui a tutto funziona...fino a quando non cerco di fare in modo che le carte siano l'una diversa dall'altra facendo un controllo tra l'ultima carta creata e il resto dell'array.
public class Mazzo
{
public Mazzo()
{
Carta[] carta = new Carta[40];
for(int i=0; i<40; i=i+1)
{
int valoreSeme = (int)(Math.random()*4+1);
int numero = (int)(Math.random()*10+1);
String seme = new String();
switch(valoreSeme)
{
case 1:
seme = "Spade";
break;
case 2:
seme = "Denari";
break;
case 3:
seme = "Coppe";
break;
case 4:
seme = "Bastoni";
break;
}
//La prima carta va sicuramente bene
if(i==0)
carta[i] = new Carta(numero, seme);
//Dalla seconda carta in poi ho fatto in modo che cerchi di confrontare l'ultima carta generata in modo casuale con il resto dell'array. Se questa risulta diversa dalla prima, la variabile j aumenta altrimenti il ciclo for finisce. Se alla fine dell'ultimo confronto, la variabile j è uguale al numero delle carte dell'array allora vuol dire che la carta da confrontare è stata confrontata con tutte quelle dell'array ed è risultata sempre diversa, quindi viene aggiunta nell'array. A questo punto però mi dà l'errore. Dopo aver inserito una o due carte mi genera un errore!
else if(i>0)
{
for(int j=1, k=0; k<i; k=k+1)
{
if((numero!=carta[k].getNumero())&&(seme!=carta[k].getSeme()))
{
j=j+1;
if(j==i)
{
carta[i] = new Carta(numero, seme);
}
}
}
}
System.out.println(carta[i].getNumero() + " di " + carta[i].getSeme());
}
}
}
Ed ecco infine l'errore!1 di Denari
Exception in thread "main" java.lang.NullPointerException
at Mazzo.<init>(Mazzo.java:34)
at Partita.main(Partita.java:5)
Process Terminated... there were problems.
banryu79
22-09-2008, 18:54
for(int i=0; i<40; i=i+1)
{
int valoreSeme = (int)(Math.random()*4+1);
int numero = (int)(Math.random()*10+1);
String seme = new String();
switch(valoreSeme)
{
//...
}
//La prima carta va sicuramente bene
if(i==0)
carta[i] = new Carta(numero, seme);
else if(i>0)
{
for(int j=1, k=0; k<i; k=k+1)
{
if((numero!=carta[k].getNumero())&&(seme!=carta[k].getSeme()))
{
j=j+1;
if(j==i)
{
carta[i] = new Carta(numero, seme);
}
}
}
}
System.out.println(carta[i].getNumero() + " di " + carta[i].getSeme());
}
Hai un NullPointerException per forza: il ciclo for principale che deve generare le 40 carte vede il suo percorso di esecuzione diviso in due flussi da un if-else.
Nel primo if (if (i==0), l'iterazione della prima carta) la carta viene sicuramente creata (si arriva ad un new "Carta(numero, seme)"), se invece l'if non viene verificato (dalla seconda iterazione in poi) nel corpo dell'else non è detto ceh si arrivi ad allocare una carta [vedi blocchi evidenziati in grassetto]
dato che il System.out.printl() lo fai dentro il ciclo for subito dopo l'if-else, dalla seconda iterazione in poi la carta potrebbe non essere stata creata (nessuna chiamata a new Carta(...), quindi ti ritrovi una reference che punta a null).
Inoltre mi sembra che la condizione di verifica sia semanticamente errata:
if ( (numero!=carta[k].getNumero()) && (seme!=carta[k].getSeme()) )
Controlli che la nouva "carta random" sia diversia sia per numero che per seme, invece basta che sia diversa per numero oppure per seme.
Izmailov
22-09-2008, 19:02
Sei un genio! E poi anche io sono impedito!
Grazie mille! :D
banryu79
22-09-2008, 19:07
Solo un consiglio: per questioni di chiarezza nella lettura del codice è bene esplicitare sempre le parentesi graffe nei costrutti if, if-else, e ancora più negli if-else if a catena.
E anche nei for/while che hanno una sola riga di istruzioni.
Izmailov
22-09-2008, 19:10
Solo un consiglio: per questioni di chiarezza nella lettura del codice è bene esplicitare sempre le parentesi graffe nei costrutti if, if-else, e ancora più negli if-else if a catena.
E anche nei for/while che hanno una sola riga di istruzioni.
D'accordo! Sei davvero gentile! :D
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html#shuffle(java.util.List)
banryu79
23-09-2008, 09:35
Un altro modo in effetti sarebbe quello di generare il mazzo di carte con due cicli for: il primo cicla per seme, il secondo, annidato nel primo, per valore della carta.
Per memorizzare le carte potresti usare un ArrayList invece di un semplice array, in questo modo puoi usare il comodo metodo shuffle() della classe Collections [java.util.Collections.shuffle(aList)] che prende come parametro una List e ne mescola gli elementi.
Ad esempio:
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
// ...
ArrayList listCarte = new ArrayList(); // il mazzo, ancora vuoto
// genera il mazzo ordinato per seme e valore
for (int seme = 1; i <= 4; seme++)
{
for (int valore = 1; valore <= 10; valore++)
{
listCarte.add(new Carta(valore, seme));
}
}
// mescola il mazzo
Collections.shuffle(listCarte);
//...
Voto per l'ultima impostazione di Baynru, anche se la condirei ulteriormente con una classe "Mazzo" che circondi e nasconda la lista.
E che abbia almeno il metodo Shuffle.
In piu', proprio per la natura di questi problemi, al posto di un normale Lista metterei (se c'e' in Java) una Coda o Stack, in modo tale da esporre la Dequeue, per scodare, quando serve, una carta per volta.
Proprio come quando si pesca o si distribuiscono le carte...
banryu79
23-09-2008, 10:20
In piu', proprio per la natura di questi problemi, al posto di un normale Lista metterei (se c'e' in Java) una Coda o Stack, in modo tale da esporre la Dequeue, per scodare, quando serve, una carta per volta.
Proprio come quando si pesca o si distribuiscono le carte...
Nel Collection Framework di Java c'è una interface: Queue, implementata (tra le varie possibilità) dalla classe LinkedList.
Alcune informazioni in merito.
The Queue Interface
A Queue is a collection for holding elements prior to processing. Besides
basic Collection operations, queues provide additional insertion, removal,
and inspection operations. The Queue interface follows.
public interface Queue<E> extends Collection<E> {
E element();
boolean offer(E e);
E peek();
E poll();
E remove();
}
Each Queue method exists in two forms: (1) one throws an exception
if the operation fails, and (2) the other returns a special value if the
operation fails (either null or false, depending on the operation).
The regular structure of the interface is illustrated in the following table.
Queue Interface Structure Throws exception Returns special value
Insert add(e) offer(e)
Remove remove() poll()
Examine element() peek()
Queues typically, but not necessarily, order elements in a FIFO
(first-in-first-out) manner. Among the exceptions are priority queues,
which order elements according to their values — see the Object
Ordering section for details). Whatever ordering is used, the head
of the queue is the element that would be removed by a call to remove
or poll. In a FIFO queue, all new elements are inserted at the tail of
the queue. Other kinds of queues may use different placement rules.
Every Queue implementation must specify its ordering properties.
Link (https://java.sun.com/docs/books/tutorial/collections/interfaces/queue.html)
Queue Implementations
The Queue implementations are grouped into general-purpose and concurrent implementations.
General-Purpose Queue Implementations
As mentioned in the previous section, LinkedList implements the Queue interface, providing FIFO queue operations for add, poll, and so on.
The PriorityQueue class is a priority queue based on the heap data structure. This queue orders elements according to an order specified at construction time, which can be the elements' natural ordering or the ordering imposed by an explicit Comparator.
The queue retrieval operations — poll, remove, peek, and element — access the element at the head of the queue. The head of the queue is the least element with respect to the specified ordering. If multiple elements are tied for least value, the head is one of those elements; ties are broken arbitrarily.
PriorityQueue and its iterator implement all of the optional methods of the Collection and Iterator interfaces. The iterator provided in method iterator is not guaranteed to traverse the elements of the PriorityQueue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).
Link (https://java.sun.com/docs/books/tutorial/collections/implementations/queue.html)
banryu79
23-09-2008, 10:47
Già che ci siamo, posto anche questo (circa ArrayList e LinkedList):
List Implementations
List implementations are grouped into general-purpose and special-purpose implementations.
General-Purpose List Implementations
There are two general-purpose List implementations — ArrayList and LinkedList. Most of the time, you'll probably use ArrayList, which offers constant-time positional access and is just plain fast. It does not have to allocate a node object for each element in the List, and it can take advantage of System.arraycopy when it has to move multiple elements at the same time. Think of ArrayList as Vector without the synchronization overhead.
If you frequently add elements to the beginning of the List or iterate over the List to delete elements from its interior, you should consider using LinkedList. These operations require constant-time in a LinkedList and linear-time in an ArrayList. But you pay a big price in performance. Positional access requires linear-time in a LinkedList and constant-time in an ArrayList. Furthermore, the constant factor for LinkedList is much worse. If you think you want to use a LinkedList, measure the performance of your application with both LinkedList and ArrayList before making your choice; ArrayList is usually faster.
ArrayList has one tuning parameter — the initial capacity, which refers to the number of elements the ArrayList can hold before it has to grow. LinkedList has no tuning parameters and seven optional operations, one of which is clone. The other six are addFirst, getFirst, removeFirst, addLast, getLast, and removeLast. LinkedList also implements the Queue interface.
Link (https://java.sun.com/docs/books/tutorial/collections/implementations/list.html)
Visto che rimuovere una carta da sopra il mazzo (ed evenetualmente reinserirla nel fondo del mazzo) non richiede un accesso posizionale si potrebbe usare LinkedList al posto del più comune ArrayList, però la collezione di carte è piccola (appena 40 elementi) e la parte in grassetto circa i fattori costanti svantaggiosi potrebbe avere il suo peso, in un caso come questo (non resterebbe che provare con entrambe).
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.