#!/usr/bin/env python
#-*- coding: utf-8 -*-
from pygame import *
from random import sample

class Game(list):
    
    class Cell(Rect):
        def __init__(self,y,x):
            self.type = 0
            self.disclosed = False
            self.py,self.px = y,x
            self.fading_level = 0
            self.flagged = False
            Rect.__init__(self,y*20+1,x*20+1,18,18)
            
    def __init__(self,width,height):
        
        def show():
            for cell in disclosed_cells:
                if cell.fading_level <= 10:
                    self.scr.fill((255-25*cell.fading_level,200-20*cell.fading_level,255-23*cell.fading_level),cell)
                    cell.fading_level +=1
                    self.scr.blit(image,(cell.inflate(cell.fading_level*2-20,cell.fading_level*2-20)),(cell.inflate(cell.fading_level*2-20,cell.fading_level*2-20)))
            display.update()
            time.wait(30)
        
        get_the_cells_around = lambda cell: [self[cell.px+x][cell.py+y] for y,x in (0,-1),(0,1),(-1,0),(1,0),(-1,-1),(1,-1),(-1,1),(1,1) if 0<=cell.px+x<height and 0<=cell.py+y<width]
            
        self.scr = display.set_mode((width*20,height*20))
        display.update(self.scr.fill((0,0,25)))
        self.extend([[self.Cell(y,x) for y in range(width)] for x in range(height)])
        display.update([self.scr.fill((255,255,255),cell) for cell in sum(self,[])])
        quantity_of_flagged_cells = 0
        quantity_of_mines = 0
        display.set_caption('Click one cell')
        cell_previously_pointed = self.Cell(0,0)
        while True:
            ev = event.wait()
            mouse_x,mouse_y = mouse.get_pos()
            cell_actually_pointed = self[mouse_y/20][mouse_x/20]
                 
            if ev.type == MOUSEBUTTONUP and ev.button == 1 and not cell_actually_pointed.flagged:
                # __________________________________________________________________________________________________________________
                # this part draw numbers and mines on image at the first click and thus prevent to find a mine at the first click
                if quantity_of_mines == 0:
                    image = Surface((width*20,height*20),SRCALPHA)
                    font.init()
                    FONT = font.Font(font.match_font('mono',1),14)
                    offset = (20-FONT.size(' ')[0])/2,0
                    quantity_of_mines = (width*height)/20
                    flattened_grid = sum(self,[])
                    for cell_ in get_the_cells_around(cell_actually_pointed)+[cell_actually_pointed]: flattened_grid.remove(cell_)
                    for cell_ in sample(flattened_grid,quantity_of_mines):
                        cell_.type = 'mine'
                        image.fill((140,0,0),cell_)
                        for cocell_ in get_the_cells_around(cell_):
                            if cocell_.type != 'mine':
                                cocell_.type += 1
                                image.fill((0,0,0,0),cocell_)
                                image.blit(FONT.render(str(cocell_.type),1,(250,250,250)),cocell_.move(offset))
                    remaining_cells = width*height-quantity_of_mines
                # __________________________________________________________________________________________________________________

                if cell_actually_pointed.type == 'mine':
                    disclosed_cells = sum(self,[])
                    for flattened_grid in range(11): show()
                    display.set_caption('YOU LOSE ! Hit any mouse button to replay')
                    break

                elif not cell_actually_pointed.disclosed:
                    cell_actually_pointed.disclosed = True
                    disclosed_cells = [cell_actually_pointed]
                    show()
                    z = t = 1
                    for cell in disclosed_cells:
                        remaining_cells -= 1
                        if not cell.type:
                            for cocell in get_the_cells_around(cell):
                                if not cocell.disclosed and not cocell.flagged:
                                    cocell.disclosed = True
                                    disclosed_cells.append(cocell)
                        z -= 1
                        if not z:
                            show()
                            z,t = len(disclosed_cells) - t,len(disclosed_cells)
                    for flattened_grid in range(9): show()
                    if remaining_cells == 0 and quantity_of_flagged_cells == 0:
                        display.set_caption('YOU WIN ! Hit any mouse button to replay')
                        break
                display.set_caption('Remain '+str(remaining_cells)+' cell(s)')
                
            elif ev.type == MOUSEBUTTONDOWN and ev.button == 3:
                if not cell_actually_pointed.disclosed:
                    if not cell_actually_pointed.flagged:
                        cell_actually_pointed.flagged = True
                        display.update(self.scr.fill((20,50,200),cell_actually_pointed.inflate(-2,-2)))
                        quantity_of_flagged_cells += 1
                    else:
                        cell_actually_pointed.flagged = False
                        display.update(self.scr.fill((255,255,255),cell_actually_pointed))
                        quantity_of_flagged_cells -= 1
            
            elif ev.type == QUIT: exit()

Game(42,26)
while True:
    ev = event.wait().type
    if ev == MOUSEBUTTONUP: Game(42,26)
    elif ev == QUIT: break
