Advertisement
eigenbom

MINESWEEPER BUT WHEN YOU SWEEP YOU HAVE TO PLAY MINESWEEPER

Feb 7th, 2017
429
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.26 KB | None | 0 0
  1. # MINESWEEPER BUT WHEN YOU SWEEP YOU HAVE TO PLAY MINESWEEPER
  2. # @eigenbom
  3. # Python 3 required
  4.  
  5. import tkinter as tk
  6. from functools import partial
  7. import random
  8.  
  9. root = tk.Tk()
  10. root.wm_title("MINESWEEPER BUT WHEN YOU SWEEP YOU HAVE TO PLAY MINESWEEPER")
  11. root.attributes("-toolwindow",1)
  12.  
  13. def center(win):
  14.     """
  15.    centers a tkinter window
  16.    :param win: the root or Toplevel window to center
  17.    Found on stackoverflow - 7/02/2017
  18.    """
  19.     win.update_idletasks()
  20.     width = win.winfo_width()
  21.     frm_width = win.winfo_rootx() - win.winfo_x()
  22.     win_width = width + 2 * frm_width
  23.     height = win.winfo_height()
  24.     titlebar_height = win.winfo_rooty() - win.winfo_y()
  25.     win_height = height + titlebar_height + frm_width
  26.     x = win.winfo_screenwidth() // 2 - win_width // 2
  27.     y = win.winfo_screenheight() // 2 - win_height // 2
  28.     win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
  29.     win.deiconify()
  30.  
  31. class GameState:
  32.     Play = 0
  33.     Dead = 1
  34.     Wait = 2
  35.  
  36. class Application(tk.Frame):
  37.     def __init__(self, master=None, parent=None, top_level=True, dimensions = 10):
  38.         super().__init__(master, height=dimensions*64, width=dimensions*64)
  39.         self.master = master
  40.         self.parent = parent
  41.         self.top_level = top_level
  42.         self.grid(row=0, column=0, sticky='nsew')
  43.         self.width = dimensions
  44.         self.height = dimensions
  45.         self.bombs = [[False]*self.width for i in range(self.height)]      
  46.         self.explored = [[False]*self.width for i in range(self.height)]
  47.         self.flagged = [[False]*self.width for i in range(self.height)]
  48.         self.widgets = [[None]*self.width for i in range(self.height)]                        
  49.         self.create_widgets()
  50.         self.state = None        
  51.         self.last_explored_cell = None
  52.         self.new_window = None
  53.         self.start_new_game()
  54.         if not top_level:
  55.             # mark one non-bomb as explored
  56.             non_bombs = []
  57.             for j in range(self.height):
  58.                 for i in range(self.width):
  59.                     if not self.bombs[j][i]:
  60.                         non_bombs.append((i,j))
  61.             assert len(non_bombs)
  62.             i, j = random.choice(non_bombs)
  63.             self.explored[j][i] = True
  64.             self.update_board()
  65.         center(self.master)
  66.  
  67.     def start_new_game(self):
  68.         if self.new_window:
  69.             self.new_window.destroy()
  70.             self.new_window = None
  71.  
  72.         self.state = GameState.Play
  73.         self.bombs = [[False]*self.width for i in range(self.height)]      
  74.         self.explored = [[False]*self.width for i in range(self.height)]
  75.         self.flagged = [[False]*self.width for i in range(self.height)]        
  76.         num_bombs = 0
  77.         for j in range(self.height):
  78.             for i in range(self.width):
  79.                 bomb = random.random() > 0.9
  80.                 num_bombs += 1 if bomb else 0
  81.                 self.bombs[j][i] = bomb
  82.         if num_bombs==self.width*self.height:
  83.             self.bombs[0][0] = False
  84.             num_bombs -= 1
  85.         if num_bombs==0:
  86.             self.bombs[0][0] = True
  87.             num_bombs = 1
  88.         self.update_board()
  89.        
  90.     def create_widgets(self):
  91.         for j in range(self.height):
  92.             tk.Grid.rowconfigure(self, j, weight=1)
  93.             for i in range(self.width):
  94.                 tk.Grid.columnconfigure(self, i, weight=1)                
  95.                 b = tk.Button(self, text=" ", command=partial(self.click, i,j), padx=2, pady=2, width = 2)                                
  96.                 b.bind("<Button-3>", partial(self.rclick,i,j))
  97.                 b.grid(row=j,column=i, sticky='nsew')
  98.                 self.widgets[j][i] = b
  99.    
  100.     def rclick(self, i, j, event):
  101.         if self.state == GameState.Play:
  102.             self.flagged[j][i] = not self.flagged[j][i]
  103.             self.update_board()
  104.  
  105.     def click(self, i, j):
  106.         if self.state == GameState.Play:
  107.             button = self.widgets[j][i]
  108.             bomb = self.bombs[j][i]
  109.             any_explored = False
  110.             for row in self.explored:
  111.                 for col in row:
  112.                     any_explored = any_explored or col
  113.             self.explored[j][i] = True
  114.             if bomb:
  115.                 # TODO: if haven't explored any then move the bomb
  116.                 self.update_board()      
  117.                 if self.top_level:
  118.                     self.state = GameState.Dead
  119.                     self.you_lose()
  120.                 else:
  121.                     self.state = GameState.Wait
  122.                     self.after(200, self.lost_next_level)
  123.                
  124.             else:
  125.                 # mark as explored, but first need to solve next level
  126.                 if self.width > 4:
  127.                     self.last_explored_cell = (i,j)
  128.                     self.flood_explore(self.last_explored_cell)                    
  129.                     self.state == GameState.Wait
  130.                     self.update_board()
  131.                     self.after(200, self.open_next_level)  
  132.                 else:
  133.                     self.last_explored_cell = (i,j)
  134.                     self.flood_explore(self.last_explored_cell)
  135.                     if self.check_win():
  136.                         if self.top_level:
  137.                             self.state = GameState.Dead
  138.                             self.you_win()
  139.                         else:
  140.                             self.state = GameState.Wait
  141.                             self.after(200, self.parent.won_next_level)
  142.         elif self.state == GameState.Dead:
  143.             self.start_new_game()        
  144.  
  145.     def neighbour_bombs(self, i, j):
  146.         nb = 0
  147.         for di in [-1,0,1]:
  148.             for dj in [-1,0,1]:
  149.                 ni, nj = i + di, j + dj
  150.                 nb += self.bombs[nj][ni] if (0<=ni<self.width and 0<=nj<self.height) else 0
  151.         return nb
  152.  
  153.     def update_board(self):
  154.         for j in range(self.height):
  155.             for i in range(self.width):
  156.                 button = self.widgets[j][i]
  157.                 bomb = self.bombs[j][i]
  158.                 if self.state == GameState.Dead:
  159.                     if bomb:
  160.                         button.config(text = "@")
  161.                     else:
  162.                         if self.explored[j][i]:
  163.                             count = self.neighbour_bombs(i, j)
  164.                             button.config(text = count or " ")
  165.                 else:
  166.                     if self.explored[j][i]:
  167.                         if bomb:
  168.                             button.config(text = "@")
  169.                         else:
  170.                             count = self.neighbour_bombs(i, j)                            
  171.                             button.config(text = count or " ")
  172.                         button.config(relief=tk.SUNKEN)
  173.                     elif self.flagged[j][i]:
  174.                         button.config(text = "F")
  175.                     else:
  176.                         button.config(text = " ")
  177.                         button.config(relief=tk.RAISED)
  178.        
  179.     def check_win(self):
  180.         # only bombs are unexplored
  181.         for j in range(self.height):
  182.             for i in range(self.width):
  183.                 explored = self.explored[j][i]
  184.                 bomb = self.bombs[j][i]
  185.                 if (explored and not bomb) or (bomb and not explored):
  186.                     pass
  187.                 else:
  188.                     return False
  189.         return True
  190.  
  191.     def open_next_level(self):
  192.         self.new_window = tk.Toplevel(self.master)
  193.         # self.new_window.transient(1)
  194.         self.new_window.attributes("-toolwindow",1)
  195.  
  196.         tk.Grid.rowconfigure(self.new_window, 0, weight=1)
  197.         tk.Grid.columnconfigure(self.new_window, 0, weight=1)
  198.         self.next_level = Application(master=self.new_window, parent=self, top_level=False, dimensions = self.width - 2)        
  199.         self.new_window.wm_protocol("WM_DELETE_WINDOW", partial(self.close_clicked, self.next_level))
  200.  
  201.         # self.next_level.pack()
  202.         self.new_window.focus_set()
  203.         self.new_window.transient(root)
  204.         self.new_window.grab_set()
  205.         root.wait_window(self.new_window)
  206.  
  207.     def close_clicked(self, t):
  208.         # propagate game over all the way up        
  209.         t.lost_next_level()
  210.  
  211.     def lost_next_level(self):
  212.         if self.top_level:
  213.             self.state = GameState.Dead
  214.             self.you_lose()
  215.         else:            
  216.             self.parent.new_window.destroy()
  217.             self.parent.new_window = None
  218.             self.parent.next_level = None
  219.             self.parent.lost_next_level()
  220.  
  221.     def won_next_level(self):
  222.         self.new_window.destroy()
  223.         self.new_window = None
  224.         self.next_level = None
  225.         self.state = GameState.Play
  226.         if self.last_explored_cell:
  227.             #self.flood_explore(self.last_explored_cell)        
  228.             if self.check_win():
  229.                 if self.top_level:
  230.                     self.state = GameState.Dead
  231.                     self.you_win()
  232.                 else:
  233.                     self.parent.won_next_level()
  234.  
  235.     def flood_explore(self, cell):
  236.         # floodto empty cells                
  237.         cells = [cell]
  238.         flooded = [cell]
  239.         while len(cells):
  240.             ci, cj = cells.pop()
  241.             flooded.append((ci,cj))
  242.             self.explored[cj][ci] = True
  243.             for di in [-1,0,1]:
  244.                 for dj in [-1,0,1]:
  245.                     if abs(di)+abs(dj)!=1: continue
  246.                     ni, nj = ci + di, cj + dj
  247.                     if 0<=ni<self.width and 0<=nj<self.height:
  248.                         if (ni,nj) not in flooded and not self.bombs[nj][ni]:
  249.                             count = self.neighbour_bombs(ni,nj)
  250.                             if count==0:
  251.                                 cells.append((ni,nj))
  252.                             else:
  253.                                 self.explored[nj][ni] = True
  254.         self.update_board()
  255.        
  256.  
  257.     def you_win(self):
  258.         self.state = GameState.Wait
  259.         def herewego():
  260.             toplevel = tk.Toplevel()
  261.             label1 = tk.Label(toplevel, text="YOU WIN!", height=3, width=8)
  262.             label1.pack()
  263.             toplevel.focus_set()
  264.             toplevel.transient(root)
  265.             toplevel.grab_set()
  266.             center(toplevel)            
  267.             self.state = GameState.Dead
  268.             self.new_window = toplevel        
  269.             toplevel.wm_protocol("WM_DELETE_WINDOW", self.start_new_game)
  270.             root.wait_window(toplevel)
  271.         self.after(500, herewego)
  272.        
  273.     def you_lose(self):
  274.         self.state = GameState.Wait
  275.         def herewego():
  276.             toplevel = tk.Toplevel()
  277.             label1 = tk.Label(toplevel, text="YOU LOSE!", height=3, width=8)
  278.             label1.pack()
  279.             toplevel.focus_set()
  280.             toplevel.transient(root)
  281.             toplevel.grab_set()
  282.             center(toplevel)            
  283.             self.state = GameState.Dead
  284.             self.new_window = toplevel
  285.             toplevel.wm_protocol("WM_DELETE_WINDOW", self.start_new_game)
  286.             root.wait_window(toplevel)
  287.         self.after(500, herewego)
  288.  
  289. tk.Grid.rowconfigure(root, 0, weight=1)
  290. tk.Grid.columnconfigure(root, 0, weight=1)
  291. app = Application(master=root, top_level=True)
  292. app.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement