3
\$\begingroup\$

I'm a newbie in programming and in java and I need some lights and help.I'm developing a game in which two players have to play with tokens (say red and blue) by placing them in cells (75x75 grid). The goal is to "capture" opponent's tokens by surrounding them. (See the image, which is the actual game output, the surrounding is drawn by hand)

Game output and capturing scene

To do so, I need to make the tokens "listen" to neighborhood, meaning other cells in the grid. A token has to check for itself in the grid(what is its position in the grid) and check of there is another token close to it, checks it color (blue or red) then, in certain conditions, trigger the capturing mechanism (draw line segments from the last token to the first).

What I have done, technically:

  1. Created the grid ( Grid/board is a 2 dimensional array of Token objects.)

  2. The token (which is an enumeration:

    public enum Jeton{ VIDE, CERCLE_ROUGE, CERCLE_BLEU }).

  3. A current player is also a Token private Token joueurActuel; When it's a player's turn, they select an empty cell at which they click this place the joueurActuel into the grid/board at cell ligneSelectionnee, colonneSelectionnee then repaint the canvas with the newly added cell in the grid/board.

Everything works: every token is printed and switch as players click. Now i'm stuck on how to make the tokens listen the next cell surrounding them in order to see if there is an opponent or an ally so that

Someone suggested me the A algorithm* and the only documentations i found are in english - imagine the effort i have to do to understand properly. The one i found in french is about c++ implementation, I've no idea how to to it in java: keywords are different, etc.

PS: I posted this question on stack overflow first, but I guess no one is very interested in video games there and got downgraded (-3). I'm just 15, so please be more tolerent. Please apologise for my english, i learn it from school and my mother language is french (I live in Congo).

