/**
* Démineur : le jeu
*
* Cette classe abstraite fournit une représentation d’une case du
* champ de mines. Chaque Case est initialement fermée, un clic bouton 1
* permet de l’ouvrir, et un clic bouton 3 de placer ou supprimer un drapeau.
* Cette classe gère la fin de partie.
*
* Un clic sur la case courante avec le bouton 1 de la souris l’ouvre
* par la méthode abstraite ouvreMoi() implémentée par les
* sous−classes Mine ou Vide
*
* Un clic avec le bouton 3 place un drapeau sur la case courante,
* mais sans l’ouvrir. Si le nombre de drapeaux bien placés (ie sur
* une Mine) est égal au nombre de mines, le joueur a gagné et c’est la
* fin de la partie.
*
* @author Vincent Granet ([email protected])
* @version 1.0.1
*
* Creation @date: 22−Nov−2016 15:48
* Last file update: 6−Jan−2017 16:38
*/
package demineur;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.*;
public abstract class Case extends JButton {
protected static int TAILLECASE = 42;
protected boolean fermée = true; // au départ la case est fermée
protected boolean drapeau = false; // et n’a pas de drapeau
//
protected ChampDeMines cdm; // champ de mines auquel la case courante appart
ient
protected int n; // numéro de la Case
/**
* Constructeur : initialise la Case courante et lui associe le listener pou
r
* gérer le clic de souris.
*/
public Case(ChampDeMines cdm) {
setPreferredSize(new Dimension(TAILLECASE,TAILLECASE));
//
this.cdm = cdm;
// ajouter le listener lorsqu’on clique sur la Case courante
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
try {
switch (e.getButton()) {
case MouseEvent.BUTTON1 : if (!drapeau) ouvreMoi(); br
eak;
case MouseEvent.BUTTON3 : if (estFermée()) toggleDrape
au();
}
}
catch (FinDePartie fdp) {
finDePartie(fdp.gagnée ? "Bravo !" : "Désolé, Perdu !");
}
}});
}
janv. 06, 17 16:38 Page 1/3Case.java
Printed by Vincent Granet
vendredi janvier 06, 2017 1/10
/**
* Rôle : ouvre la Case courante
*/
public abstract void ouvreMoi();
/**
* Rôle : renvoie le nombre de mines (0 ou 1) contenues dans la
* Case courante
*/
public abstract int nbMines();
/*
* Rôle : place ou enlève un drapeau sur la Case courante la
* partie est gagnée s’il le nombre de drapeaux est égal
* au nombre de mines et s’ils sont bien placés
*
*/
private void toggleDrapeau() throws FinDePartie {
int n = cdm.getNbMines();
drapeau = !drapeau;
setIcon(drapeau ? Démineur.DRAPEAU : null);
if (drapeau) {
cdm.incrNbDrapeaux();
Démineur.lMines.setText(String.valueOf(n−cdm.getNbDrapeaux()));
if (nbMines()==1) {
// on a placé un drapeau sur une mine
cdm.incrNbMinesTrouvées();
if (n==cdm.getNbMinesTrouvées() && n==cdm.getNbDrapeaux())
// Gagné !
throw new FinDePartie(true);
}
}
else {
cdm.decrNbDrapeaux();
Démineur.lMines.setText(String.valueOf(n−cdm.getNbDrapeaux()));
if (nbMines()==1) cdm.decrNbMinesTrouvées();
}
}
/**
* Rôle : gère la fin de partie, gagnée ou perdue, et ouvre toutes
* les Case du champ de mines et termine l’application
*/
public void finDePartie(String msg) {
for (Case c : this.cdm)
if (c.estFermée())
try { c.ouvreMoi(); }
catch (FinDePartie e) { /* ne rien faire */ }
//
JOptionPane.showMessageDialog(null, msg, "",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Rôle : affecte le numéro n sur la Case courante
*/
public void setNuméroCase(int n) { this.n = n; }
/**
* Rôle : renvoie true si la Case courante est fermée, et false sinon
*/
public boolean estFermée() { return this.fermée; }
/**
* Rôle : renvoie true si la Case courante est sans drapeau, et false sinon
janv. 06, 17 16:38 Page 2/3Case.java
Printed by Vincent Granet
2/10 vendredi janvier 06, 2017
*/
public boolean sansDrapeau() { return !this.drapeau; }
}
janv. 06, 17 16:38 Page 3/3Case.java
Printed by Vincent Granet
vendredi janvier 06, 2017 3/10
/**
* Cette classe représente le champ de mines et définit la
* structure de données qui mémorise les Case du champ de mines.
* Toutes les cases sont numérotées de [0 ; lignes*colonnes[
*
* @author Vincent Granet ([email protected])
* @version 1.0.1
*
* Creation @date: 22−Nov−2016 15:48
* Last file update: 5−Jan−2017 15:59
*/
package demineur;
import java.util.*;
import javax.swing.*;
public class ChampDeMines implements Iterable<Case> {
private final Random r = new Random();
private int lignes, colonnes, nbMines;
private int nbMinesTrouvées = 0;
private int nbDrapeaux = 0;
private Case lesCases[][];
/**
* Constructeur : intialise le ChampDeMines this à la dimension
* lxc avec n mines
*/
public ChampDeMines(int l, int c, int n) {
this.lesCases = new Case[l][c];
this.lignes = l;
this.colonnes = c;
this.nbMines=n;
this.initChampDeMines(l*c);
}
public void decrNbDrapeaux() { this.nbDrapeaux−−; }
public void incrNbDrapeaux() { this.nbDrapeaux++; }
public int getNbDrapeaux() { return this.nbDrapeaux; }
public void incrNbMinesTrouvées() { this.nbMinesTrouvées++; }
public void decrNbMinesTrouvées() { this.nbMinesTrouvées−−; }
public int getNbMinesTrouvées() { return this.nbMinesTrouvées; }
/**
* Rôle : initialise le tableau lesCases avec des cases Vide et
* nbMines cases Mine
*/
private void initChampDeMines(int nbCases) {
Vector<Case> v = new Vector<Case>();
// placer les cases Vide
for (int i=nbCases; i>this.nbMines; i−−) v.add(new Vide(this));
// placer les mines au hasard dans le champ
for (int i=0; i<this.nbMines; i++)
v.add(this.r.nextInt(v.size()), new Mine(this));
// mettre les Case dans la matrice et les numéroter
for (int i=0, n=0; i<this.lignes; i++)
for (int j=0; j<this.colonnes; j++) {
this.lesCases[i][j] = v.elementAt(n);
this.lesCases[i][j].setNuméroCase(n++);
}
}
// offsets pour accéder au cases adjacentes
private final int[] adj_l = { 0, −1, −1, −1, 0, +1, +1, +1 };
private final int[] adj_c = {−1, −1, 0, +1, +1, +1, 0, −1 };
/**
* Rôle : renvoie un Vector de cases adjacentes à la Case numéro n
janv. 06, 17 16:38 Page 1/2ChampDeMines.java
Printed by Vincent Granet
4/10 vendredi janvier 06, 2017
*/
public Vector<Case> lesCasesAdjacentes(int n) {
int lig = n/this.colonnes;
int col = n%this.colonnes;
Vector<Case> lca = new Vector<Case>();
// au maximum 8 Case adjacentes => calculer leurs coordonnées
for (int k=0; k<adj_l.length; k++)
try {
lca.add(this.lesCases[lig+adj_l[k]][col+adj_c[k]]);
}
catch (ArrayIndexOutOfBoundsException e) {
// coordonnées hors lesCases => ne rien faire
}
//
return lca;
}
/**
* Rôle : renvoie le nombre de mines total du champ de mines
*/
public int getNbMines() {
return nbMines;
}
public void setNbMines(int n) {
this.nbMines=n;
}
/**
* Rôle : renvoie un Iterator pour parcourir toutes
* Case du ChampDeMines this
*/
public Iterator<Case> iterator() {
Iterator<Case> it = new Iterator<Case>() {
private int i=0, j=0;
public boolean hasNext() {
return i!=lignes;
}
public Case next() {
Case c = lesCases[i][j++];
if (j==colonnes) {
j=0;
i++;
}
return c;
}
};
return it;
}
}
janv. 06, 17 16:38 Page 2/2ChampDeMines.java
Printed by Vincent Granet
vendredi janvier 06, 2017 5/10
/**
* Démineur : le jeu
*
* Classe principale qui lance le jeu du démineur.
* Voir règles : fr.wikipedia.org/wiki/Démineur_(jeu)
*
* @author Vincent Granet ([email protected])
* @version 1.0.1
*
* Creation @date: 22−Nov−2016 15:48
* Last file update: 25−Nov−2016 19:04
*/
package demineur;
import javax.swing.*;
import java.awt.*;
public class Démineur extends JFrame
{
private static String DIR = "demineur/Images/";
public static ImageIcon MINE = new ImageIcon(ClassLoader.getSystemResource(
DIR+"mine.png"));
public static ImageIcon MINEBARREE = new ImageIcon(ClassLoader.getSystemRes
ource(DIR+"mine−barree.png"));
public static ImageIcon DRAPEAU = new ImageIcon(ClassLoader.getSystemResour
ce(DIR+"drapeau.png"));
public static JLabel lMines;
/**
* Rôle : crée l’interface graphique du jeu
*/
public Démineur(int nbLignes, int nbColonnes, int nbMines) {
setTitle("Démineur : le jeu");
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
p.add(lMines = new JLabel(MINE));
lMines.setText(String.valueOf(nbMines));
//
p.add(initChamp(nbLignes, nbColonnes, nbMines));
getContentPane().add(p);
pack();
setVisible(true);
this.setResizable(false);
}
/**
* Antécédent : lignes x colonnes : dimension du champ de mines
* nbMines : nb de mines dans le champ
*
* Rôle : crée le champ de mines
*/
public JPanel initChamp(int nbLignes, int nbColonnes, int nbMines) {
//
JPanel p = new JPanel();
p.setLayout(new GridLayout(nbLignes, nbColonnes));
for (Case c : new ChampDeMines(nbLignes, nbColonnes, nbMines)) p.add(c);
return p;
}
public static void main(String [] args) {
String usage = "Usage : démineur facile|moyenne|difficile";
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (args.length!=1) System.err.println(usage);
else
janv. 06, 17 16:38 Page 1/2Démineur.java
Printed by Vincent Granet
6/10 vendredi janvier 06, 2017
switch (args[0]) {
case "facile" : new Démineur(9,9,10); break;
case "moyen" : new Démineur(16,16,40); break;
case "difficile" : new Démineur(16,30,99); break;
default: System.err.println(usage);
}
}
});
}
}
janv. 06, 17 16:38 Page 2/2Démineur.java
Printed by Vincent Granet
vendredi janvier 06, 2017 7/10
package demineur;
public class FinDePartie extends RuntimeException {
boolean gagnée;
public FinDePartie(boolean gagnée) {
this.gagnée=gagnée;
}
}
janv. 06, 17 16:38 Page 1/1FinDePartie.java
Printed by Vincent Granet
8/10 vendredi janvier 06, 2017
/**
* Démineur : le jeu
*
* Cette classe définit une Case contenant une mine, et définit la
* méthode ouvreMoi qui a pour effet de signaler au joueur que la
* partie est perdue et que le jeu est fini.
*
* @author Vincent Granet ([email protected])
* @version 1.0.1
*
* Creation @date: 22−Nov−2016 15:48
* Last file update: 24−Nov−2016 16:05
*/
package demineur;
import javax.swing.*;
import java.awt.event.*;
public class Mine extends Case {
/**
* Rôle : initialise this
*/
public Mine(ChampDeMines cdm) { super(cdm); }
/**
* Rôle : renvoie le nombre de mines contenues par this (IE 1)
*/
@Override
public int nbMines() {
return 1;
}
/**
* Rôle : ouvre la case courante visualise la mine et achève le
* jeu (partie perdue)
*
*/
@Override
public void ouvreMoi() throws FinDePartie {
if (sansDrapeau()) {
fermée=false;
setIcon(Démineur.MINE);
setBackground(java.awt.Color.RED);
throw new FinDePartie(false);
}
}
}
janv. 06, 17 16:38 Page 1/1Mine.java
Printed by Vincent Granet
vendredi janvier 06, 2017 9/10
/**
* Démineur : le jeu
*
* Cette classe définit une Case vide, et définit la méthode ouvreMoi
* qui indique le nombre de mines sur les cases
* adjacentes (ou rien s’il n’y en a pas)
*
* @author Vincent Granet ([email protected])
* @version 1.0.1
*
* Creation @date: 22−Nov−2016 15:48
* Last file update: 5−Jan−2017 15:48
*/
package demineur;
import javax.swing.ImageIcon;
import java.awt.event.*;
import java.util.Vector;
public class Vide extends Case {
public Vide(ChampDeMines cdm) { super(cdm); }
/**
* Rôle : renvoie le nombre de mines contenues par this (IE 0)
*/
@Override
public int nbMines() { return 0; }
/**
* Rôle : ouvre la case courante et indique le nombre de mines
* adjacentes si elle n’est pas marquée par un drapeau
*/
@Override
public void ouvreMoi() {
if (drapeau)
// drapeau mal placé
setIcon(Démineur.MINEBARREE);
else {
setEnabled(false);
fermée=false;
int nbm = compterMinesAdjacentes(n);
if (nbm!=0) {
setText(String.valueOf(nbm));
setBackground(java.awt.Color.WHITE);
}
}
}
/*
* Rôle : compte le nombre de mines dans les Case adjacentes
*/
private int compterMinesAdjacentes(int n) {
Vector<Case> lca = cdm.lesCasesAdjacentes(n);
// compter les mines dans 8 cases adjcentes
int nbm = 0;
for (Case c : lca) nbm+=c.nbMines();
if (nbm==0)
// pas de mine dans 8 cases adjacentes
// recommencer le calcul pour chacune de ces 8 cases
for (Case c : lca)
if (c.estFermée() && c.sansDrapeau()) c.ouvreMoi();
return nbm;
}
}
janv. 06, 17 16:38 Page 1/1Vide.java
Printed by Vincent Granet
10/10 vendredi janvier 06, 2017
1 / 5 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !