View Full Version : [Java] Gioco memory
Ciao a tutti, vorrei farvi un paio di domande riguardo a unìapplicazione che sto cercando di sviluppare: il gioco del memory (quello con le carte girate a faccia in giù dove bisogna indovinare le coppie uguali).
Allora, per il mio giochetto ho creato un JPanel con layout GridLayout 6x6, una classe Carta che estende JButton e che ha come varaible un numero intero da 1 a 18(essendo le carte 36), e con un ciclo aggiungo tutte le 36 carte al gridlayout. L'intenzione è quella di aggiungere un actionlistener a ogni jbutton, e poi controllare se il numero della carta fonte dell'evento del primo listener è uguale a quello della seconda. In questo caso vuol dire che ho fatto una coppia.
Il problema è che non so dove effettuare questo confronto, o come ridefinire il metodo actionPerformed per fare in modo che mi restituisca il valore intero della carta fonte dell'evento...
Un aiuto sarebbe molto gradito, non so che pesci prendere...grazie in anticipo a chi si degnerà di rispondermi :(
banryu79
12-07-2010, 08:24
Potresti pensare a una classe GameLogic, a cui redirigere alcune informazioni che prederai nel corpo del metodo actionPerformed del tuo Listener (sarebbe meglio creare un solo ActionListener da associare a tutte le Carte-bottone).
Quando viene fatto click su una carta, il Listener la passa a GameLogic (nel metodo actionPerformed ottieni il riferimento all'istanza della Carta-bottone cliccata invocando il metodo 'getSource' sull'argomento ActionEvent, e promuovendolo (cast) al tipo di riferimento Carta-bottone).
GameLogic controlla se ha già letto o no la prima carta.
Se non l'ha già letta memorizza il riferimento passato dal Listener come prima Carta e stop.
Altrimenti confronta il valore della prima Carta memorizzata con quello della Carta attuale passata dal Listener:
- se sono uguali elimina le due carte;
- se non sono uguali le "rigira".
- in ogni caso, resetta il riferimento alla prima carta.
Può andare bene come idea di massima?
Ciao, ti ringrazio della risposta, e ti confesso che ho preso un bello spunto dal sorgente di un altro utente di questo forum, in un thread di un paio di anni fa (che implementa un listener che fa proprio come dici tu).
Con qualche ritocco adesso va tutto a meraviglia, apparte il fatto che non mi mostra l'icona della seconda carta quando la giro a faccia in su, a meno che non faccia coppia....se faccio coppia seconda.uncover() mi mostra l'immagine jpg della seconda carta scoperta, altrimenti il metodo uncover() viene comunque chiamato, ma non mostra l'icona....:muro:
Allego le classi Carta e MemoryListener, così magari ci puoi dare un'occhiata...
import javax.swing.*;
import java.awt.*;
class Carta extends JButton
{
private int num;
Carta(int n)
{
super(new ImageIcon("retro.jpg"));
num = n;
}
void uncover()
{
setIcon(new ImageIcon(num+".jpg"));
System.out.println("Uncover"); // messo per vedere se eseguiva il metodo sulla seconda carta
}
void cover()
{
setIcon(new ImageIcon("retro.jpg"));
}
int getNum()
{
return num;
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
class MemoryListener implements ActionListener
{
private int giocatoreAttivo = 0;
private Carta prima = null;
private Carta seconda = null;
private int coppie = 0;
public MemoryListener()
{
super();
}
public void actionPerformed(ActionEvent e)
{
switch (giocatoreAttivo)
{
case 0:
{
Carta mem2 = (Carta) e.getSource();
if (prima == null) //1
{
prima = mem2;
mem2.uncover();
System.out.println("prima= "+prima.getNum());
}
else //1
if (seconda == null) //2
{
seconda = mem2;
seconda.uncover();
//MyMemory.aspetta();
System.out.println("seconda= "+seconda.getNum());
if (prima.getNum()==(seconda.getNum())) //3
{
prima.setBackground(Color.GREEN);
seconda.setBackground(Color.GREEN);
prima = null;
seconda = null;
coppie++;
//mem2.removeActionListener(this);
if (coppie == 18) //4
{
JOptionPane.showMessageDialog(null,"Hai trovato tutte le coppie.\nVittoria!", "Gioco terminato",JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
else //3
{
//seconda.uncover();
MyMemory.aspetta();
prima.cover();
seconda.cover();
prima=null;
seconda=null;
giocatoreAttivo = 1;
System.out.println("Non hai indovinato, clicca per far giocare la CPU");
break;
}
}
else //2
{
}
break;
}
case 1:
{
System.out.println("Turno CPU");
giocatoreAttivo=0;
break;
}
}
}
}
Grazie a chiunque sarà così gentile da illuminarmi :)
Riuppo, anche per dire che il metodo uncover() non funziona neanche quando lo chiamo sulle carte che gira il giocatore cpu....
Questo è il metodo in questione, appartenente alla classe Carta che estende JButton, che trovate per intero nel post precedente...
void uncover()
{
setIcon(new ImageIcon(num+".jpg"));
}
Questa invece è la classe MyMemory, che contiene il main e costruisce l'interfaccia.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import java.util.*;
import java.util.ArrayList;
public class MyMemory extends JFrame implements ActionListener
{
public Container panel;
MemoryListener mem1 = new MemoryListener();
public static ArrayList<Carta> arraylist = new ArrayList<Carta>();
public MyMemory()
{
this.panel = this.getContentPane();
panel.setLayout(new BorderLayout());
setTitle("Memory");
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
JMenu submenu = new JMenu("Gioca una partita");
JMenuItem facile = new JMenuItem("Livello facile");
submenu.add(facile);
facile.addActionListener(this);
JMenuItem difficile = new JMenuItem("Livello difficile");
submenu.add(difficile);
difficile.addActionListener(this);
menu.add(submenu);
JMenuItem esci = new JMenuItem("Esci");
menu.add(esci);
esci.addActionListener(this);
panel.add(menuBar, BorderLayout.NORTH);
setSize(870, 950);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private int[] labels = { 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2,
3, 4, 5, 6, 7, 8, 9,10,11,12, 13, 14,
15, 16, 17, 18 };
private int lung = labels.length;
private int randomLabel()
{
int random = (int) (Math.random()*100);
int ran = (int) random % lung;
int ran1 = labels[ran];
for (int i = ran + 1; i < lung; i++)
{
labels[i - 1] = labels[i];
}
lung--;
return ran1;
}
public void costruisci()
{
JPanel cartePanel = new JPanel();
cartePanel.setLayout(new GridLayout(6,6,3,3));
for (int i = 0; i < 36; i++)
{
Carta c = new Carta(this.randomLabel());
cartePanel.add(c);
arraylist.add(i,c);
c.addActionListener(mem1);
panel.add(cartePanel, BorderLayout.CENTER);
setVisible(true);
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("Livello facile"))
{
costruisci();
System.out.println("FAcileeeeeeeeeee");
}
else if (e.getActionCommand().equals("Livello difficile"))
{
costruisci();
System.out.println("Difficileeeeeeeeeee");
}
else System.exit(0);
}
public static void aspetta()
{
long t0,t1;
t0=System.currentTimeMillis();
do{
t1=System.currentTimeMillis();
}
while (t1-t0<1000);
}
public static void main(String[] args) throws Exception
{
MyMemory m = new MyMemory();
}
}
Possibile che questo metodo funzioni solo con la prima carta che giro? Viene invocato, ma non setta l'icona, semplicemente non fa nulla....prima ci avevo aggiunto un comando System.out.println per vedere se veniva chiamato, ed effettivamente stampava la strainga ogni volta che doveva farlo. Però di mostrare l'immagine non ne vuole sapere. Qualcuno ha un'idea?
Sto affogando in un bicchier d'acqua? :help:
banryu79
13-07-2010, 17:19
Ciao, ho realizzato un piccolo esempio sulla base dei suggerimenti che ti ho dato poco sopra (ignora il fatto che la finestra e' trasparente, stavo provando io una cosa):
http://www.freeimagehosting.net/uploads/b99df9a2ad.png (http://www.freeimagehosting.net/)
Ti posto le classi relative (circa il tuo problema prova a guardare come sono gestite le cose nell'implementazione dell'ActionListener che è collegato a ciascuna carta-bottone. C'è una questione relativa all'uso dei thread e al fatto che Swing è single-threaded).
Game.java
package banryu79.mymemory;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
*
* @author francesco
*/
public class Game
{
public static void main(String[] argv) {
// Load images for all cards
CardStore store = new CardStore();
store.load();
// build interface
final JFrame FRAME = new JFrame("MyMemory");
FRAME.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// buld moves counter:
GuessCounter guessCounter = new GuessCounter();
FRAME.add(guessCounter, BorderLayout.NORTH);
// build CardListener
CardListener cardLogic = new CardListener(FRAME);
cardLogic.bindToGuessCounter(guessCounter);
// build game field:
JPanel gameField = new JPanel(new GridLayout(0, 4));
List<CardButton> deck = store.getNewDeck();
for (CardButton card : deck) {
card.addActionListener(cardLogic);
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(card);
b.add(Box.createHorizontalGlue());
gameField.add(b);
}
FRAME.add(gameField, BorderLayout.CENTER);
// show UI!
SwingUtilities.invokeLater(new Runnable() {
public void run() {
FRAME.pack();
FRAME.setLocationRelativeTo(null);
FRAME.setVisible(true);
}
});
for (CardButton card : deck)
System.out.println(card);
}
static class CardListener implements ActionListener
{
JFrame parent;
GuessCounter counter;
CardButton firstCard;
boolean freeForEvents;
final int PAUSE;
CardListener(JFrame parent) {
this.parent = parent;
freeForEvents = true;
PAUSE = 1200;
}
public void actionPerformed(ActionEvent e) {
if (freeForEvents) {
freeForEvents = false;
CardButton card = (CardButton) e.getSource();
if (isChosingFirstCard()) {
firstCardChosen(card);
}
else {
if (isChosingSecondCard(card))
secondCardChosen(card);
else
rechosingFirstCard();
}
}
}
boolean isChosingFirstCard() {
return firstCard == null;
}
boolean isChosingSecondCard(CardButton card) {
return !card.isShowingFrontCover();
}
// Giro la carta e stop.
void firstCardChosen(CardButton card) {
System.out.println("First card chosen: "+ card);
card.swapIcons();
firstCard = card;
freeForEvents = true;
}
// Non faccio nulla, a parte resettare il flag degli eventi
void rechosingFirstCard() {
System.out.println("First rechosed.");
freeForEvents = true;
}
void secondCardChosen(CardButton card) {
counter.incrementGuessAttempt();
if (card.equals(firstCard))
succesfullMatch(card);
else
failedMatch(card);
}
// Giro la carta, mostro JOptionPane, disabilito le due carte e stop.
void succesfullMatch(CardButton card) {
System.out.println("Second card chosen: they match!");
counter.incrementMatch();
card.swapIcons();
JOptionPane.showMessageDialog(parent, "Hai indovinato!");
firstCard.resetIcon();
firstCard.setEnabled(false);
card.resetIcon();
card.setEnabled(false);
parent.repaint();
firstCard = null;
freeForEvents = true;
}
// se non matcha, giro la carta, aspetto un po', e rigiro entrambe le carte.
void failedMatch(final CardButton card) {
System.out.println("Second card chosen: mismatch.");
counter.incrementError();
card.swapIcons();
// launch UI updating task in worker thread, after the pause.
SwingWorker<Void, Void> failedMatchUpdater = new SwingWorker<Void, Void>() {
@Override protected Void doInBackground() throws Exception {
try {
Thread.sleep(PAUSE);
} catch (InterruptedException ignored) {}
return null;
}
@Override protected void done() {
firstCard.swapIcons();
card.swapIcons();
firstCard = null;
freeForEvents = true;
}
};
failedMatchUpdater.execute();
}
private void bindToGuessCounter(GuessCounter guessCounter) {
counter = guessCounter;
}
}
static class GuessCounter extends JPanel
{
final Box BOX;
final JLabel LB_TENTATIVI;
final JLabel LB_ERRORI;
final JLabel LB_MATCH;
int numTentativi = 0;
int numErrori = 0;
int numMatch = 0;
GuessCounter() {
setLayout(new FlowLayout(FlowLayout.LEFT));
LB_TENTATIVI = new JLabel("0");
LB_ERRORI = new JLabel("0");
LB_MATCH = new JLabel("0");
BOX = Box.createHorizontalBox();
BOX.add(Box.createHorizontalStrut(15));
BOX.add(new JLabel("Tentativi eseguiti: "));
BOX.add(LB_TENTATIVI);
BOX.add(Box.createHorizontalStrut(50));
BOX.add(new JLabel("Match: "));
BOX.add(LB_MATCH);
BOX.add(Box.createHorizontalStrut(15));
BOX.add(new JLabel("Errori: "));
BOX.add(LB_ERRORI);
BOX.add(Box.createHorizontalGlue());
add(BOX);
}
void incrementGuessAttempt() {
numTentativi++;
LB_TENTATIVI.setText(String.valueOf(numTentativi));
}
void incrementError() {
numErrori++;
LB_ERRORI.setText(String.valueOf(numErrori));
}
void incrementMatch() {
numMatch++;
LB_MATCH.setText(String.valueOf(numMatch));
}
}
}
CardStore.java
package banryu79.mymemory;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import static java.lang.Math.random;
/**
* A simple collections of loaded images to use for Cards.
* @author francesco
*/
public class CardStore
{
public static final int DECK_SIZE = 12;
private final String IMAGES_PATH = "/banryu79/mymemory/images/";
private final String IMAGES_FRONT_NAME = "cardfront";
private final String IMAGE_RETRO_NAME = "cardback.jpg";
private Map<Integer, Icon> cards;
public CardStore() {
cards = new HashMap();
}
/**
* Load the deck from disk
*/
public void load() {
// Load "back-cover" image
int index = 0;
storeInMap(index, IMAGES_PATH+IMAGE_RETRO_NAME);
// Load "front-cover" images
index = 1;
String path = IMAGES_PATH + IMAGES_FRONT_NAME;
while (index <= DECK_SIZE) {
storeInMap(index, path+index+".jpg");
index++;
}
}
public List<CardButton> getNewDeck() {
// choose only DECK_SIZE/2 random unique images:
final int NUM = DECK_SIZE/2;
Set<Icon> chosen = new HashSet<Icon>(NUM);
while (chosen.size() != NUM) {
int index = (int) (random() * DECK_SIZE) + 1;
chosen.add(cards.get(index));
}
List<CardButton> deck =
new ArrayList<CardButton>(DECK_SIZE);
Icon backCover = cards.get(0);
for (Icon frontCover : chosen) {
CardButton card1 = new CardButton(frontCover, backCover);
CardButton card2 = new CardButton(frontCover, backCover);
deck.add(card1);
deck.add(card2);
}
Collections.shuffle(deck);
return deck;
}
private void storeInMap(int index, String imagePath) {
System.out.println("loading "+imagePath);
URL imgURL = getClass().getResource(imagePath);
if (imgURL == null)
throw new RuntimeException("Cannot find: "+imagePath);
ImageIcon icon = new ImageIcon(imgURL);
cards.put(index, icon);
}
public Map<Integer, Icon> getAll() {
return cards;
}
}
CardButton.java
package banryu79.mymemory;
import java.awt.Insets;
import javax.swing.Icon;
import javax.swing.JButton;
/**
* Basic Memory CardButton, implemented as a JButton.
* it has a common back-cover, and a specific front-cover, ad a unique identity.
*
* @author francesco
*/
public class CardButton extends JButton
{
private static final Insets NO_MARGINS = new Insets(0,0,0,0);
private Icon frontCover;
private Icon backCover;
private boolean showingFrontCover;
public CardButton(Icon front, Icon back) {
if (front == null)
throw new IllegalArgumentException("Front cover icon cannot be null.");
if (back == null)
throw new IllegalArgumentException("Back cover icon cannot be null.");
super.setMargin(NO_MARGINS);
super.setIcon(back);
showingFrontCover = false;
frontCover = front;
backCover = back;
}
/**
* Called by the EDT
*/
public void swapIcons() {
if (showingFrontCover) {
setIcon(backCover);
showingFrontCover = false;
}
else {
setIcon(frontCover);
showingFrontCover = true;
}
}
public boolean isShowingFrontCover() {
return showingFrontCover;
}
public void resetIcon() {
setIcon(null);
}
@Override
public boolean equals(Object o) {
if (o instanceof CardButton) {
CardButton other = (CardButton) o;
return backCover == other.backCover &&
frontCover == other.frontCover;
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + (frontCover != null ? frontCover.hashCode() : 0);
hash = 53 * hash + (backCover != null ? backCover.hashCode() : 0);
return hash;
}
@Override
public String toString() {
return "CardButton_" + (frontCover.hashCode()+backCover.hashCode()/1000);
}
}
Ti conviene copia-incollare il codice in un editor che colora la sintassi, per una consultazione più comoda.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.