I'm unable to post image because of my reputation :'(

Here is my code (took me several months and thousands attemps to make it work though): variables names are in french, I can provide translation if needed.

    import javax.swing.JFrame;
    import java.awt.*;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.*;


    public final class Phagocyte extends JFrame {

        public  static final int LIGNES = 75; //Cellules = lignes x colonnes
        public static final int COLONNES = 75;//Cellules = lignes x colonnes

        //Noms des constants des dimensions variées utilisées pour le dessins graphiques
        public static final float TAILLE_CELLULE = (float) 20.0; //Largeur et hauteur des cellules (de forme carée)
        public static final int LARGEUR_DE_LA_TOILE = (int) (TAILLE_CELLULE * COLONNES); // Dessine la toille (tableau)
        public static final int HAUTEUR_DE_LA_TOILE = (int) (TAILLE_CELLULE * LIGNES);
        public static final int LARGEUR_DE_LA_GRILLE = 2; // La largeur des lignes de la grille
        public static final int DEMI_LARGEUR_GRILLE = LARGEUR_DE_LA_GRILLE / 2;

        //Les symboles (rouge et bleu) sont affichés à l'intérieur des cercles avec rembourage des bordures
        public static final int REMBOURAGE_CELLULE = (int) (TAILLE_CELLULE / 5);
        public static final int TAILLE_SYMBOLE = (int) (TAILLE_CELLULE - REMBOURAGE_CELLULE *2 ); //Largeur / Hauteur
        public static final int LARGEUR_TRAIT_SYMBOLE = 3; //Largeur des traits

        //Utiliser une table d'ennumération (class interne) pour représenter les états variés du jeu
        public enum EtatJeu{
            JOUE, NUL, CERCLE_ROUGE_GAGNE, CERCLE_BLEU_GAGNE
        }

        private EtatJeu etatActuel; //Etat actuel du jeu

        //Utiliser une table d'enumération (classe interne) pour représenter les contenu des cellules et seed
        public enum Jeton{
            VIDE, CERCLE_ROUGE, CERCLE_BLEU
        }

        private Jeton joueurActuel; //Le joueur qui a la main

        private Jeton[][] planche; //l'aire de jeu avec cellules composées des lignes et colonnes
        private DessineToile toile; //Dessine la toile (avec JPanel) pour l'air de jeu
        private JLabel barreDetat; // La barre d'état

        /*Constructeurs pour definir les composants du jeu et de l'interface utilisateur (IU)*/
        public Phagocyte(){

            toile = new DessineToile(); //Construit une toile (JPanel)
            toile.setPreferredSize(new Dimension(LARGEUR_DE_LA_TOILE, HAUTEUR_DE_LA_TOILE));

        //Comportement de la toile (JPanel) en rapport avec un clic de la souris
            toile.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) { //Gestion des clics de souris
            int sourisX = e.getX();
            int  sourisY = e.getY();

            //Verifier le clic sur les lignes et colonnes
            int ligneSelectionnee = (int) (sourisY / TAILLE_CELLULE);
            int colonneSelectionnee;
                colonneSelectionnee = (int) (sourisX / TAILLE_CELLULE);

            if(etatActuel == EtatJeu.JOUE){
                if(ligneSelectionnee >= 0 && ligneSelectionnee < LIGNES && colonneSelectionnee >= 0
                        && colonneSelectionnee < COLONNES &&
                        planche[ligneSelectionnee][colonneSelectionnee] == Jeton.VIDE){
                    planche[ligneSelectionnee][colonneSelectionnee] = joueurActuel; //Joue un tour
                    actualiseJeu(joueurActuel, ligneSelectionnee, colonneSelectionnee); //Met a jour l'etat de jeu
                    joueurActuel = (joueurActuel == Jeton.CERCLE_ROUGE)? Jeton.CERCLE_BLEU : Jeton.CERCLE_ROUGE;
                }
            } else { //Fin de la partie
                initJeu(); //Rejouer le jeu
            }
            //Actueliser le dessin de la toile
            repaint(); //Rappeler la fonction dessinner
        }

      });

        //Barre d'état (JPanel) pour afficher les messages
        barreDetat = new JLabel("  ");
        barreDetat.setFont(new Font(Font.DIALOG_INPUT, Font.ITALIC, 15));
        barreDetat.setBorder(BorderFactory.createEmptyBorder(2, 5, 4, 5));

        Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        cp.add(toile, BorderLayout.CENTER);
        cp.add(barreDetat, BorderLayout.NORTH);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack(); //Emballer tous les composants dans cette JFrame
        setTitle("Phagocyte par esQmo");
        setVisible(true); //Afficher cette fenetre

        planche = new Jeton[LIGNES][COLONNES]; //Allouer le tableau
        initJeu(); //Initialise les contenus de l'aire de jeu et ses variables    
    }
        /*initialisation  des contenus l'aire de jeu et les differenrs status*/
        public void initJeu(){
            for(int ligne = 0; ligne < LIGNES; ++ligne){
                for(int colonne = 0; colonne < COLONNES; ++colonne){
                    planche[ligne][colonne] = Jeton.VIDE; //Toutes les cellules sont vides
                }
            }
            etatActuel = EtatJeu.JOUE; //Pret a jouer
            joueurActuel = Jeton.CERCLE_ROUGE; //Le rouge ouvre la partie
        }

        public void actualiseJeu(Jeton leJeton, int ligneSelectionnee, int colonneSelectionnee) {
          if (aGagne(leJeton, ligneSelectionnee, colonneSelectionnee)) {  // check for win
             etatActuel= (leJeton == Jeton.CERCLE_ROUGE) ? EtatJeu.CERCLE_ROUGE_GAGNE : EtatJeu.CERCLE_BLEU_GAGNE;
          } else if (estNul()) {  // check for draw
             etatActuel = EtatJeu.CERCLE_BLEU_GAGNE;
          }
          // Otherwise, no change to current state (still GameState.PLAYING).
       }
     public boolean estNul() {
          for (int row = 0; row < LIGNES; ++row) {
             for (int col = 0; col < COLONNES; ++col) {
                if (planche[row][col] == Jeton.VIDE) {
                   return false; // an empty cell found, not draw, exit
                }
             }
          }
          return true;  // no more empty cell, it's a draw
       }

       public boolean aGagne(Jeton leJeton, int ligneSelectionnee, int colonneSelectionnee) {
return
    }   



    class DessineToile extends JPanel{

            @Override
            public void paintComponent(Graphics g){ //Invoqué via repaint()
                super.paintComponent(g); //Pour remplir l'arriere plan
                setBackground(Color.WHITE); //Defini la couleur de l'arriere plan

                //Dessine les lignes de la toile
                g.setColor(Color.BLACK);
                for(int ligne = 1; ligne < LIGNES; ++ligne){
                    g.fillRoundRect(0, (int) (TAILLE_CELLULE * ligne - DEMI_LARGEUR_GRILLE), LARGEUR_DE_LA_TOILE - 1,
                            LARGEUR_DE_LA_GRILLE, LARGEUR_DE_LA_GRILLE, LARGEUR_DE_LA_GRILLE);
                }
                for(int colonne = 1; colonne < COLONNES; ++colonne){
                    g.fillRoundRect((int) (TAILLE_CELLULE * colonne - DEMI_LARGEUR_GRILLE), 0
                            , LARGEUR_DE_LA_GRILLE, HAUTEUR_DE_LA_TOILE - 1,
                            LARGEUR_DE_LA_GRILLE, LARGEUR_DE_LA_GRILLE);
                }

                //Dessine le jeton (seed) pour toutes les cellules si elles ne sont pas vides
                //Utilise la Graphic2D pour le trait
                Graphics2D g2d = (Graphics2D)g;
                g2d.setStroke(new BasicStroke(LARGEUR_TRAIT_SYMBOLE,
                        BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); //Dessin en 2D uniquement
                for(int ligne = 0; ligne < LIGNES; ++ligne){
                    for(int colonne = 0; colonne < COLONNES; ++colonne){
                        int x1 = (int) (colonne * TAILLE_CELLULE + REMBOURAGE_CELLULE);
                        int y1 = (int) (ligne * TAILLE_CELLULE + REMBOURAGE_CELLULE);

                        if(planche[ligne][colonne] == Jeton.CERCLE_ROUGE){
                            g2d.setColor(Color.RED);
                            g2d.drawOval(x1, y1, TAILLE_SYMBOLE, TAILLE_SYMBOLE);
                            g2d.fillOval(x1, y1, TAILLE_SYMBOLE, TAILLE_SYMBOLE);
                        } else
                            if(planche[ligne][colonne] == Jeton.CERCLE_BLEU){
                                int x2 = (int) (colonne * TAILLE_CELLULE + REMBOURAGE_CELLULE);
                                g2d.setColor(Color.BLUE);
                                g2d.drawOval(x1, y1, TAILLE_SYMBOLE, TAILLE_SYMBOLE);
                                g2d.fillOval(x2, y1, TAILLE_SYMBOLE, TAILLE_SYMBOLE);
                            }
                    }

                }


                //Imprime les messages sur la barre d'etat
                if(etatActuel == EtatJeu.JOUE){
                    if(joueurActuel == Jeton.CERCLE_ROUGE){
                        barreDetat.setText("ROUGE, c'est votre tour");
                        barreDetat.setForeground(Color.RED);
                    } else {
                        barreDetat.setText("BLEU, c'est votre tour");
                        barreDetat.setForeground(Color.BLUE);
                        barreDetat.addMouseMotionListener(null);
                    }
                } else
                    if(etatActuel == EtatJeu.NUL){
                        barreDetat.setForeground(Color.yellow);
                        barreDetat.setText("Match nul! Cliquez pour rejouer");
                    } else
                        if(etatActuel == EtatJeu.CERCLE_ROUGE_GAGNE){
                            barreDetat.setText("Le jouer X a remporté la partie, cliquez pour rejouer");
                            barreDetat.setForeground(Color.RED);
                        } else
                            if(etatActuel == EtatJeu.CERCLE_BLEU_GAGNE){
                                barreDetat.setForeground(Color.BLUE);
                                barreDetat.setText("Le joueur O a remporté la partie, cliquez pour rejouer");
                            }
            }
        }

        /*La méthode principale*/
        public static void main(String[] args){
            SwingUtilities.invokeLater(() -> {
                Phagocyte phagocyte = new Phagocyte();
            });
        }
    }
