Hola.
Puedes poner el main() en la clase Deck, sin embargo, no es lo ideal.
Cuando escribimos clases que modelan entidades del "mundo real": un carta, un mazo de cartas, un coche, una lavadora... suele ser preferible hacer que NO sean autoejecutables, es decir, que no tengan método main()
Imagina ahora que te piden hacer un programa donde tienes que usar 4 objetos Deck (4 mazos de cartas) para intercambiar cartas entre ellos, o simular una partida Poker o lo que sea..
Entonces te encontrarías con que cada uno de esos 4 objetos Deck tienen su propio método main().
Y en realidad no molestarían, porque en este supuesto estarías ejecutando el main() que simula la partida de Poker.
Pero en esos objetos Deck, tendrías código innecesario, métodos main() que no aportan nada.
Pero hay un problema mayor: muchas de las funciones que has puesto pick, suffle, head, hand.... son métodos estáticos pensados para ser ejecutados desde ese main()
En el supuesto programa que simularía la partida de Poker, los 4 Deck (mazos) que intervienen en la partida, no tendrían disponibles esas funciones de pick, hand, etc.... ¡¡a pesar de estar escritas en su clase Deck!!
Por eso yo hice una clase Card, una clase Deck y para ejecutar el programa, una clase a parte con el main().
Luego, otras cosas a mencionar sobre tu código.
Comienzas el programa creando una carta:
public class Deck {
public static void main(String[] args)
{
Card card = new Card();
No se por qué lo haces, quizás piensas que es necesario para luego poder usar la clase Card... no se.
Pero no, no es necesario para nada. Ahí lo que estás haciendo es crear
una carta.
Una carta sin atributos definidos (ni palo, ni valor, ni color), que estaría fuera del mazo, y que no interviene para nada en el resto del programa.
Así que esa línea la puedes borrar, porque no aporta absolutamente nada.
Más cosas, tras crear las cartas, intentas mostrarlas en pantalla.
for (Card elemento : deck) {
System.out.print(elemento + " / ");
}
Pero lo que haces es pasarle al System.out.print() directamente un objeto
Card.
El System.out ni tiene ni pajolera idea de qué es un
Card, no sabe como debe mostrar "eso" en pantalla, así que lo único que acierta a hacer, es mostrar en pantalla el identificador interno de esos objetos
Card:
cardPoker2.Card@2f92e0f4 / cardPoker2.Card@28a418fc / cardPoker2.Card@5305068a / cardPoker2.Card@1f32e575
Y claro, no es eso lo que queremos.
El System.out básicamente solo sabe manejarse con objetos String, porque son cadenas de texto y eso es fácil de mostrar en pantalla.
Entonces, si queremos mostrar los datos de una Card en pantalla, tenemos
dos opciones:
- Recurrir a los métodos getter
for (Card elemento : deck) {
System.out.println("Palo: " + elemento.getPalo());
System.out.println("Color: " + elemento.getColor());
System.out.println("Valor: " + elemento.getValor());
System.out.println("\n***************");
}
Y ahora en pantalla sí tenemos la información deseada:
Deck de Cartas para Iniciar:
Palo: corazones
Color: rojo
Valor: 2
***************
Palo: corazones
Color: rojo
Valor: 3
***************
Palo: corazones
Color: rojo
Valor: 4
***************
Palo: corazones
Color: rojo
Valor: 5
***************
Hay una segunda opción, que es más adecuada. Y es "enseñarle" a la clase Card cómo construir un String con sus datos, para que System.out y métodos similares, puedan utilizar ese String.
Para ello, añadimos este método a la clase Card:
@Override
public String toString() {
return "Palo: " + palo + "\nColor: " + color +
"\nValor: " + valor;
}
En realidad, lo que hacemos es "sobreescribir" el método toString() que TODAS las clase Java heredan automáticamente de la clase Object (Object es una superclase, nivel Dios..., de las que todas las clases Java son hijas)
Por eso añadimos la etiqueta
@Override, para indicar al compilador que no estamos creado un nuevo método, si no que estamos sobreescribiendo uno que ya existe por herencia de una superclase.
No importa si ahora mismo no entiendes bien esto de la herencia entre clases, la cuestión es que ahora la clase Card ya sabe como ha de construir un String que la represente.
Y el método System.out cuando recibe un objeto que NO es un String, lo que hace es consultar si dicho objeto dispone de un método toString().
Y como ahora Card ya lo tiene, ya si podemos mostrar cartas en pantalla sin tener que recurrir a los getters:
for (Card elemento : deck) {
System.out.println(elemento); //Aquí interviene el método toString()
System.out.println("\n***************");
}
Bien, más cosas.
En los métodos pick, hand, etc... pones que van a recibir un ArrayList pero sin especificar que clase van a contener esos ArrayList:
public static void head(ArrayList deck){
System.out.println(deck.get(0));
deck.remove(0);
System.out.println("Quedan " + deck.size() + " cartas");
}
Esto, hoy día Java lo permite (en versiones más antiguas no lo permitía) pero no está bien visto.
Lo correcto es indicar la clase que va a contener esta colección. Además a la hora de leer el código otro programador que no seas tú, le será más informativo poder ver indicado que se trata de ArrayList que contienen Card.
Es más, esto nos puede ahorrar, posibles errores posteriores, como veremos después.
Así que a TODOS los métodos, hay que especificar la clase del ArrayList:
public static void head(ArrayList<Card> deck){
System.out.println(deck.get(0));
deck.remove(0);
System.out.println("Quedan " + deck.size() + " cartas");
}
Y esto enlaza con el principal problema, al error que lanza tu programa.
En el método suflle, haces un Iterable de tipo String, para recorrer el ArrayList:
public static void suflle(ArrayList deck){
Collections.shuffle(deck);
System.out.println("Se mezcló el Deck.");
for (String elemento : (Iterable<String>) deck) {
System.out.print(elemento + " / ");
}
}
Pero claro, el ArrayList no contiene objetos String, lo que contiene son Card.
Entonces al ejecutar el programa, Java se encuentra con que le pides que trate a un Card, como si fuera un String. Y entonces te avisa de que no sabe como hacer eso, mediante este error:
Exception in thread "main" java.lang.ClassCastException: class cardPoker2.Card cannot be cast to class java.lang.String
Este es un error de "ejecución", es decir, que ocurre mientras se ejecuta el programa.
Si hubieras especificado en el método suflle que el ArrayList es de Card, entonces habrías tenido un error de "compilación", que siempre es preferible a uno de "ejecución".
Es decir, como no especificabas qué clase contiene el ArrayList, el compilador dio por bueno que luego hicieras un Iterable de String.
Pero claro, eso no es correcto y se produce un error de "ejecución".
Si hubieras especificado la clase del ArrayList:
public static void suflle(ArrayList<Card> deck){
Collections.shuffle(deck);
System.out.println("Se mezcló el Deck.");
for (String elemento : (Iterable<String>) deck) {
System.out.print(elemento + " / ");
}
}
entonces el compilador JAMÁS te habría permitido hacer un Iterable de String, y te habrías dado cuenta del problema antes de poder ejecutar el programa.
Si quieres usar un Iterable, ha de ser de clase Card, como el ArrayList.
Y como además ahora Card tiene un método toString(), ya si se mostrará en pantalla correctamente:
public static void suflle(ArrayList<Card> deck){
Collections.shuffle(deck);
System.out.println("Se mezcló el Deck.");
for (Card elemento : (Iterable<Card>) deck) {
System.out.print(elemento + " / "); //Método toString() hace que se vea en pantalla
}
}
Sin embargo, no se necesita ningún Iterable (para los ArrayList nunca son necesarios), ya hemos visto al principio que basta con un for.
public static void suflle(ArrayList<Card> deck){
Collections.shuffle(deck);
System.out.println("Se mezcló el Deck.");
for (Card elemento : deck) {
System.out.print(elemento + " / ");
}
}
Y bueno, eso es todo.
Solo recalcar que lo ideal sería que la clase Deck, no tuviera main().
Ha de ser un programa que modele un mazo, pero no un programa que se ejecute.
Un saludo.