Help with my match3 game

Hello from Russia, friends!
A can’t understand how i can realized
algorithm to find neighboring pieces and replacing them for another pieces

this example very simillar
But i dont understand how i can do this
Here my code

namespace match3_game_test1

 { 
 {
    GraphicsDeviceManager graphics
    SpriteBatch spriteBatch;

    Vector2 Centerposition = Vector2.Zero;

    Texture2D gridTexture;
    Texture2D boxTexture0;
    Texture2D boxTexture1;
    Texture2D boxTexture2;
    Texture2D boxTexture3;
    Texture2D boxTexture4;
    Texture2D boxTexture5;
    
    List<Box> piecesList;
    List<Box> backgroundbox;
    

    int tlsizeX = 50;
    int tlsizeY = 50;
    
    int[,] map = new int[,]{ {0,0,1,1,1,1,0,0},{0,1,1,1,1,1,1,0},{1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1},{0,1,1,1,1,1,1,0},{0,0,1,1,1,1,0,0}};

    #region //WINDOW RESOLUTION
    int screenWidth = 612;
    int screenHeight = 612;
     #endregion

    #region Private variables
    private MouseState _previousMouse, _currentMouse;
    private SpriteBatch _spriteBatch;
    private List<Tile> _tiles = new List<Tile>();
    private Random _rnd = new Random();
    private Box _currentlyDraggedTile, _tileUnderMouse;
    private Vector2 _startingPositionForCurrentlyDraggedTile, _currentMousePosition;
    private SpriteFont _bigFont;
    #endregion


    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";


    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        graphics.PreferredBackBufferWidth = screenWidth;
        graphics.PreferredBackBufferHeight = screenHeight;
        graphics.ApplyChanges();
        
        
        IsMouseVisible = true;
        
        base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
     
        gridTexture = Content.Load<Texture2D>("maps");
        boxTexture0 = Content.Load<Texture2D>("cude");
        boxTexture1 = Content.Load<Texture2D>("round");
        boxTexture2 = Content.Load<Texture2D>("triangle");
        boxTexture3 = Content.Load<Texture2D>("cude_purple");
        boxTexture4 = Content.Load<Texture2D>("round_purple");
        boxTexture5 = Content.Load<Texture2D>("triangle_purple");
        _bigFont = Content.Load<SpriteFont>("BigFont");

    Backgroundtiles();
    CreateTileswithTextures();
      


    }
 

 
    public void CreateTileswithTextures()
    {
        
        Random rnd = new Random();
        
        string[] texturelist;
        texturelist = new string[] { "triangle_purple", "round_purple", "triangle", "cude_purple", "round", "cude"};

        
        piecesList = new List<Box>();
       

        int x = 0;
        int y = 0;
        for (int i = 0; i < map.GetLength(0); i++)
        {
            for (int j = 0; j < map.GetLength(1); j++)
            {
                Vector2 topRightCorner = new Vector2(103,103);
                Texture2D texture = Content.Load<Texture2D>(texturelist[rnd.Next(texturelist.GetLength(0))]);
                Vector2 pos = new Vector2(x , y) + topRightCorner ;
                int a = map[i, j];
                if (a == 1)
                {
                    Box piece = new Box { Texture = texture, Position = pos };
                    piecesList.Add(piece);
                }

                x += tlsizeX;
            }
            x = 0;
            y += tlsizeY;
        }


       
    }
    void Backgroundtiles() 
    {
        backgroundbox = new List<Box>();
    
        int x = 0;
        int y = 0;
        for (int i = 0; i < map.GetLength(0); i++)
        {
            for (int j = 0; j < map.GetLength(1); j++)
            {
                Vector2 topRightCorner = new Vector2(103, 103);
                Vector2 pos = new Vector2(x, y) + topRightCorner;
               
                int a = map[i, j];
                if (a == 1)
                {
                    Box bpiece = new Box { Texture = gridTexture, Position = pos };
                    backgroundbox.Add(bpiece);
                }
                x += tlsizeX;

            }
            x = 0;
            y += tlsizeY;
        }


    
    }


   
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit();
        // TODO: Add your update logic here

        UpdateMouseStates();
        CheckForTileRelease();
        CheckForNewDrag();
        UpdateDraggedTilePosition();
    }

    private void CheckForTileRelease()
    {
        if (_currentMouse.LeftButton == ButtonState.Released)
        {
            if (_currentlyDraggedTile != null)
            {

                if (_tileUnderMouse != null)
                {
                    _currentlyDraggedTile.Position = _tileUnderMouse.Position;
                    _tileUnderMouse.Position = _startingPositionForCurrentlyDraggedTile;
                }
                else
                {
                    _currentlyDraggedTile.Position = _startingPositionForCurrentlyDraggedTile;
                }
            }
            _currentlyDraggedTile = null;
        }
    }
    private void CheckForNewDrag()
    {
        if (_previousMouse.LeftButton == ButtonState.Released && _currentMouse.LeftButton == ButtonState.Pressed)
        {
            _currentlyDraggedTile = GetTileUnderMouse();
            if (_currentlyDraggedTile != null)
            {
                _startingPositionForCurrentlyDraggedTile = _currentlyDraggedTile.Position;
            }
        }
    }
 
    private Box GetTileUnderMouse()
    {
        return piecesList.FirstOrDefault(piece =>
            piece.GetBounds().Contains((int)_currentMousePosition.X, (int)_currentMousePosition.Y)
            && piece != _currentlyDraggedTile);
    }
    private void UpdateDraggedTilePosition()
    {
        if (_currentlyDraggedTile != null)
        {
            _currentlyDraggedTile.Position = _currentMousePosition - Vector2.One * _currentlyDraggedTile.Texture.Width / 2;
        }
    }
    private void UpdateMouseStates()
    {
        _previousMouse = _currentMouse;
        _currentMouse = Mouse.GetState();
        _currentMousePosition = new Vector2(_currentMouse.X, _currentMouse.Y);
        _tileUnderMouse = GetTileUnderMouse();
    }


    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.DarkViolet);

        // TODO: Add your drawing code here
        spriteBatch.Begin();

        DrawText();

        DrawbackgroundTiles();

        DrawPiecesAndSelection();

        spriteBatch.End();
       
      
        base.Draw(gameTime);
    }

    private void DrawbackgroundTiles()
    {
        foreach (Box bpiece in backgroundbox)
        {
            MouseState mouseState = Mouse.GetState();
            if (bpiece.Bounds.Contains(mouseState.Position))
            {

                // TODO: Code to handle node being clicked...
                Texture2D select = Content.Load<Texture2D>("select");
                Rectangle rect = bpiece.Bounds;
                spriteBatch.Draw(select, rect, Color.WhiteSmoke);
            }

            bpiece.Draw(spriteBatch);
        }

    }
    private void DrawPiecesAndSelection()
    {

       
        foreach (Box piece in piecesList)
        {



            piece.Draw(spriteBatch);


        }
    }

    
    private void DrawText()
    {
        spriteBatch.DrawString(_bigFont, "Developer MaDcat413", new Vector2(50, 10), Color.White);
        
    }
     
    }
}

