Task: Minesweeper game



C#: 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]; 
        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;
    }

    
    public void ForEachCell(Action<int,int> action)
    {
        for (var i = 0; i < Height; i++)
        for (var j = 0; j < Width; j++)
            action(i,j);
    }

    
    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(){
        
        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());
    }
}





Python: 


gridsize  = (6, 4)
minerange = (0.2, 0.6)


try:
    raw_input
except:
    raw_input = input
    
import random
from itertools import product
from pprint import pprint as pp


def gridandmines(gridsize=gridsize, minerange=minerange):
    xgrid, ygrid = gridsize
    minmines, maxmines = minerange
    minecount = xgrid * ygrid    
    minecount = random.randint(int(minecount*minmines), int(minecount*maxmines))
    grid = set(product(range(xgrid), range(ygrid)))
    mines = set(random.sample(grid, minecount))
    show = {xy:'.' for xy in grid}
    return grid, mines, show

def printgrid(show, gridsize=gridsize):
    xgrid, ygrid = gridsize
    grid = '\n'.join(''.join(show[(x,y)] for x in range(xgrid))
                     for y in range(ygrid))
    print( grid )

def resign(showgrid, mines, markedmines):
    for m in mines:
        showgrid[m] = 'Y' if m in markedmines else 'N'

def clear(x,y, showgrid, grid, mines, markedmines):
    if showgrid[(x, y)] == '.':
        xychar = str(sum(1
                         for xx in (x-1, x, x+1)
                         for yy in (y-1, y, y+1)
                         if (xx, yy) in mines ))
        if xychar == '0': xychar = '.'
        showgrid[(x,y)] = xychar
        for xx in (x-1, x, x+1):
            for yy in (y-1, y, y+1):
                xxyy = (xx, yy)
                if ( xxyy != (x, y)
                     and xxyy in grid
                     and xxyy not in mines | markedmines ):
                    clear(xx, yy, showgrid, grid, mines, markedmines)

if __name__ == '__main__':
    grid, mines, showgrid = gridandmines()
    markedmines = set([])
    print( __doc__ )
    print( '\nThere are %i true mines of fixed position in the grid\n' % len(mines) )
    printgrid(showgrid)
    while markedmines != mines:
        inp = raw_input('m x y/c x y/p/r: ').strip().split()
        if inp:
            if inp[0] == 'm':
                x, y = [int(i)-1 for i in inp[1:3]]
                if (x,y) in markedmines:
                    markedmines.remove((x,y))
                    showgrid[(x,y)] = '.'
                else:
                    markedmines.add((x,y))
                    showgrid[(x,y)] = '?'
            elif inp[0] == 'p':
                printgrid(showgrid)
            elif inp[0] == 'c':
                x, y = [int(i)-1 for i in inp[1:3]]
                if (x,y) in mines | markedmines:
                    print( '\nKLABOOM!! You hit a mine.\n' )
                    resign(showgrid, mines, markedmines)
                    printgrid(showgrid)
                    break
                clear(x,y, showgrid, grid, mines, markedmines)
                printgrid(showgrid)
            elif inp[0] == 'r':
                print( '\nResigning!\n' )
                resign(showgrid, mines, markedmines)
                printgrid(showgrid)
                break
    
    print( '\nYou got %i and missed %i of the %i mines'
           % (len(mines.intersection(markedmines)),
              len(markedmines.difference(mines)),
              len(mines)) )