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:
- How to use observer pattern in your programming
- How to use
DataGridView
and its event
- How to use delegate
- How to make usercontrol
Using the Code
The main classes and interface are given below.
Interfaces
public interface IClick
{
bool RightClick(int x, int y, Presenter pr);
bool LeftClick(int x, int y, Presenter pr);
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
private readonly ObjectList mines;
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;
}
}
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;
}
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);
}
}
}
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