11# Python Version 2.7.3 
22# File: minesweeper.py 
33
4- from  Tkinter  import  * 
5- import  tkMessageBox 
6- import  random 
4+ from  tkinter  import  * 
5+ from  tkinter  import  messagebox  as  tkMessageBox 
76from  collections  import  deque 
7+ import  random 
8+ import  platform 
9+ import  time 
10+ 
11+ SIZE_X  =  10 
12+ SIZE_Y  =  10 
13+ 
14+ STATE_DEFAULT  =  0 
15+ STATE_CLICKED  =  1 
16+ STATE_FLAGGED  =  2 
17+ 
18+ BTN_CLICK  =  "<Button-1>" 
19+ BTN_FLAG  =  "<Button-2>"  if  platform .system () ==  'Darwin'  else  "<Button-3>" 
820
921class  Minesweeper :
1022
1123    def  __init__ (self , master ):
1224
1325        # import images 
14-         self .tile_plain  =  PhotoImage (file  =  "images/tile_plain.gif" )
15-         self .tile_clicked  =  PhotoImage (file  =  "images/tile_clicked.gif" )
16-         self .tile_mine  =  PhotoImage (file  =  "images/tile_mine.gif" )
17-         self .tile_flag  =  PhotoImage (file  =  "images/tile_flag.gif" )
18-         self .tile_wrong  =  PhotoImage (file  =  "images/tile_wrong.gif" )
19-         self .tile_no  =  []
26+         self .tiles  =  {
27+             "plain" : PhotoImage (file  =  "images/tile_plain.gif" ),
28+             "clicked" : PhotoImage (file  =  "images/tile_clicked.gif" ),
29+             "mine" : PhotoImage (file  =  "images/tile_mine.gif" ),
30+             "flag" : PhotoImage (file  =  "images/tile_flag.gif" ),
31+             "wrong" : PhotoImage (file  =  "images/tile_wrong.gif" ),
32+             "numbers" : []
33+         }
2034        for  x  in  range (1 , 9 ):
21-             self .tile_no .append (PhotoImage (file  =  "images/tile_" + str (x )+ ".gif" ))
35+             self .tiles [ "numbers" ] .append (PhotoImage (file  =  "images/tile_" + str (x )+ ".gif" ))
2236
2337        # set up frame 
2438        frame  =  Frame (master )
@@ -36,167 +50,165 @@ def __init__(self, master):
3650        # create buttons 
3751        self .buttons  =  dict ({})
3852        self .mines  =  0 
39-         x_coord  =  1 
40-         y_coord  =  0 
41-         for  x  in  range (0 , 100 ):
42-             mine  =  0 
43-             # tile image changeable for debug reasons: 
44-             gfx  =  self .tile_plain 
45-             # currently random amount of mines 
46-             if  random .uniform (0.0 , 1.0 ) <  0.1 :
47-                 mine  =  1 
48-                 self .mines  +=  1 
49-             # 0 = Button widget 
50-             # 1 = if a mine y/n (1/0) 
51-             # 2 = state (0 = unclicked, 1 = clicked, 2 = flagged) 
52-             # 3 = button id 
53-             # 4 = [x, y] coordinates in the grid 
54-             # 5 = nearby mines, 0 by default, calculated after placement in grid 
55-             self .buttons [x ] =  [ Button (frame , image  =  gfx ),
56-                                 mine ,
57-                                 0 ,
58-                                 x ,
59-                                 [x_coord , y_coord ],
60-                                 0  ]
61-             self .buttons [x ][0 ].bind ('<Button-1>' , self .lclicked_wrapper (x ))
62-             self .buttons [x ][0 ].bind ('<Button-3>' , self .rclicked_wrapper (x ))
63- 
64-             # calculate coords: 
65-             y_coord  +=  1 
66-             if  y_coord  ==  10 :
67-                 y_coord  =  0 
68-                 x_coord  +=  1 
69-         
70-         # lay buttons in grid 
71-         for  key  in  self .buttons :
72-             self .buttons [key ][0 ].grid ( row  =  self .buttons [key ][4 ][0 ], column  =  self .buttons [key ][4 ][1 ] )
73- 
74-         # find nearby mines and display number on tile 
75-         for  key  in  self .buttons :
76-             nearby_mines  =  0 
77-             if  self .check_for_mines (key - 9 ):
78-                 nearby_mines  +=  1 
79-             if  self .check_for_mines (key - 10 ):
80-                 nearby_mines  +=  1 
81-             if  self .check_for_mines (key - 11 ):
82-                 nearby_mines  +=  1 
83-             if  self .check_for_mines (key - 1 ):
84-                 nearby_mines  +=  1 
85-             if  self .check_for_mines (key + 1 ):
86-                 nearby_mines  +=  1 
87-             if  self .check_for_mines (key + 9 ):
88-                 nearby_mines  +=  1 
89-             if  self .check_for_mines (key + 10 ):
90-                 nearby_mines  +=  1 
91-             if  self .check_for_mines (key + 11 ):
92-                 nearby_mines  +=  1 
93-             # store mine count in button data list 
94-             self .buttons [key ][5 ] =  nearby_mines 
95-             #if self.buttons[key][1] != 1: 
96-             #    if nearby_mines != 0: 
97-             #        self.buttons[key][0].config(image = self.tile_no[nearby_mines-1]) 
53+         for  x  in  range (0 , SIZE_X ):
54+             for  y  in  range (0 , SIZE_Y ):
55+                 if  y  ==  0 :
56+                     self .buttons [x ] =  {}
57+ 
58+                 id  =  str (x ) +  "_"  +  str (y )
59+                 isMine  =  False 
60+ 
61+                 # tile image changeable for debug reasons: 
62+                 gfx  =  self .tiles ["plain" ]
63+ 
64+                 # currently random amount of mines 
65+                 if  random .uniform (0.0 , 1.0 ) <  0.1 :
66+                     isMine  =  True 
67+                     self .mines  +=  1 
68+ 
69+                 self .buttons [x ][y ] =  {
70+                     "id" : id ,
71+                     "isMine" : isMine ,
72+                     "state" : STATE_DEFAULT ,
73+                     "coords" : {
74+                         "x" : x ,
75+                         "y" : y 
76+                     },
77+                     "widget" : Button (frame , image  =  gfx ),
78+                     "mines" : 0  # calculated after grid is built 
79+                 }
80+ 
81+                 self .buttons [x ][y ]["widget" ].bind (BTN_CLICK , self .lclicked_wrapper (x , y ))
82+                 self .buttons [x ][y ]["widget" ].bind (BTN_FLAG , self .rclicked_wrapper (x , y ))
83+ 
84+                 # lay buttons in grid 
85+                 self .buttons [x ][y ]["widget" ].grid ( row  =  x , column  =  y  )
86+ 
87+         # loop again to find nearby mines and display number on tile 
88+         for  x  in  range (0 , SIZE_X ):
89+             for  y  in  range (0 , SIZE_Y ):
90+                 nearby_mines  =  0 
91+                 nearby_mines  +=  1  if  self .check_for_mines (x - 1 , y - 1 ) else  0   #top right 
92+                 nearby_mines  +=  1  if  self .check_for_mines (x - 1 , y ) else  0     #top middle 
93+                 nearby_mines  +=  1  if  self .check_for_mines (x - 1 , y + 1 ) else  0   #top left 
94+                 nearby_mines  +=  1  if  self .check_for_mines (x , y - 1 ) else  0     #left 
95+                 nearby_mines  +=  1  if  self .check_for_mines (x , y + 1 ) else  0     #right 
96+                 nearby_mines  +=  1  if  self .check_for_mines (x + 1 , y - 1 ) else  0   #bottom right 
97+                 nearby_mines  +=  1  if  self .check_for_mines (x + 1 , y ) else  0     #bottom middle 
98+                 nearby_mines  +=  1  if  self .check_for_mines (x + 1 , y + 1 ) else  0   #bottom left 
99+ 
100+                 self .buttons [x ][y ]["mines" ] =  nearby_mines 
98101
99102        #add mine and count at the end 
100103        self .label2  =  Label (frame , text  =  "Mines: " + str (self .mines ))
101-         self .label2 .grid (row  =  11 , column  =  0 , columnspan  =  5 )
104+         self .label2 .grid (row  =  SIZE_X + 1 , column  =  0 , columnspan  =  SIZE_Y / 2 )
102105
103106        self .label3  =  Label (frame , text  =  "Flags: " + str (self .flags ))
104-         self .label3 .grid (row  =  11 , column  =  4 , columnspan  =  5 )
107+         self .label3 .grid (row  =  SIZE_X + 1 , column  =  SIZE_Y / 2 - 1 , columnspan  =  SIZE_Y / 2 )
105108
106109    ## End of __init__ 
107110
108-     def  check_for_mines (self , key ):
111+     def  check_for_mines (self , x ,  y ):
109112        try :
110-             if  self .buttons [key ][1 ] ==  1 :
111-                 return  True 
113+             return  self .buttons [x ][y ]["isMine" ]
112114        except  KeyError :
113115            pass 
114116
115-     def  lclicked_wrapper (self , x ):
116-         return  lambda  Button : self .lclicked (self .buttons [x ])
117+     def  lclicked_wrapper (self , x ,  y ):
118+         return  lambda  Button : self .lclicked (self .buttons [x ][ y ] )
117119
118-     def  rclicked_wrapper (self , x ):
119-         return  lambda  Button : self .rclicked (self .buttons [x ])
120+     def  rclicked_wrapper (self , x ,  y ):
121+         return  lambda  Button : self .rclicked (self .buttons [x ][ y ] )
120122
121123    def  lclicked (self , button_data ):
122-         if  button_data [1 ] ==  1 : #if a mine 
123-             # show all mines and check for flags 
124-             for  key  in  self .buttons :
125-                 if  self .buttons [key ][1 ] !=  1  and  self .buttons [key ][2 ] ==  2 :
126-                     self .buttons [key ][0 ].config (image  =  self .tile_wrong )
127-                 if  self .buttons [key ][1 ] ==  1  and  self .buttons [key ][2 ] !=  2 :
128-                     self .buttons [key ][0 ].config (image  =  self .tile_mine )
124+         if  button_data ["isMine" ] ==  True :
129125            # end game 
130126            self .gameover ()
131127        else :
132-             #change image 
133-             if  button_data [5 ] ==  0 :
134-                 button_data [0 ].config (image  =  self .tile_clicked )
135-                 self .clear_empty_tiles (button_data [3 ])
128+             #  change image 
129+             if  button_data ["mines" ] ==  0 :
130+                 button_data ["widget" ].config (image  =  self .tiles [ "clicked" ] )
131+                 self .clear_empty_tiles (button_data ["id" ])
136132            else :
137-                 button_data [0 ].config (image  =  self .tile_no [ button_data [5 ]- 1 ])
133+                 button_data ["widget" ].config (image  =  self .tiles [ "numbers" ][ button_data ["mines" ]- 1 ])
138134            # if not already set as clicked, change state and count 
139-             if  button_data [2 ] !=  1 :
140-                 button_data [2 ] =  1 
135+             if  button_data ["state" ] !=  STATE_CLICKED :
136+                 button_data ["state" ] =  STATE_CLICKED 
141137                self .clicked  +=  1 
142138            if  self .clicked  ==  100  -  self .mines :
143139                self .victory ()
144140
145141    def  rclicked (self , button_data ):
146142        # if not clicked 
147-         if  button_data [2 ] ==  0 :
148-             button_data [0 ].config (image  =  self .tile_flag )
149-             button_data [2 ] =  2 
150-             button_data [0 ].unbind ('<Button-1>' )
143+         if  button_data ["state" ] ==  STATE_DEFAULT :
144+             button_data ["widget" ].config (image  =  self .tiles [ "flag" ] )
145+             button_data ["state" ] =  STATE_FLAGGED 
146+             button_data ["widget" ].unbind (BTN_CLICK )
151147            # if a mine 
152-             if  button_data [1 ] ==  1 :
148+             if  button_data ["isMine" ] ==  True :
153149                self .correct_flags  +=  1 
154150            self .flags  +=  1 
155151            self .update_flags ()
156152        # if flagged, unflag 
157-         elif  button_data [2 ] ==  2 :
158-             button_data [0 ].config (image  =  self .tile_plain )
159-             button_data [2 ] =  0 
160-             button_data [0 ].bind ('<Button-1>' , self .lclicked_wrapper (button_data [3 ]))
153+         elif  button_data ["state" ] ==  2 :
154+             button_data ["widget" ].config (image  =  self .tiles [ "plain" ] )
155+             button_data ["state" ] =  0 
156+             button_data ["widget" ].bind (BTN_CLICK , self .lclicked_wrapper (button_data ["coords" ][ "x" ],  button_data [ "coords" ][ "y" ]))
161157            # if a mine 
162-             if  button_data [1 ] ==  1 :
158+             if  button_data ["isMine" ] ==  True :
163159                self .correct_flags  -=  1 
164160            self .flags  -=  1 
165161            self .update_flags ()
166162
167-     def  check_tile (self , key , queue ):
163+     def  check_tile (self , x ,  y , queue ):
168164        try :
169-             if  self .buttons [key ][ 2 ]  ==  0 :
170-                 if  self .buttons [key ][ 5 ] ==  0 :
171-                     self .buttons [key ][ 0 ] .config (image  =  self .tile_clicked )
172-                     queue .append (key )
165+             if  self .buttons [x ][ y ][ "state" ]  ==  STATE_DEFAULT :
166+                 if  self .buttons [x ][ y ][ "mines" ] ==  0 :
167+                     self .buttons [x ][ y ][ "widget" ] .config (image  =  self .tiles [ "clicked" ] )
168+                     queue .append (self . buttons [ x ][ y ][ "id" ] )
173169                else :
174-                     self .buttons [key ][ 0 ] .config (image  =  self .tile_no [ self .buttons [key ][ 5 ]- 1 ])
175-                 self .buttons [key ][ 2 ]  =  1 
170+                     self .buttons [x ][ y ][ "widget" ] .config (image  =  self .tiles [ "numbers" ][ self .buttons [x ][ y ][ "mines" ]- 1 ])
171+                 self .buttons [x ][ y ][ "state" ]  =  STATE_CLICKED 
176172                self .clicked  +=  1 
177173        except  KeyError :
178174            pass 
179175
180-     def  clear_empty_tiles (self , main_key ):
181-         queue  =  deque ([main_key ])
176+     def  clear_empty_tiles (self , id ):
177+         queue  =  deque ([id ])
182178
183179        while  len (queue ) !=  0 :
184180            key  =  queue .popleft ()
185-             self .check_tile (key - 9 , queue )      #top right 
186-             self .check_tile (key - 10 , queue )     #top middle 
187-             self .check_tile (key - 11 , queue )     #top left 
188-             self .check_tile (key - 1 , queue )      #left 
189-             self .check_tile (key + 1 , queue )      #right 
190-             self .check_tile (key + 9 , queue )      #bottom right 
191-             self .check_tile (key + 10 , queue )     #bottom middle 
192-             self .check_tile (key + 11 , queue )     #bottom left 
193-     
181+             parts  =  key .split ("_" )
182+             source_x  =  int (parts [0 ])
183+             source_y  =  int (parts [1 ])
184+ 
185+             self .check_tile (source_x - 1 , source_y - 1 , queue )  #top right 
186+             self .check_tile (source_x - 1 , source_y , queue )    #top middle 
187+             self .check_tile (source_x - 1 , source_y + 1 , queue )  #top left 
188+             self .check_tile (source_x , source_y - 1 , queue )    #left 
189+             self .check_tile (source_x , source_y + 1 , queue )    #right 
190+             self .check_tile (source_x + 1 , source_y - 1 , queue )  #bottom right 
191+             self .check_tile (source_x + 1 , source_y , queue )    #bottom middle 
192+             self .check_tile (source_x + 1 , source_y + 1 , queue )  #bottom left 
193+ 
194+     def  reveal (self ):
195+         for  x  in  range (0 , SIZE_X ):
196+             for  y  in  range (0 , SIZE_Y ):
197+                 if  self .buttons [x ][y ]["isMine" ] ==  False  and  self .buttons [x ][y ]["state" ] ==  STATE_FLAGGED :
198+                     self .buttons [x ][y ]["widget" ].config (image  =  self .tiles ["wrong" ])
199+                 if  self .buttons [x ][y ]["isMine" ] ==  True  and  self .buttons [x ][y ]["state" ] !=  STATE_FLAGGED :
200+                     self .buttons [x ][y ]["widget" ].config (image  =  self .tiles ["mine" ])
201+         global  root 
202+         root .update ()
203+ 
194204    def  gameover (self ):
205+         self .reveal ()
195206        tkMessageBox .showinfo ("Game Over" , "You Lose!" )
196207        global  root 
197208        root .destroy ()
198209
199210    def  victory (self ):
211+         self .reveal ()
200212        tkMessageBox .showinfo ("Game Over" , "You Win!" )
201213        global  root 
202214        root .destroy ()
0 commit comments