commit 5c0578eacd523ce105f69e94aea13c443d80d840 Author: KeyZiro Date: Mon Dec 6 22:07:53 2021 +0100 Projet diff --git a/Block.java b/Block.java new file mode 100644 index 0000000..b62c83f --- /dev/null +++ b/Block.java @@ -0,0 +1,140 @@ +/** + * La classe Block est utilisée pour créer les blocs + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ + +import java.awt.*; +import javax.swing.*; + + +public class Block extends JPanel { + private int column; + private int line; + private char color; + private int status; + + /** + * Constructeur uniquement destiné à la création des variables publiques. + * + * @param blockColumn le numéro de la colonne où se trouve le bloc + * @param blockLine le numéro de la ligne où se trouve le bloc + * @param blockColor la couleur du bloc + */ + public Block(int blockColumn, int blockLine, char blockColor) { + super(); + this.column = blockColumn; + this.line = blockLine; + this.color = blockColor; + this.status = 1; + } + + /** + * Renvoie le numéro de colonne du bloc + * + * @return Renvoie le numéro de colonne du bloc (de 0 à 14) + */ + public int getColumn() { + return this.column; + } + + /** + * Renvoie le numéro de ligne du bloc + * + * @return Renvoie le numéro de ligne du bloc (de 0 à 9) + */ + public int getLine() { + return this.line; + } + + /** + * Renvoie la couleur du bloc + * + * @return Renvoie la couleur du bloc ('R', 'V' ou 'B') + */ + public char getColor() { + return this.color; + } + + /** + * Renvoie le status + * + * @return Renvoie le status du bloc (1 ou 0) + */ + public int getStatus() { + return this.status; + } + + /** + * Modifie le numéro de colonne du bloc + * + * @param blockColumn le numéro de la colonne que l'on souhaite affecter au bloc (de 0 à 14) + */ + public void setColumn(int blockColumn) { + this.column = blockColumn; + } + + /** + * Modifie le numéro de ligne du bloc + * + * @param blockLine le numéro de la ligne que l'on souhaite affecter au bloc (de 0 à 9) + */ + public void setLine(int blockLine) { + this.line = blockLine; + } + + /** + * Modifie la couleur du bloc + * + * @param blockColor la couleur que l'on souhaite affecter au bloc ('R', 'V' ou 'B') + */ + public void setColor(char blockColor) { + this.color = blockColor; + } + + /** + * Modifie le status du bloc + * + * @param blockStatus le status que l'on souhaite affecter au bloc (1 ou 0) + */ + public void setStatus(int blockStatus) { + this.status = blockStatus; + } + + /** + * Actualise les graphiques du block + */ + @Override + public void paintComponent(Graphics g) { + if (this.isOpaque()) { + g.setColor(this.getBackground()); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + } + if(this.status == 1) { + + if(this.color == 'R') { + Image img = getToolkit().getImage(this.getClass().getResource("/img/rouge.png")); + g.drawImage(img, 0, 0, this); + } + + else if(this.color=='V') { + Image img = getToolkit().getImage(this.getClass().getResource("/img/vert.png")); + + g.drawImage(img, 0, 0, this); + } + + else if(this.color=='B') { + Image img = getToolkit().getImage(this.getClass().getResource("/img/bleu.png")); + g.drawImage(img, 0, 0, this); + } + } + else { + g.setColor(Color.WHITE); + g.drawOval(0, 0, 50, 50); + g.fillOval(0, 0, 50, 50); + } + } + + +} diff --git a/FinalScreen.java b/FinalScreen.java new file mode 100644 index 0000000..f267434 --- /dev/null +++ b/FinalScreen.java @@ -0,0 +1,44 @@ +/** + * La classe FinalScreen est utilisée pour afficher l'écran de fin de partie + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ +import javax.swing.*; +import java.awt.*; + +public class FinalScreen extends JFrame { + /** + * Constructeur déstiné à créer l'écran de fin. + * + * @param gameInstance l'instance de jeu + */ + public FinalScreen(int score) { + FinalScreenListener fsListener = new FinalScreenListener(this); + + JPanel scorePanel = new JPanel(); + JLabel scoreLabel = new JLabel("Votre score : " + String.valueOf(score)); + + scorePanel.add(scoreLabel, JPanel.CENTER_ALIGNMENT); + + JPanel p = new JPanel(); + p.setLayout(new GridLayout(1,2)); + + JButton restartBtn = new JButton("Revenir"); + JButton exitBtn = new JButton("Quitter"); + + restartBtn.addActionListener(fsListener); + exitBtn.addActionListener(fsListener); + + scorePanel.add(scoreLabel); + p.add(restartBtn); + p.add(exitBtn); + + this.add(scorePanel, BorderLayout.NORTH); + this.add(p); + this.setPreferredSize(new Dimension(300, 300)); + this.pack(); + this.setLocationRelativeTo(null); + this.setVisible(true); + } +} \ No newline at end of file diff --git a/FinalScreenListener.java b/FinalScreenListener.java new file mode 100644 index 0000000..5ceb3cc --- /dev/null +++ b/FinalScreenListener.java @@ -0,0 +1,33 @@ +/** + * La classe FinalScreenListener est utilisée pour donner un rôle aux boutons de l'écran de fin + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ +import java.awt.event.*; +import javax.swing.JFrame; + +public class FinalScreenListener implements ActionListener { + + private JFrame fsFrame; + + public FinalScreenListener(JFrame fsFrame) { + this.fsFrame = fsFrame; + } + + public void actionPerformed(ActionEvent e) { + // On récupère l'action afin d'exécuter le code qui lui est attribué + String action = e.getActionCommand(); + + switch(action) + { + case "Revenir": + fsFrame.dispose(); + break; + + case "Quitter": + System.exit(0); + break; + } + } +} \ No newline at end of file diff --git a/Grid.java b/Grid.java new file mode 100644 index 0000000..378dd69 --- /dev/null +++ b/Grid.java @@ -0,0 +1,395 @@ +/** + * La classe Grid est utilisée pour générer la grille de blocs + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ + +import java.io.*; +import java.awt.*; +import javax.swing.*; +import java.util.Random; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +public class Grid extends JPanel { + + private Random random = new Random(); + private int col = 15; + private int row = 10; + private char charTab[][] = new char[10][15]; + private Block blockTab[][] = new Block[10][15]; + private String[] connectedCellList = null; + private final ArrayList cellNeigbors = new ArrayList<>(); + private HUD gameHUD; + private int score = 0; + + /** + *Constructeur de la Grid : Génère une grille aléatoire. + *@param HUD Nom de l'HUD + */ + public Grid(HUD gameHUD) { + this.gameHUD = gameHUD; + this.setLayout(new GridLayout(row,col,0,0)); + this.setBackground(Color.WHITE); + this.initGrid(); + } + + /** + *TODO : Surchage du constructeur avec le fichier + * + *@param s Nom du fichier + *@param HUD Nom de l'HUD + */ + public Grid(String s, HUD gameHUD) { + this.gameHUD = gameHUD; + this.setLayout(new GridLayout(row,col,0,0)); + try { + + File grid_file = new File(s); + FileInputStream flux = new FileInputStream(grid_file); + + this.initGrid(flux); + + try { + flux.close(); + } + + catch (IOException e) { + System.err.println("Impossible de fermer le fichier " + s + " !"); + } + } + + catch (FileNotFoundException e) { + System.err.println("Impossible d'ouvrir le fichier " + s + " !"); + } + } + /** + * Met en place la grille + * + */ + public void initGrid() { + GridMouseHandler gridMouseHandler = new GridMouseHandler(); + + int i,j; + for (i=0; i= 0 && (matrix_X + dx) < (matrix.length) + && (matrix_Y + dy) >= 0 && (matrix_Y + dy) < (matrix[0].length) + && matrix[matrix_X + dx][matrix_Y + dy] == matrix[matrix_X][matrix_Y] + && matrix[matrix_X][matrix_Y] != '1') { + // Pour les celulles avec des voisins à la même valeur + String neighbor = String.valueOf((matrix_X + dx)) + ";" + String.valueOf((matrix_Y + dy)); + if (!this.cellNeigbors.contains(neighbor)) { + this.cellNeigbors.add(neighbor); + // Récursivité pour les voisins + String[] tmp = getMatrixNeighCells(matrix, matrix_X + dx, matrix_Y + dy); + if (tmp != null) { + for (String str : tmp) { + if (!this.cellNeigbors.contains(str)) { + this.cellNeigbors.add(str); + } + } + } + } + } + } + + // On return la liste s'il y'a au moins une cellule voisine aux valeurs adjacente à celle de base + if (this.cellNeigbors.size() >= 2) { + return this.cellNeigbors.toArray(new String[this.cellNeigbors.size()]); + } + return null; + } + + /** + * Permet de vérifier s'il y'a des lignes vides en dessous de chaques boules. + * S'il y'en a, on abaisse d'un niveau la boule et on fait une récursion. + *@param j Numéro de colonne + */ + public void reorganizeCol(int j) { + for(int i = 0; i < row-1; i++) { + if(blockTab[i][j].getStatus() == 1 && blockTab[i+1][j].getStatus() == 0) { + blockTab[i+1][j].setColor(blockTab[i][j].getColor()); + blockTab[i+1][j].setStatus(1); + blockTab[i][j].setStatus(0); + blockTab[i+1][j].setBackground(Color.WHITE); + blockTab[i][j].setBackground(Color.WHITE); + charTab[i][j]='1'; + charTab[i+1][j]=blockTab[i+1][j].getColor(); + reorganizeCol(j); + } + } + this.validate(); + this.repaint(); + } + + /** + * Permet de vérifier si une des colonnes est vide. Si oui, on décale et on relance. + *@param i Numéro de col + */ + public void reorganizeRow(int i) { + int nbCount = 0; + for(int j = 0; j < row; j++) { + if(blockTab[j][i].getStatus() == 0) { + nbCount++; + } + if(nbCount == row) { + for(int k = 0; k < row; k++) { + blockTab[k][i].setColor(blockTab[k][i+1].getColor()); + if(blockTab[k][i+1].getStatus() == 1) { + blockTab[k][i].setStatus(1); + blockTab[k][i+1].setStatus(0); + charTab[k][i]=blockTab[k][i+1].getColor(); + } + blockTab[k][i].setBackground(Color.WHITE); + blockTab[k][i+1].setBackground(Color.WHITE); + charTab[k][i+1]='1'; + } + if(i != col-2) { + reorganizeRow(i+1); + } + } + + } + this.validate(); + this.repaint(); + + } + + /** + * Getter du tableau de la grille + * + *@return tableau de la grille + */ + public char[][] getGrid() { + return this.charTab; + } + + /** + * Un setter avec incrémentation du score + * On change le label du score. + */ + public void addScore(int score) { + this.score += score; + gameHUD.setScoreLabel(this.score); + } + + /** + * Getter du score + * @return le score + */ + public int getScore() { + return this.score; + } + + /** + * On itère chaque blocs pour savoir s'il leur reste des voisins + * Si non, on fait gagner le joueur + * @return un bool, true marquant la victoire du joueur. + */ + + public void checkWin() { + int moveLeft = 0; + for (int i=0; i< blockTab.length; i++) { + for (int j=0; j< blockTab[i].length; j++) { + cellNeigbors.clear(); + connectedCellList = getMatrixNeighCells(getGrid(), i,j); + if (connectedCellList != null && connectedCellList.length > 1) moveLeft++; + } + } + if(moveLeft <= 0) endGame(); + } + + /** + * Créé l'écran de fin de partie + */ + public void endGame() { + FinalScreen fs = new FinalScreen(score); + JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this); + topFrame.dispose(); + } + + /** + * Mouse Event + */ + public class GridMouseHandler extends MouseAdapter { + + /** + * Si le joueur passe la souris sur un des Blocks, + * on vérifie les cellules voisines du block ponté + * puis on change le backGround des cellules voisines + */ + @Override + public void mouseEntered(MouseEvent evt) { + Block source = (Block) evt.getSource(); + for (int i = 0; i < blockTab.length; i++) { + for (int j = 0; j < blockTab[i].length; j++) { + if (blockTab[i][j] == source) { + cellNeigbors.clear(); + connectedCellList = getMatrixNeighCells(getGrid(), i, j); + + if (connectedCellList != null && connectedCellList.length > 1) { + for (String cells : connectedCellList) { + int x = Integer.valueOf(cells.split(";")[0]); + int y = Integer.valueOf(cells.split(";")[1]); + blockTab[x][y].setBackground(Color.YELLOW); + } + } + } + } + } + } + + /** + * Si le joueur quitte le block avec le pointeur de souris, + * on remet le background à sa couleur de base + */ + @Override + public void mouseExited(MouseEvent evt) { + if (connectedCellList != null) { + for (String cells : connectedCellList) { + int x = Integer.valueOf(cells.split(";")[0]); + int y = Integer.valueOf(cells.split(";")[1]); + blockTab[x][y].setBackground(Color.WHITE); + } + } + } + + /** + * Si le joueur clique et relâche la souris, + * on désactive le block (en changeant le status), + * on remet le fond, on lui assigne une couleur hors du champs + * (afin de désactiver le surlignage), et on réorganise les + * lignes et colonnes du grid. + * On cherche aussi si le joueur a gagné en appelant CheckWin() + */ + @Override + public void mouseReleased(MouseEvent evt) { + if (connectedCellList != null) { + int ccListSize = connectedCellList.length; + for (String cells : connectedCellList) { + int x = Integer.valueOf(cells.split(";")[0]); + int y = Integer.valueOf(cells.split(";")[1]); + charTab[x][y]='1'; + blockTab[x][y].setStatus(0); + blockTab[x][y].setBackground(Color.WHITE); + } + addScore((ccListSize-2) * (ccListSize-2)); + for(int j = 0; j < col; j++) { + reorganizeCol(j); + } + for(int i = (col-2) ; i >= 0; i--) { + reorganizeRow(i); + } + } + checkWin(); + mouseEntered(evt); + } + } + +} \ No newline at end of file diff --git a/HUD.java b/HUD.java new file mode 100644 index 0000000..36a6cf7 --- /dev/null +++ b/HUD.java @@ -0,0 +1,35 @@ +/** + * La classe HUD est utilisée pour générer le HUD (interface) du jeu. + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ + +import java.awt.Color; +import javax.swing.*; +import javax.swing.border.MatteBorder; + +public class HUD extends JPanel { + + private int score = 0; + public JLabel label2; + /** + *Constructeur du HUD : Genère un HUD. + */ + public HUD() { + this.setBorder(new MatteBorder(1, 1, 2, 1, Color.black)); + JLabel label = new JLabel("Score : "); + label2 = new JLabel(Integer.toString(score)); + this.add(label); + this.add(label2); + } + + /** + * Setter du Score. + */ + public void setScoreLabel(int score) { + label2.setText(Integer.toString(score)); + } + + +} \ No newline at end of file diff --git a/Main.java b/Main.java new file mode 100644 index 0000000..babae6b --- /dev/null +++ b/Main.java @@ -0,0 +1,5 @@ +public class Main { + static public void main(String[] args) { + Menu m = new Menu(); + } +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..315ae2c --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +JC = javac +.SUFFIXES: .java .class +.java.class: + $(JC) $*.java + +CLASSES = \ + Menu.java \ + MenuListener.java \ + SameGame.java \ + HUD.java \ + FinalScreen.java \ + FinalScreenListener.java \ + Grid.java \ + Main.java + +default: classes + +classes: $(CLASSES:.java=.class) + +run: + make + java Main + +clean: + $(RM) *.class \ No newline at end of file diff --git a/Menu.java b/Menu.java new file mode 100644 index 0000000..e99957e --- /dev/null +++ b/Menu.java @@ -0,0 +1,73 @@ +/** + * La classe Menu est utilisée pour créer le menu du jeu + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ +import java.awt.*; +import javax.swing.JPanel; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JFrame; +import javax.swing.border.BevelBorder; + +public class Menu extends JFrame { + + private JButton playBtn; + private JButton playFromFileBtn; + private JButton quitBtn; + + public Menu() { + JFrame frame = new JFrame("SameGame by Lucas Grandjean & Adil Hammerschmidt"); + frame.setPreferredSize(new Dimension(300, 300)); + frame.add(new MenuPanel()); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public class MenuPanel extends JPanel { + + public MenuPanel() { + MenuListener mListener = new MenuListener(); + setOpaque(true); + setBackground(new Color(67,133,200)); + + setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.anchor = GridBagConstraints.NORTH; + + add(new JLabel("

SameGame


"), gbc); + add(new JLabel("Lucas GRANDJEAN"), gbc); + add(new JLabel("Adil HAMMERSCHMIDT
"), gbc); + + + gbc.anchor = GridBagConstraints.CENTER; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 0, 5, 0); + JPanel buttons = new JPanel(new GridBagLayout()); + buttons.setBackground(new Color(57,108,160)); + buttons.setBorder(new BevelBorder(BevelBorder.RAISED)); + + playBtn = new JButton("Jouer"); + playBtn.addActionListener(mListener); + + playFromFileBtn = new JButton("Charger une grille"); + playFromFileBtn.addActionListener(mListener); + + quitBtn = new JButton("Quitter"); + quitBtn.addActionListener(mListener); + + buttons.add(playBtn, gbc); + buttons.add(playFromFileBtn, gbc); + buttons.add(quitBtn, gbc); + + gbc.weighty = 1; + + add(buttons, gbc); + } + + } +} diff --git a/MenuListener.java b/MenuListener.java new file mode 100644 index 0000000..1ecd2d6 --- /dev/null +++ b/MenuListener.java @@ -0,0 +1,39 @@ +/** + * La classe MenuListener est utilisée pour donner un rôle aux boutons du menu + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import java.io.*; + +import javax.swing.JFileChooser; + +public class MenuListener implements ActionListener { + + public void actionPerformed(ActionEvent e) { + // On récupère l'action afin d'exécuter le code qui lui est attribué + String action = e.getActionCommand(); + + switch(action) + { + case "Jouer": + SameGame g1 = new SameGame(); + break; + + case "Charger une grille": + // On sélectionne le fichier à l'aide de JFileChooser + JFileChooser chooser = new JFileChooser(); + int ret = chooser.showOpenDialog(null); + if (ret == JFileChooser.APPROVE_OPTION) { + SameGame g2 = new SameGame(chooser.getSelectedFile().getAbsolutePath()); + } + break; + + case "Quitter": + System.exit(0); + break; + } + } +} \ No newline at end of file diff --git a/OutOfRangeBlock.java b/OutOfRangeBlock.java new file mode 100644 index 0000000..c205096 --- /dev/null +++ b/OutOfRangeBlock.java @@ -0,0 +1,8 @@ +public class OutOfRangeBlock extends Exception { + + @Override + public String toString() { + return ("Le bloc est en dehors de la range demandée"); + } + +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc7fb63 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# SameGame + +Ce jeu est une copie du célèbre "SameGame" + +## Projet Tutoré 2021 + +Ce jeu a été conçu dans le but du projet tutoré de 2021, à l'IUT Sénart-Fontainebleau. + +### Installation + +Grâce au Makefile intégré, l'installation sera très simple. + +``` +Clonez le projet dans un dossier vide +``` +``` +Utilisez la commande make afin de compiler le jeu +``` +``` +Profitez d'une expérience de jeu inégalée avec make run ! +``` + +### Langage de programmation + +* [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) - Le langage Java. + +## Auteurs + +* **Lucas Grandjean** +* **Adil Hammerschmidt** + +## Licence + +Ce jeu est libre de droit, utilisez le comme bon vous semble ! + +## Remerciements + +* Les élèves du DUT Informatique pour leur aide +* Les professeurs du DUT Informatique pour leur conseils \ No newline at end of file diff --git a/SameGame.java b/SameGame.java new file mode 100644 index 0000000..d873e0d --- /dev/null +++ b/SameGame.java @@ -0,0 +1,47 @@ +/** + * La classe SameGame est utilisée pour assembler HUD et Grid afin de former le jeu. + * + * @version 0.1 + * @author Adil HAMMERSCHMIDT & Lucas GRANDJEAN + */ + +import java.awt.BorderLayout; +import javax.swing.*; + +public class SameGame extends JFrame { + + private int tempScore = 0; + private HUD gameHUD = new HUD(); + + /** + * Constructeur de classe + */ + public SameGame() { + Grid gameGrid = new Grid(this.gameHUD); + this.add(BorderLayout.CENTER, gameGrid); + this.add(BorderLayout.NORTH, this.gameHUD); + this.pack(); + this.setSize(800, 650); + this.setLocation(300, 300); + this.setResizable(false); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setVisible(true); + } + + /** + * (Surchage) Constructeur de classe + * @param s Fichier texte de la Grid + */ + public SameGame(String s) { + Grid gameGrid = new Grid(s, this.gameHUD); + this.add(BorderLayout.CENTER, gameGrid); + this.add(BorderLayout.NORTH, this.gameHUD); + this.pack(); + this.setSize(800, 650); + this.setLocation(300, 300); + this.setResizable(false); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setVisible(true); + } + +} \ No newline at end of file diff --git a/img/bleu.png b/img/bleu.png new file mode 100644 index 0000000..bef6849 Binary files /dev/null and b/img/bleu.png differ diff --git a/img/rouge.png b/img/rouge.png new file mode 100644 index 0000000..2c4d904 Binary files /dev/null and b/img/rouge.png differ diff --git a/img/vert.png b/img/vert.png new file mode 100644 index 0000000..8823b4f Binary files /dev/null and b/img/vert.png differ diff --git a/rapport_pt_final.pdf b/rapport_pt_final.pdf new file mode 100644 index 0000000..4affd0d Binary files /dev/null and b/rapport_pt_final.pdf differ diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..4f79e7e --- /dev/null +++ b/test.txt @@ -0,0 +1,10 @@ +RVVRRVRVBBBBRBV +BVVVVRBVVBRRVRB +VBBRVRBVRRBRRRR +BRBVBRBBVVBRVRV +RVBVBBBRRBRRRBV +RVVVBBRBVVBVVRB +BRBRBBBRBVRVRRV +VRRVVBBVVBBRVVV +BVRRVVBRVRRRBVV +BBRBBBBRVVRRVRB \ No newline at end of file