here is my BOX class

namespace match3_game_test1
{
    public class Box
    {
        public Texture2D Texture { get; set; }
        public Vector2 Position { get; set; }
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(Texture, Position, Color.White);
        }
        public Rectangle GetBounds()
        {
            return new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height);
        }
        public Rectangle Bounds
        {
            get { return new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height); }
        }
        

    }
}

Can you explain what isn’t working? Also it looks like some of your code isn’t formatted with the rest.

I need advice on how to make a chain of three identical elements disappear.

I need to understand the logic of constructing a method

Please be more specific. Do you mean disappear, as in you need help with the graphics? Or do you need help with an algorithm that can look at a 2d array and identify where there are three adjacent identical elements? The smaller and more specific your questions are, the easier it will be to help. If possible, can you point at specific parts of your code that don’t do what you want them to do?

Yes! I need help with an algorithm that can look at a 2d array and identify where there are minimum three adjacent identical element (vertically,horizontally)

please, i need deal with that, what direction i should follow?

A simple solution would be to do a double for loop, iterating over every element in the grid, and then for each element check the 3 in a row and in a column. Something like this:

for (int i = 1; i < numRows - 1; ++i) {
  for (int j = 1; j < numCols - 1; ++j) {
    bool hasColMatch = true;
    bool hasRowMatch = true;
    for (int k = -1; k <= 1; ++k) {
      if (k == 0)
        continue;
      if (grid[i+k][j] != grid[i][j])
        hasColMatch = false;
      if (grid[i][j+k] != grid[i][j])
        hasRowMatch = false;
    }

    // At this point, 'hasColMatch' and 'hasRowMatch' represent whether or not
    // there are 3 identical elements in a column or row, centered at coordinate (i, j)
  }
}

Does something like that work for you?

EDIT: actually, I see you wanted a minimum of 3, but potentially more. I can write a simple code block for that below too.

If you want just a minimum 3, but potentially more, maybe loop over all elements and count the number of adjacent elements from each point. You can keep a list of all the matches you’ve found and not add a new 3 if it’s already contained in a 4 you found. Something like this. It’s untested, but it should give you a good start. It should return a list of the longest matches found that are at least min length.

struct Match {
  public int i;
  public int j;
  public int colLength;
  public int rowLength;
  public Match(int i, int j, int colLength, int rowLength) {
    this.i = i;
    this.j = j;
    this.colLength = colLength;
    this.rowLength = rowLength;
  }
}

void TryAddMatch(Match match, List<Match> matches) {
  bool isOverlapping = false;
  foreach (Match other in matches) {
    if (other.i <= match.i &&
        other.j <= match.j &&
        other.i + other.colLength >= match.i + match.colLength &&
        other.j + other.rowLength >= match.j + match.rowLength) {
      isOverlapping = true;
      break;
    }
  }

  if (!isOverlapping)
    matches.Add(match);
}

List<Match> FindMatches(int[][] grid, int numRows, int numCols, int min = 3) {
  List<Match> matches = new List<Match>();
  for (int i = 0; i < numRows - min; ++i) {
    for (int j = 0; j < numCols - min; ++j) {
      int k;

      // Check for a match in the column
      for (k = 1; k < numRows - i; ++k) {
        if (grid[i+k][j] != grid[i][j])
          break;
      }
      if (k >= min)
        TryAddMatch(new Match(i, j, k, 1);

      // Check for a match in the row
      for (k = 1; k < numCols - i; ++k) {
        if (grid[i][j+k] != grid[i][j])
          break;
      }
      if (k >= min)
        TryAddMatch(new Match(i, j, 1, k);
    }
  }

  return matches;
}

thank you! I will try!

i am sorry, it is return error

It looks like it expects matches as the second parameter

And now we need to extract the names of the elements, compare them. Identical elements of at least 3 in a column and a line to be removed. Put new elements in place. Is my logic correct?