user@linuxtrack:~ $ python -c 'print("Soyez les bienvenus !")'

Vous n'êtes pas identifié(e).

#1 08-07-2014 02:14:09

WarLocG
#! modo de compet

Programme réalisant des carrés magique - cli + gui

Voici un gros paquet de code que je partage pour le plus grand plaisir d'apprendre le langage et puis aussi pour profiter du programme en cas de besoin.

Juste une petite remarque avant de déposer cette source:

Avis aux personnes qui passent par là (pas forcément des membres du forum) et qui se servent, la réalisation de cette source m'a demandé du temps et de l'investissement. Ainsi, je partage librement mes sources mais elle n'est pas consacrées a des buts commerciaux. Merci de me laisser ma part de crédits sur le travail effectué en pensant à conserver l'auteur original du code source (c'est a dire moi). Ce n'est pas du WTFPL, c'est du GPLv3.

Vous êtes bien entendu libre de la modifier, de l'améliorer et de la repartager autour de vous, et c'est même souhaité smile

Vos remerciements, remarques et suggestions également sont les bienvenues et j'espère qu'elle vous pourra vous servir de références sur d'autres projets smile

Code:

/**
 * Carré magique - Magical square
 *
 * Programme java qui fabrique un carré magique.
 * Java program designed to built magical square.
 *
 * Copyright (C) 2014-07-07  WarLocG(C)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * ----------------------------------------------------------------
 * Ce programme est partagé librement en respect de la GNU GPLv3.
 * Veuillez ne pas réutiliser cette source à des fins commerciaux.
 */
 
/* imports de lib */
import java.util.Scanner;    /* Frappe clavier CLI */
import java.lang.Exception;  /* Gestion d'erreur */
import javax.swing.*;        /* GUI */
import java.awt.*;           /* Container et Component pour GUI */
import java.awt.event.*;     /* Listener's pour GUI */

/* structure du programme
 *
 * main <>--- FabriqueCarreM <>---------------- PasImpairException
 *                      |                                      |
 *                      |                                      |
 *            (abs)CarreM <>-----------------------------------'
 *                     /\
 *                    /__\
 *                      |
 *                      |-------------------------,
 *                      |                         |
 *                CarreMCLI <>-----, ,-----<> CarreMGUI <>--- GUI
 *                                 | |
 *                                Case
 *
 * Explication:
 * Réalisation d'un pattern fabrique sur CarreM, selon que l'utilisateur choisira
 * CLI ou GUI, le programme fabriquera un CarreM en fonction
 *
 */
 
/* classes */
/** Case contenant les nombres */
class Case{

  /* -- Attributs -- */
  
  private int nombre;       /* valeur contenue dans la case */
  private boolean bordure;  /* indique si la case est en bordure */
  
  /* -- Constructeur -- */
  
  public Case(){
    this.nombre = 0;        /* a la creation, nombre vaut 0 */
    this.bordure = false;   /* indique si la case est au bord */
  }
  
  /* -- Methodes -- */
  
  /** Methode verifiant si la case contient deja une valeur */
  public boolean estVide(){
    return (this.nombre == 0) ? true : false;
  }
  
  public int getNombre(){
    return this.nombre;
  }
  
  public void setNombre(int nombre){
    this.nombre = nombre;
  }
  
  /** Verifie si la case est sur un bord */
  public boolean estBordure(){
    return this.bordure;
  }
  
  public void setBordure(boolean bordure){
	this.bordure = bordure;
  }
}

/** Exception declenchée lorsque le nombre est impair */
class PasImpairException extends Exception{
  public PasImpairException(String message){super(message);}
}

abstract class CarreM{

  /* -- Attributs -- */
  
  protected int nombreM;       /* nombre magique calculé comme etant N² + N* ((N-1)*(int)(N/2)) */
  protected int nombre;        /* nombre donne en argument */
  protected Case[][] matrice;  /* tableau de case */
  
  /* -- Constructeur -- */
  
  public CarreM(int nombre) throws PasImpairException{
    if (! estImpair(nombre)) throw new PasImpairException("Un carré magique ne peut se créer qu'avec des nombres impairs.");
    else{
      this.nombre = nombre;
      this.nombreM = (nombre * nombre) + (nombre * ((nombre - 1) * (nombre / 2)));
      this.matrice = new Case[nombre][nombre];
      
      remplir();
	}   
  }
  
  /* -- Methodes -- */
  
  protected boolean estImpair(int nombre){
    return (nombre % 2 == 1) ? true : false;
  }
  
  protected int getNombre(){
	 return this.nombre;
  }
  
  protected int getNombreM(){
	 return this.nombreM;
  }
  
  protected boolean verifier(){
    int somme;
    boolean ok = true;
    
    /* test sur les lignes */
    for (int i=0; i<nombre; i++){
      somme = 0;
      for (int j=0; j<nombre; j++){
        somme += this.matrice[i][j].getNombre();
      }
      ok &= (somme == this.nombreM) ? true : false;
    }
    /* test sur les colonnes */
    for (int i=0; i<nombre; i++){
      somme = 0;
      for (int j=0; j<nombre; j++){
        somme += this.matrice[j][i].getNombre();
      }
      ok &= (somme == this.nombreM) ? true : false;
    }
    /* test sur les diagonales */
    somme = 0;
    for (int i=0; i<nombre; i++){
      somme += this.matrice[i][i].getNombre();
    }
    ok &= (somme == this.nombreM) ? true : false;
    
    return ok;
  }
  
  protected void remplir(){
	  int x,y,n;     /* x et y : position dans le plateau; n : nombre actuel */
	  int carre = this.getNombre() * this.getNombre(); /* le nombre au carré */
	  
	  /* creer la matrice d'objet Case */
	  for (int i=0;i<getNombre();i++){
		  for (int j=0;j<getNombre();j++){
			  this.matrice[i][j]=new Case();
		  }
	  }
	  
	  /* Algorithme : demo sur 3 x 3
	   * 
	   * On commence par placer 1 dans la case au centre de la dernière ligne:
	   * *-----*
	   * | | | |
	   * +-+-+-+
	   * | | | |
	   * +-+-+-+
	   * | |1| |
	   * *-----*
	   * 
	   * Ensuite, en partant du 1 on se deplace en diagonale bas/droite
	   * - si on rencontre un bord, on reporte de l autre coté
	   * - si la case est occupée, on place le nombre au dessus
	   * *-----*
	   * | | |2|
	   * +-+-+-+
	   * | | | |
	   * +-+-+-+
	   * | |1| |
	   * *-----*
	   * 
	   * *-----*
	   * | | |2|
	   * +-+-+-+
	   * |3| | |
	   * +-+-+-+
	   * | |1| |
	   * *-----*
	   * Ici la prochaine case est occupée, on la dépose au dessus
	   * *-----*
	   * |4| |2|
	   * +-+-+-+
	   * |3| | |
	   * +-+-+-+
	   * | |1| |
	   * *-----*
	   * Si vous avez correctement posé les nombres, la case centrale aura le nombre
	   * nombre magique / nombre; dans le cas du 3 * 3, le nombre magique vaut:
	   * 3² + 3*2*1 = 15; la case centrale devrait donc avoir 15/3 = 5;
	   * 
	   * Carré terminé:
	   * *-----*
	   * |4|9|2|
	   * +-+-+-+
	   * |3|5|7|
	   * +-+-+-+
	   * |8|1|6|
	   * *-----*
	   * Si toutes les cases ont pu etre remplies, c'est bon :)
	   * Le dernier nombre tombera en normalement sur la case centrale de la premiere ligne
	   * 
	   * Vérification: lignes, colonnes et diagonales doivent avoir pour valeur le nombre magique
	   * soit 15
	   */   
	   
	   /* detecter le centre de la derniere ligne */
	   x = this.getNombre()-1;
	   y = (int)(this.getNombre()/2);
	   n = 1; /* on commence par poser le 1 */
	   /* boucler jusqu' a ce que tout les nombres soient incrustés */
	   try{ 
	     /* juste un petit try - catch pour ne pas planter le programme en cas d Exception */
	   while(n < carre+1){
		  // on pose le 1		  
		  this.matrice[x][y].setNombre(n);
		  
		  /* detection des bords; dans la mesure ou l on se deplace toujours vers bas/droite 
		   * le test sur les coordonnees 0,0 n est pas utile */
		  if (x == this.getNombre()-1 | y == this.getNombre()-1){
			 this.matrice[x][y].setBordure(true);
		  }
		  
		  /* test si on est sur une bordure */
		  if (this.matrice[x][y].estBordure()){
			/* si on est arrivé dans le coin bas/droite, la case 0,0 est normalement deja occupée */
			if (x == this.getNombre()-1 && y == this.getNombre()-1){
				// arrivé dans le coin bas/droite, poser sur la case au dessus */
				x--;
			}else{
				// les autres cas, les cases sont normalement inoccupés. Report normal.		
				
				if (x+1 >= this.getNombre()){x=0;} else {x++;}
				if (y+1 >= this.getNombre()){y=0;} else {y++;}
			}
		  }else{
		    // on teste la case suivante
		    if (this.matrice[x+1][y+1].estVide()){ // vide => on place normalement
				//System.out.println("test - rentré dans le cas estVide");
				x++;
				y++;
			} else { // occupée => on place au dessus
				//System.out.println("test - rentré dans le cas estOccupe");
				x--;
			}
	      }
		  n++;		  
		  // la dernière case devrait normalement tomber sur la case centrale de la premiere ligne
	   }
	   
	   }catch(ArrayIndexOutOfBoundsException e){
		   // passer a la suite
	   }
  }
  abstract void construire();       /* fabrique la grille du carre magique (affiche en CLI)*/
  abstract void construireTest();   /* verifier si on a un carre magique */
  
  protected String aPropos(){
	String apropos = "\nA propos\n\n";
	apropos +=       "Programme réalisé par WarLocG(c). Juillet 2014\n";
	apropos +=       "Ce programme est partagé librement en respect de la GNU GPLv3.\n";
	apropos +=       "Veuillez ne pas réutiliser cette source à des fins commerciaux.";
	return apropos;
  }
}

/** Carre magique sur console */
class CarreMCLI extends CarreM {

  /* -- Constructeur -- */
  
  public CarreMCLI(int nombre) throws PasImpairException{
    super(nombre);
    
    construireTest();
    construire();
    
    System.out.println(super.aPropos());
  }
  
  /* -- Methodes -- */
  
  // a adapter ...
  @Override
  public void construire(){
    int i,j;
    /* bord sup de la grille -> *---+---+---* */
    String str = "*---";
    for (i=0; i<nombre-1; i++){ // partie interne uniq.; car. par car.
      str += "+---";
    }
    str += "*";
    System.out.println(str);
    
    /* partie centrale */
    for (i=0; i<(nombre*2)-1; i++){ // partie interne uniq.; ligne par ligne
      if (! estImpair(i)){
        str = "|";
        for (j=0; j<nombre; j++){ //partie interne + bord; par 2 car.
          str += String.format("%3d",this.matrice[i/2][j].getNombre())+"|";
        }
      }else{
        str = "+";
        for (j=0; j<nombre; j++){ //partie interne + bord; par 2 car.
          str += "---+";
        }
      }
      System.out.println(str);
    }
    
    /* bord inf de la grille -> *---+---+---* */
    str = "*---";
    for (i=0; i<nombre-1; i++){
      str += "+---";
    }
    str += "*";
    System.out.println(str);
  }
  
  @Override
  public void construireTest(){
	System.out.println("Carré magique vaut: "+this.getNombreM());
	System.out.println("Nombre central doit valoir: "+this.getNombreM()/this.getNombre());
	System.out.println("Nombre central vaut: "+this.matrice[this.getNombre()/2][this.getNombre()/2].getNombre());
	System.out.println("Nombre au sommet doit valoir: "+this.getNombre()*this.getNombre());
	System.out.println("Nombre au sommet vaut: "+this.matrice[0][this.getNombre()/2].getNombre());
	System.out.println("Carré magique vaut: "+this.getNombreM());
	System.out.println("La somme doit valoir: "+this.getNombreM());
	System.out.println("A passé les tests des sommes: "+super.verifier());
	System.out.println();
  }
}

/** Carre magique sur interface graphique */
class CarreMGUI extends CarreM {

  /* -- Constructeur -- */
  
  public CarreMGUI(int nombre) throws PasImpairException{
	  super(nombre);
	  
	  construire();
  }
  
  // appel a JFrame et Listener
  @Override
  public void construire(){                                   
	  // en commentaire: a quoi la methode sert + classe fournissant la methode a la suite
	  GUI gui = new GUI(this.getNombre(), this.matrice, this.aPropos()); // Fenetre et titre          JFrame
	  gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     // Operation à la fermeture  JFrame
	  gui.setTitle("Programme Carré  magique version GUI");   // Met un titre
	  gui.pack();                                             // Dimensionne la fenetre    Window
	  gui.setVisible(true);                                   // Rend visible !important!  Window
  }
  
  @Override
  public void construireTest(){
  }
}

class GUI extends JFrame implements ActionListener{
	
  private String apropos = ""; // attributs "global" pour partager avec le listener
	
  public GUI(int nombre, Case[][] matrice, String apropos){
	 
	 /* -- Attributs importés -- */	 
	 this.apropos = apropos;
	 
	 /* Barre des menus */
	 JMenuBar menuPrincipal = new JMenuBar();
	 JMenu jmMenu = new JMenu("Menu");
	 JMenuItem jmiAPropos = new JMenuItem("A propos");
	 JMenuItem jmiQuitter = new JMenuItem("Quitter");
	 
	 /* Contenant et layouts */
	 Container supportPrincipal = this.getContentPane();
	 Container supportCase = new Container();
	 
	 /* Composants (boutons, barre de texte, etc.. */
	 // aucun ici :P
	 
	 /* Pré-requis pour affichier la boite */
	 jmiAPropos.addActionListener(this); // on integre une action lors d'un clic sur "Quitter"
	 jmiQuitter.addActionListener(this); // on integre une action lors d'un clic sur "A Propos"	 
	 jmMenu.add(jmiAPropos);             // ajout de l'option "A Propos" dans le menu "Menu"	 
	 jmMenu.add(jmiQuitter);             // ajout de l'option "Quitter" dans le menu "Menu"	 
	 menuPrincipal.add(jmMenu);          // ajout du menu "Menu" dans la bar des menus
	 
	 supportCase.setLayout(new GridLayout(nombre,nombre));
	 for (int i=0; i<(nombre*nombre); i++){
		 // cree un tableau de JLabel contenant la valeur dans Case dans la matrice
		 supportCase.add(new JLabel(String.valueOf(matrice[i/nombre][i%nombre].getNombre())));
		 // Comme je ne travaille pas avec deux for imbriqués, je calcule ce que vaudrait i et j
	 }
	 supportCase.setSize(400,400);
	 
	 this.setJMenuBar(menuPrincipal);    // ajout de la bar des menus a la fenetre
	 supportPrincipal.add(supportCase);  // ajout du corps de la fenetre
  }
  
  /* -- Listener -- */
  
  @Override
  public void actionPerformed(ActionEvent action){
	/* decoupe de la string de l event pour sortir le menuItem correspondant a l action */
	String act = action.toString(), str;
	int debut = act.lastIndexOf("=")+1, fin = act.lastIndexOf("]");
	str = act.substring(debut,fin);
	
	/* switch - case non realisable avec des String, utilisation des if */  
	if( str.compareTo("A propos")==0){new JOptionPane().showMessageDialog(this,apropos);}
	else if( str.compareTo("Quitter")==0){this.dispose();}
	else{System.out.println("autre -> dbg: str vaut "+str);}
  }
	
}

/* pattern factory */

/** Pattern factory sur CarreM */
class FabriqueCarreM{
	
  /* -- Methode -- */
	
  public static CarreM build(int choix, int nombre) throws PasImpairException{
	if (choix == 1){
	  return new CarreMCLI(nombre);
	}else{ //choix == 2
	  return new CarreMGUI(nombre);
	}
  }
}

/* programme principale */

class main{
  public static void main(String[] args){
	// detection de l'environement pour savoir si X est lancé.. plus tard, sinon via
	// arguments lancé dans la commande, genre ${0} --gui pour le mode GUI.
	// en attendant, une question est posée dans le terminal
	Scanner sc = new Scanner(System.in);
	CarreM carre;
	System.out.print("CLI ou GUI ?\n 1. CLI\n 2. GUI\nVeuillez repondre par 1 ou 2 svp: ");
	int choix = sc.nextInt();
	if (choix == 1 | choix == 2){
	  System.out.println("La matrice sera un carré de combiens ? (ex: 3 => carré de 3x3)");
	  System.out.print("> ");
	  int nombre = sc.nextInt();
	  try{
	    carre = FabriqueCarreM.build(choix,nombre);
	  }catch (PasImpairException e){
	    System.out.println(e.getMessage());
	  }
	} // else abandon
	sc.close();
  }
}

Ce que ca fait en images:

Partie en CLI:
1404767323.png
(capture sur une version encore en phase beta)

Partie en GUI:
1404766975.png

Bonne amusement wink


Avant de poser vos questions, jeter un oeil ici
Mon CodeVault et Wiki : ici
Les messages privés envers le staff sont uniquement pour les cas d'urgence ou affaires privées (personnelles). Les demandes se feront exclusivement sur le forum. Merci de respecter cette clause sous peine de sanctions.

Hors ligne

#2 08-07-2014 06:21:02

IceF0x
#! Gourou Linux

Re : Programme réalisant des carrés magique - cli + gui

Joli travail smile


Utiliser des logiciels propriétaires, c'est comme les plats préparés, on est incapable de dire les conservateurs qu'ils contiennent, on dira toujours que c'est bon, mais ça ne remplacera jamais le repas fait maison par sa maman.
]:D #! Crunchbang & Archlinux GNU/Linux User ]:D

Hors ligne

#3 07-02-2015 23:29:27

Sylaar
Membre

Re : Programme réalisant des carrés magique - cli + gui

Bonsoir, merci pour ce partage !!!

Hors ligne

Pied de page des forums