Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple Mine Sweeping Game

0.00/5 (No votes)
22 Sep 2008 1  
A simple mine sweeping game using C#

Introduction

This article is a simple example for beginners who are just learning C#. Windows's winmine is an interesting game, so I like to write this game to learn the following things:

  1. How to use observer pattern in your programming
  2. How to use DataGridView and its event
  3. How to use delegate
  4. How to make usercontrol

Using the Code

The main classes and interface are given below.

Interfaces

public interface IClick
{
    //to set mine flag 
    bool RightClick(int x, int y, Presenter pr);
    //whether trigger mine
    bool LeftClick(int x, int y, Presenter pr);

    //double click
    bool BothClick(int x, int y, Presenter pr);
}
public interface ICoordinate
{
    int XCoordinate { get;}
    int YCoordinate { get;}
    void SetCoordinate(int x, int y);
}

public interface IGetSetValue
{
    void Initialization();
    int Lines { get;set;}
    int Columns { get;set;}
    int MineNums { get;set;}
}
public interface IOberverable
{
    void Register(IObserver ober);
    void UnRegister(IObserver ober);
}
public interface IObserver
{
    void Update(EventArgs brgs);
}

Main Class

The SweepingMap class defines form's width, height and number of mines, the main methods of the class are LeftClick which means mouse's left click on DataGridView cells, RightClick which means mouse's right click on DataGridView cells, BothClick means mouse's double click on DataGridView cells.

public class SweepingMap : IClick, IGetSetValue
    {
        #region Private Field
        /// <summary>
        /// to store mines
        /// </summary>
        private readonly ObjectList mines;
        /// <summary>
        /// to store the mines which are found
        /// </summary>
        private readonly ObjectList flags;
        private readonly ObjectList hasAccessed;
        private int lines;
        private int columns;
        private int mineNums;
        private Random ran = new Random();
        #endregion
        #region Public Attributes
        public ObjectList Mines
        {
            get
            {
                return this.mines;
            }
        }
        public ObjectList Flags
        {
            get
            {
                return this.flags;
            }
        }
        public int Lines
        {
            get
            {
                return this.lines;
            }
            set
            {
                this.lines = value;
            }
        }
        public int Columns
        {
            get
            {
                return this.columns;
            }
            set
            {
                this.columns = value;
            }
        }
        public int MineNums
        {
            get
            {
                return this.mineNums;
            }
            set
            {
                this.mineNums = value;
            }
        }
        #endregion
        #region Constructor
        public SweepingMap()
        {
            this.mines = new ObjectList();
            this.flags = new ObjectList();
            hasAccessed = new ObjectList();
        }
        #endregion
        #region Private Methods
        private int CertainCondition(int x, int y, Condition condition)
        {
            int count = 0;
            for (int i = x - 1; i <= x + 1; i++)
            {
                for (int j = y - 1; j <= y + 1; j++)
                {
                    if ((i >= 0 && i < Lines) && (j >= 0 && 
			j < Columns) && !(i == x && j == y))
                    {
                        if (condition(i, j))
                            count++;
                    }
                }
            }        
            return count;
        }
        private bool CheckSuccess()
        {
            int count = 0;
            foreach (GridObject f in this.Flags.ObjectTable.Keys)
            {
                foreach (GridObject m in this.Mines.ObjectTable.Keys)
                {
                    if (this.Flags.ObjectTable[f].Equals(this.Mines.ObjectTable[m]))
                        count++;
                }
            }
            if (count == this.Mines.ObjectTable.Count)
                return true;
            else
                return false;
        }
        #endregion
        #region Public Methods
        public void Initialization()
        {
            this.mines.Clear();
            this.flags.Clear();
            this.hasAccessed.Clear();
            for (int i = 0; i < this.MineNums; i++)
            {
                int x = ran.Next(this.Lines);
                int y = ran.Next(this.Columns);
#if Debug
                System.Diagnostics.Debug.Print("Coordinate:({0},{1}) \n", x, y);
#endif
                if (!this.mines.ContainsKey(x, y))
                    this.mines.Add(x, y);
                else
                    i -= 1;
            }
        }
        //to set mine flag 
        public bool RightClick(int x, int y, Presenter pr)
        {
            if (this.flags.ContainsKey(x, y))
            {
                this.flags.Remove(x, y);
                pr(x, y, true);
            }
            else
            {
                if (!this.hasAccessed.ContainsKey(x, y) && 
				!this.flags.ContainsKey(x, y))
                {
                    this.flags.Add(x, y);
                    pr(x, y, false);
                }
            }
            if (this.Flags.Length == this.Mines.Length)
            {
                if (CheckSuccess())
                {
                    return true;
                }
            }
            return false;
        }
        //whether trigger mine
        public bool LeftClick(int x, int y, Presenter pr)
        {
            if (!this.Flags.ContainsKey(x, y))
            {
                if (this.Mines.ContainsKey(x, y))
                {
                    pr(x, y, "Mine");
                    return false;
                }
                else
                {
                    GridTraversing(x, y, pr);
                    return true;
                }
               
            }
            return true;
        }
        private void GridTraversing(int x, int y, Presenter pr)
        {
            Stack<GridObject> stack = new Stack<GridObject>();
            GridObject tmp = new GridObject(x, y);
            stack.Push(tmp);
            Condition condition = new Condition(this.Mines.ContainsKey);
            while (!(stack.Count == 0))
            {
                tmp = stack.Pop();
                int num = CertainCondition(tmp.XCoordinate, tmp.YCoordinate, condition);
                hasAccessed.Add(tmp.XCoordinate, tmp.YCoordinate);
                if (num == 0)
                {
                    pr(tmp.XCoordinate, tmp.YCoordinate, num);
                    for (int i = tmp.XCoordinate - 1; i <= tmp.XCoordinate + 1; i++)
                    {
                        for (int j = tmp.YCoordinate - 1; j <= tmp.YCoordinate + 1; j++)
                        {
                            if (i >= 0 && i < Lines && j >= 0 && j < Columns 
                                && !hasAccessed.ContainsKey(i, j) 
                                && !this.Flags.ContainsKey(i, j))
                            {
                                pr(i, j, num);
                                hasAccessed.Add(i,j);
                                stack.Push(new GridObject(i, j));
                            }
                        }
                    }
                }
                else
                {
                    pr(tmp.XCoordinate, tmp.YCoordinate, num);
                }
            }
        }
        //double click
        public bool BothClick(int x, int y, Presenter pr)
        {
            Condition condition = new Condition(this.Mines.ContainsKey);
            int num = CertainCondition(x, y, condition);
            condition = new Condition(this.flags.ContainsKey);
            int count = CertainCondition(x, y, condition);
            if (count == 0)
                return true;
            if (num == count)
            {
                for (int i = x - 1; i <= x + 1; i++)
                {
                    for (int j = y - 1; j <= y + 1; j++)
                    {
                        if (i >= 0 && i < Lines && j >= 0 && j < Columns 
                           && !(i == x && j == y))
                        {
                            if (!(this.flags.ContainsKey(i, j))) 
                            {
                                if (!LeftClick(i, j, pr))
                                    return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
        public void DisplayAllMines(int x, int y, Presenter pr)
        {
            int i, j;
            foreach (GridObject cur in mines.ObjectTable.Keys)
            {
                i = mines.ObjectTable[cur].XCoordinate;
                j = mines.ObjectTable[cur].YCoordinate;
                if (i != x && j != y)
                    pr(i, j, mines.ObjectTable[cur]);
            }
        }
        #endregion
    }

History

  • 22nd September, 2008: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here