\$\endgroup\$
  • \$\begingroup\$ I can't really make out your code, but the general approach I would make would be to iterate through your two dimenional array which stores where pieces are already placed. If a match is found, that is, it isn't empty, calculate the distance between your target position and the non-empty position using the indices of the array. Store this number and then compare all the number you have or just keep the highest one. If this doesn't help you, please add a comment to say what you want. \$\endgroup\$ – S. Mitchell Oct 15 '16 at 16:55
  • \$\begingroup\$ Hellp S.Mitchell, thanks for the reply. The problem is I don't know how to code it, how i could implement this algorithm to my java game? I can translate the code to make it clear to you? \$\endgroup\$ – esQmo_ Oct 15 '16 at 17:19
  • \$\begingroup\$ since many site are in English, it make it hard to me to understand. may be a human to human explanation could help me \$\endgroup\$ – esQmo_ Oct 15 '16 at 17:21
2
\$\begingroup\$

The best would be to create an independent class Jeton, which would contain an enumeration (as you currently do), but also the X and Y position in the grid (in which column and which line). To check if the token next to yours is ally or not, you could keep the table with all your Jetons, and iterate over it like this :

for (Jeton token : planche) {
    if(token != Jeton.VIDE) {
        //We check if there is a token in the same line and next to the one we want to place
        if(token.x == colonneSelectionnee - 1 || token.x == colonneSelectionnee + 1) { 
            //We check if there is a token in the same column and next to the one we want to place
            if(token.y == ligneSelectionnee - 1 || token.y == ligneSelectionnee + 1) {
                if(token != joueurActuel) { //We check if the token is ally or not
                     doSomething(); //Like attack
                } else {
                     doSomethingElse();
                }
            }
        }
    }    
}

I don't know if this code is the best way to implement this, but it is a way to do it. I hope it helped you :)

\$\endgroup\$
  • \$\begingroup\$ Hello cocosushi, thanks your advice. But I think there are many conditions to check for. Every toke must check (in 8 directions) if there is an ally next to it and if there is at least one enemy in the neighborhood. As an example in the image above. the 4 red token + one blue token \$\endgroup\$ – esQmo_ Oct 20 '16 at 10:56
  • \$\begingroup\$ Hi esQmo, the code I wrote up here is just a template, not something that works out of the box. It just shows how you could check bounds of every Token you have. I just more or less wrote what S. Mitchell commented to your question. \$\endgroup\$ – cocosushi Oct 20 '16 at 11:14
1
\$\begingroup\$

If I understand your question correctly, the problem you're trying to solve is to find out whether a newly placed token closes some area, therefore capturing other tokens.

The first solution that comes to my mind is to run a breadth-first search (explained on Wikipedia). Treat your own tokens as graph nodes, while edges exist whenever two tokens are neighbours. Placing a token captures an area if while running the search algorithm you encounter the starting token again. I can write some pseudocode for you if you need.

\$\endgroup\$
  • \$\begingroup\$ Hi Mikolaj Radwan, yes I would like that. I'm still a noob, so some simple things look really hard to me. Thanks \$\endgroup\$ – esQmo_ Oct 20 '16 at 12:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.