Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
266
Task/Minesweeper-game/C-sharp/minesweeper-game.cs
Normal file
266
Task/Minesweeper-game/C-sharp/minesweeper-game.cs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
class MineFieldModel
|
||||
{
|
||||
public int RemainingMinesCount{
|
||||
get{
|
||||
var count = 0;
|
||||
ForEachCell((i,j)=>{
|
||||
if (Mines[i,j] && !Marked[i,j])
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool[,] Mines{get; private set;}
|
||||
public bool[,] Opened{get;private set;}
|
||||
public bool[,] Marked{get; private set;}
|
||||
public int[,] Values{get;private set; }
|
||||
public int Width{ get{return Mines.GetLength(1);} }
|
||||
public int Height{ get{return Mines.GetLength(0);} }
|
||||
|
||||
public MineFieldModel(bool[,] mines)
|
||||
{
|
||||
this.Mines = mines;
|
||||
this.Opened = new bool[Height, Width]; // filled with 'false' by default
|
||||
this.Marked = new bool[Height, Width];
|
||||
this.Values = CalculateValues();
|
||||
}
|
||||
|
||||
private int[,] CalculateValues()
|
||||
{
|
||||
int[,] values = new int[Height, Width];
|
||||
ForEachCell((i,j) =>{
|
||||
var value = 0;
|
||||
ForEachNeighbor(i,j, (i1,j1)=>{
|
||||
if (Mines[i1,j1])
|
||||
value++;
|
||||
});
|
||||
values[i,j] = value;
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
// Helper method for iterating over cells
|
||||
public void ForEachCell(Action<int,int> action)
|
||||
{
|
||||
for (var i = 0; i < Height; i++)
|
||||
for (var j = 0; j < Width; j++)
|
||||
action(i,j);
|
||||
}
|
||||
|
||||
// Helper method for iterating over cells' neighbors
|
||||
public void ForEachNeighbor(int i, int j, Action<int,int> action)
|
||||
{
|
||||
for (var i1 = i-1; i1 <= i+1; i1++)
|
||||
for (var j1 = j-1; j1 <= j+1; j1++)
|
||||
if (InBounds(j1, i1) && !(i1==i && j1 ==j))
|
||||
action(i1, j1);
|
||||
}
|
||||
|
||||
private bool InBounds(int x, int y)
|
||||
{
|
||||
return y >= 0 && y < Height && x >=0 && x < Width;
|
||||
}
|
||||
|
||||
public event Action Exploded = delegate{};
|
||||
public event Action Win = delegate{};
|
||||
public event Action Updated = delegate{};
|
||||
|
||||
public void OpenCell(int i, int j){
|
||||
if(!Opened[i,j]){
|
||||
if (Mines[i,j])
|
||||
Exploded();
|
||||
else{
|
||||
OpenCellsStartingFrom(i,j);
|
||||
Updated();
|
||||
CheckForVictory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenCellsStartingFrom(int i, int j)
|
||||
{
|
||||
Opened[i,j] = true;
|
||||
ForEachNeighbor(i,j, (i1,j1)=>{
|
||||
if (!Mines[i1,j1] && !Opened[i1,j1] && !Marked[i1,j1])
|
||||
OpenCellsStartingFrom(i1, j1);
|
||||
});
|
||||
}
|
||||
|
||||
void CheckForVictory(){
|
||||
int notMarked = 0;
|
||||
int wrongMarked = 0;
|
||||
ForEachCell((i,j)=>{
|
||||
if (Mines[i,j] && !Marked[i,j])
|
||||
notMarked++;
|
||||
if (!Mines[i,j] && Marked[i,j])
|
||||
wrongMarked++;
|
||||
});
|
||||
if (notMarked == 0 && wrongMarked == 0)
|
||||
Win();
|
||||
}
|
||||
|
||||
public void Mark(int i, int j){
|
||||
if (!Opened[i,j])
|
||||
Marked[i,j] = true;
|
||||
Updated();
|
||||
CheckForVictory();
|
||||
}
|
||||
}
|
||||
|
||||
class MineFieldView: UserControl{
|
||||
public const int CellSize = 40;
|
||||
|
||||
MineFieldModel _model;
|
||||
public MineFieldModel Model{
|
||||
get{ return _model; }
|
||||
set
|
||||
{
|
||||
_model = value;
|
||||
this.Size = new Size(_model.Width * CellSize+1, _model.Height * CellSize+2);
|
||||
}
|
||||
}
|
||||
|
||||
public MineFieldView(){
|
||||
//Enable double-buffering to eliminate flicker
|
||||
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer,true);
|
||||
this.Font = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold);
|
||||
|
||||
this.MouseUp += (o,e)=>{
|
||||
Point cellCoords = GetCell(e.Location);
|
||||
if (Model != null)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
Model.OpenCell(cellCoords.Y, cellCoords.X);
|
||||
else if (e.Button == MouseButtons.Right)
|
||||
Model.Mark(cellCoords.Y, cellCoords.X);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Point GetCell(Point coords)
|
||||
{
|
||||
var rgn = ClientRectangle;
|
||||
var x = (coords.X - rgn.X)/CellSize;
|
||||
var y = (coords.Y - rgn.Y)/CellSize;
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
static readonly Brush MarkBrush = new SolidBrush(Color.Blue);
|
||||
static readonly Brush ValueBrush = new SolidBrush(Color.Black);
|
||||
static readonly Brush UnexploredBrush = new SolidBrush(SystemColors.Control);
|
||||
static readonly Brush OpenBrush = new SolidBrush(SystemColors.ControlDark);
|
||||
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
var g = e.Graphics;
|
||||
if (Model != null)
|
||||
{
|
||||
Model.ForEachCell((i,j)=>
|
||||
{
|
||||
var bounds = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
|
||||
if (Model.Opened[i,j])
|
||||
{
|
||||
g.FillRectangle(OpenBrush, bounds);
|
||||
if (Model.Values[i,j] > 0)
|
||||
{
|
||||
DrawStringInCenter(g, Model.Values[i,j].ToString(), ValueBrush, bounds);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g.FillRectangle(UnexploredBrush, bounds);
|
||||
if (Model.Marked[i,j])
|
||||
{
|
||||
DrawStringInCenter(g, "?", MarkBrush, bounds);
|
||||
}
|
||||
var outlineOffset = 1;
|
||||
var outline = new Rectangle(bounds.X+outlineOffset, bounds.Y+outlineOffset, bounds.Width-2*outlineOffset, bounds.Height-2*outlineOffset);
|
||||
g.DrawRectangle(Pens.Gray, outline);
|
||||
}
|
||||
g.DrawRectangle(Pens.Black, bounds);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static readonly StringFormat FormatCenter = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment=StringAlignment.Center
|
||||
};
|
||||
|
||||
void DrawStringInCenter(Graphics g, string s, Brush brush, Rectangle bounds)
|
||||
{
|
||||
PointF center = new PointF(bounds.X + bounds.Width/2, bounds.Y + bounds.Height/2);
|
||||
g.DrawString(s, this.Font, brush, center, FormatCenter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MineSweepForm: Form
|
||||
{
|
||||
|
||||
MineFieldModel CreateField(int width, int height)
|
||||
{
|
||||
var field = new bool[height, width];
|
||||
int mineCount = (int)(0.2 * height * width);
|
||||
var rnd = new Random();
|
||||
while(mineCount > 0)
|
||||
{
|
||||
var x = rnd.Next(width);
|
||||
var y = rnd.Next(height);
|
||||
if (!field[y,x])
|
||||
{
|
||||
field[y,x] = true;
|
||||
mineCount--;
|
||||
}
|
||||
}
|
||||
return new MineFieldModel(field);
|
||||
}
|
||||
|
||||
public MineSweepForm()
|
||||
{
|
||||
var model = CreateField(6, 4);
|
||||
var counter = new Label{ };
|
||||
counter.Text = model.RemainingMinesCount.ToString();
|
||||
var view = new MineFieldView
|
||||
{
|
||||
Model = model, BorderStyle = BorderStyle.FixedSingle,
|
||||
};
|
||||
var stackPanel = new FlowLayoutPanel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
FlowDirection = FlowDirection.TopDown,
|
||||
Controls = {counter, view}
|
||||
};
|
||||
this.Controls.Add(stackPanel);
|
||||
model.Updated += delegate{
|
||||
view.Invalidate();
|
||||
counter.Text = model.RemainingMinesCount.ToString();
|
||||
};
|
||||
model.Exploded += delegate {
|
||||
MessageBox.Show("FAIL!");
|
||||
Close();
|
||||
};
|
||||
model.Win += delegate {
|
||||
MessageBox.Show("WIN!");
|
||||
view.Enabled = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
Application.Run(new MineSweepForm());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue