Advertisement
AlfonsoPEREZ

Minesweeper

May 3rd, 2020
508
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.30 KB | None | 0 0
  1. # MINESWEEPER
  2. import tkinter as tk
  3. from tkinter import ttk
  4. import random
  5. import copy
  6.  
  7.  
  8. def get_dimensions():
  9.     """Function will get user input for dimension (x, y) of game grid and mine count for game"""
  10.  
  11.     x = int(input('How many columns(1-20): '))
  12.     while x < 1 or x > 20:
  13.         x = int(input('Invalid try again: '))
  14.  
  15.     y = int(input('How many rows(1-20): '))
  16.     while y < 1 or y > 20:
  17.         x = int(input('Invalid try again: '))
  18.  
  19.     mines = int(input('How many Mines: '))
  20.     while mines < 1 or mines > x * y:
  21.         x = int(input('Invalid try again: '))
  22.  
  23.     return x, y, mines
  24.  
  25.  
  26. def init_grid(x_dim, y_dim):
  27.     """Function will create the basic grid"""
  28.  
  29.     the_grid = []
  30.  
  31.     for i in range(y_dim):  # This formula will (most of the time) place the grid in the middle
  32.         for ii in range(x_dim):
  33.             the_grid.append(create_button(ii / 40 + 0.3, i / 20 + 0.1))
  34.  
  35.     return the_grid
  36.  
  37.  
  38. def init_mines(grid, mines_num):
  39.     """Randomized mine placement"""
  40.  
  41.     mines = []
  42.     copy_grid = copy.copy(grid)
  43.  
  44.     for i in range(mines_num):
  45.         mine = random.choice(copy_grid)
  46.         copy_grid.remove(mine)
  47.  
  48.         mine_config(mine)  # Sets default mine click functionality
  49.         mines.append(mine)
  50.  
  51.     return mines
  52.  
  53.  
  54. def init_spaces(grid, mine_lst, x_dime, y_dime):
  55.     """For each space in the grid find amount of adjacent mines"""
  56.  
  57.     nums = []
  58.     total = x_dime * y_dime
  59.     corn_right = x_dime + 1
  60.     corn_left = x_dime - 1
  61.  
  62.     up_side = list(range(x_dime))
  63.     down_side = list(range(total - x_dime, total))
  64.     left_side = list(range(0, total - corn_right, x_dime))
  65.     right_side = list(range(corn_left, total, x_dime))
  66.  
  67.     for space in grid:
  68.         if space in mine_lst:
  69.             nums.append('M')
  70.             continue
  71.  
  72.         else:
  73.             ind = grid.index(space)
  74.             num_adj_mine = 0
  75.  
  76.             if ind == 0:
  77.                 for near_space in [grid[ind + 1], grid[ind + x_dime], grid[ind + corn_right]]:
  78.                     if near_space in mine_lst:
  79.                         num_adj_mine += 1
  80.  
  81.             elif ind == x_dime - 1:
  82.                 for near_space in [grid[ind - 1], grid[ind + x_dime], grid[ind + corn_left]]:
  83.                     if near_space in mine_lst:
  84.                         num_adj_mine += 1
  85.  
  86.             elif ind == total - x_dime:
  87.                 for near_space in [grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left]]:
  88.                     if near_space in mine_lst:
  89.                         num_adj_mine += 1
  90.  
  91.             elif ind == total - 1:
  92.                 for near_space in [grid[ind - 1], grid[ind - x_dime], grid[ind - corn_right]]:
  93.                     if near_space in mine_lst:
  94.                         num_adj_mine += 1
  95.  
  96.             elif ind in up_side:
  97.                 for near_space in [grid[ind - 1], grid[ind + 1], grid[ind + x_dime], grid[ind + corn_left],
  98.                                    grid[ind + corn_right]]:
  99.                     if near_space in mine_lst:
  100.                         num_adj_mine += 1
  101.  
  102.             elif ind in down_side:
  103.                 for near_space in [grid[ind - 1], grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left],
  104.                                    grid[ind - corn_right]]:
  105.                     if near_space in mine_lst:
  106.                         num_adj_mine += 1
  107.  
  108.             elif ind in left_side:
  109.                 for near_space in [grid[ind + x_dime], grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left],
  110.                                    grid[ind + corn_right]]:
  111.                     if near_space in mine_lst:
  112.                         num_adj_mine += 1
  113.  
  114.             elif ind in right_side:
  115.                 for near_space in [grid[ind + x_dime], grid[ind - 1], grid[ind - x_dime], grid[ind + corn_left],
  116.                                    grid[ind - corn_right]]:
  117.                     if near_space in mine_lst:
  118.                         num_adj_mine += 1
  119.  
  120.             else:
  121.                 for near_space in [grid[ind + 1], grid[ind - 1], grid[ind + x_dime], grid[ind + corn_right],
  122.                                    grid[ind + corn_left],
  123.                                    grid[ind - corn_right], grid[ind - x_dime], grid[ind - corn_left]]:
  124.                     if near_space in mine_lst:
  125.                         num_adj_mine += 1
  126.  
  127.             if num_adj_mine == 0:
  128.                 nums.append(' ')
  129.             else:
  130.                 nums.append(num_adj_mine)
  131.  
  132.     return nums  # List includes num of adjacent mines ' ' if none 'M' if space in mine
  133.  
  134.  
  135. def adj_blank_spaces(grid, x_dime, y_dime, space):
  136.     """When empty block is clicked all blocks around will sink (relief)"""
  137.  
  138.     total = x_dime * y_dime
  139.     corn_right = x_dime + 1
  140.     corn_left = x_dime - 1
  141.  
  142.     up_side = list(range(x_dime))
  143.     down_side = list(range(total - x_dime, total))
  144.     left_side = list(range(0, total - corn_right, x_dime))
  145.     right_side = list(range(corn_left, total, x_dime))
  146.  
  147.     ind = grid.index(space)
  148.     if ind == 0:  # Top left corner
  149.         for near_space in [grid[ind + 1], grid[ind + x_dime], grid[ind + corn_right], grid[ind]]:
  150.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  151.                 near_space['relief'] = 'sunken'
  152.                 space_left('', near_space)  # As if being left clicked
  153.  
  154.     elif ind == x_dime - 1:  # Top right corner
  155.         for near_space in [grid[ind - 1], grid[ind + x_dime], grid[ind + corn_left], grid[ind]]:
  156.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  157.                 near_space['relief'] = 'sunken'
  158.                 space_left('', near_space)
  159.  
  160.     elif ind == total - x_dime:  # Bottom left corner
  161.         for near_space in [grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left], grid[ind]]:
  162.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  163.                 near_space['relief'] = 'sunken'
  164.                 space_left('', near_space)
  165.  
  166.     elif ind == total - 1:  # Bottom right corner
  167.         for near_space in [grid[ind - 1], grid[ind - x_dime], grid[ind - corn_right]]:
  168.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  169.                 near_space['relief'] = 'sunken'
  170.                 space_left('', near_space)
  171.  
  172.     elif ind in up_side:
  173.         for near_space in [grid[ind - 1], grid[ind + 1], grid[ind + x_dime], grid[ind + corn_left],
  174.                            grid[ind + corn_right]]:
  175.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  176.                 near_space['relief'] = 'sunken'
  177.                 space_left('', near_space)
  178.  
  179.     elif ind in down_side:
  180.         for near_space in [grid[ind - 1], grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left],
  181.                            grid[ind - corn_right]]:
  182.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  183.                 near_space['relief'] = 'sunken'
  184.                 space_left('', near_space)
  185.  
  186.     elif ind in left_side:
  187.         for near_space in [grid[ind + x_dime], grid[ind + 1], grid[ind - x_dime], grid[ind - corn_left],
  188.                            grid[ind + corn_right]]:
  189.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  190.                 near_space['relief'] = 'sunken'
  191.                 space_left('', near_space)
  192.  
  193.     elif ind in right_side:
  194.         for near_space in [grid[ind + x_dime], grid[ind - 1], grid[ind - x_dime], grid[ind + corn_left],
  195.                            grid[ind - corn_right]]:
  196.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  197.                 near_space['relief'] = 'sunken'
  198.                 space_left('', near_space)
  199.  
  200.     else:  # All middle blocks
  201.         for near_space in [grid[ind + 1], grid[ind - 1], grid[ind + x_dime], grid[ind + corn_right],
  202.                            grid[ind + corn_left],
  203.                            grid[ind - corn_right], grid[ind - x_dime], grid[ind - corn_left]]:
  204.             if near_space['text'] != 'M' and near_space['relief'] != 'sunken':
  205.                 near_space['relief'] = 'sunken'
  206.                 space_left('', near_space)
  207.  
  208.  
  209. def create_button(relx, rely):
  210.     """First component of flag system and general button creator"""
  211.  
  212.     butt = tk.Button(game, height=2, width=4)
  213.     butt.place(relx=relx, rely=rely)
  214.  
  215.     butt.bind('<ButtonRelease-1>', lambda event_, arg=butt: space_left(event_, arg))  # Left click - reveal space
  216.     butt.bind('<ButtonRelease-3>', lambda event_, arg=butt: space_flagged(event_, arg))  # Right click - flag space
  217.  
  218.     return butt
  219.  
  220.  
  221. def space_left(event, space):
  222.     """Happens when a regular not flagged (not mine) is left clicked"""
  223.  
  224.     print(event)
  225.     num = fin_grid[grid_lst.index(space)]  # Gets the number of the space from init_spaces function
  226.     space['text'] = num
  227.  
  228.     if num == 1:  # Sets color based on number
  229.         space['fg'] = 'green'
  230.     elif num == 2:
  231.         space['fg'] = 'red'
  232.     elif num == 4:
  233.         space['fg'] = 'yellow'
  234.     elif num == 5:
  235.         space['fg'] = 'orange'
  236.     elif num == 6:
  237.         space['fg'] = 'blue'
  238.     elif num == 7:
  239.         space['fg'] = 'purple'
  240.     elif num == 8:
  241.         space['fg'] = 'brown'
  242.  
  243.     game.after(1, lambda the_space: space.configure(relief='sunken'), space)  # Sinks button
  244.     space.bind('<ButtonRelease-1>', '')  # Now button dormant
  245.     space.bind('<ButtonRelease-3>', '')
  246.  
  247.     if num == ' ':  # If the button has no adjacent mines
  248.         adj_blank_spaces(grid_lst, dims[0], dims[1], space)
  249.  
  250.     if check_win():
  251.         win = tk.Label(game, text='YOU WIN!')
  252.         win.place(relx=0.1, rely=0.2)
  253.  
  254.         end_game()  # - Disables all grid buttons
  255.         new_game(win)  # - Asks user if he wants to play again
  256.  
  257.  
  258. def space_flagged(event, space):
  259.     """Enables regular spaces being flagged"""
  260.  
  261.     print(event)
  262.     space['text'] = '⛳'
  263.  
  264.     space.bind('<ButtonRelease-1>', '')  # Once flagged can't left click
  265.     space.bind('<ButtonRelease-3>', lambda event_, arg=space: space_unflagged(event_, arg))  # Right click to unflag
  266.  
  267.  
  268. def space_unflagged(event, space):
  269.     """To unflag a regular space"""
  270.  
  271.     print(event)
  272.     space['text'] = ''
  273.  
  274.     space.bind('<ButtonRelease-1>',
  275.                lambda _event, arg=space: space_left(_event, arg))  # Set button functionality back to default
  276.     space.bind('<ButtonRelease-3>', lambda _event, arg=space: space_flagged(_event, arg))
  277.  
  278.  
  279. def mine_config(a_mine):
  280.     """Default mine functionality"""
  281.  
  282.     a_mine['text'] = ''
  283.  
  284.     a_mine.bind('<ButtonRelease-1>', mine_left)  # All mines appear and game ends when left clicked
  285.     a_mine.bind('<ButtonRelease-3>', lambda event, arg=a_mine: mine_flagged(event, arg))  # Right click to flag
  286.  
  287.  
  288. def mine_left(event):
  289.     """Game fail scenario"""
  290.  
  291.     print(event)
  292.  
  293.     for button in mines_lst:
  294.         button.configure(text='M', bg='red')  # All mines appear
  295.  
  296.     lose = tk.Label(game, text='YOU LOSE!')
  297.     lose.place(relx=0.1, rely=0.2)
  298.  
  299.     end_game()  # Disables all gris buttons
  300.     new_game(lose)  # New game option
  301.  
  302.  
  303. def mine_flagged(event, the_mine):
  304.     """Triggers when mine is right clicked to flag"""
  305.  
  306.     print(event)
  307.     the_mine['text'] = '⛳'
  308.  
  309.     the_mine.bind('<ButtonRelease-1>', '')  # Disable left click
  310.     the_mine.bind('<ButtonRelease-3>',
  311.                   lambda event_, arg=the_mine: mine_unflagged(event_, arg))  # Right click to unflag
  312.  
  313.  
  314. def mine_unflagged(event, mine):
  315.     """Right click again to unflag"""
  316.  
  317.     print(event)
  318.     mine['text'] = ''
  319.  
  320.     mine.bind('<ButtonRelease-1>', mine_left)  # Set default functionality
  321.     mine.bind('<ButtonRelease-3>', lambda _event, arg=mine: mine_flagged(_event, arg))
  322.  
  323.  
  324. def check_win():
  325.     """Checks to see if player has run"""
  326.  
  327.     for space in grid_lst:
  328.         if space in mines_lst or space['relief'] == 'sunken':  # If all non mine blocks are sunken
  329.             continue
  330.         else:
  331.             return False
  332.  
  333.     return True
  334.  
  335.  
  336. def end_game():
  337.     """Disables all grid buttons"""
  338.  
  339.     for button in grid_lst:
  340.         button.bind('<ButtonRelease-1>', '')
  341.         button.bind('<ButtonRelease-3>', '')
  342.  
  343.  
  344. def new_game(lab):
  345.     """Sets up buttons for new game option"""
  346.  
  347.     question = ttk.Button(game, text='Do you want to play again?', style='Fun.TButton', width=25)
  348.     question.place(relx=0.03, rely=0.3)
  349.  
  350.     yres = tk.Button(game, width=5, height=1, text='YES', command=lambda: yes_res(lab, question, yres, nres))
  351.     yres.place(relx=0.03, rely=0.35)  # If yes is clicked game reset and randomized with same dimensions
  352.  
  353.     nres = tk.Button(game, width=5, height=1, text='NO', command=lambda: game.quit())
  354.     nres.place(relx=0.1, rely=0.35)  # If no window closes
  355.  
  356.  
  357. def yes_res(label, ques, yes_resp, no_resp):
  358.     """Clicked yes to new game"""
  359.  
  360.     global grid_lst, mines_lst, fin_grid
  361.  
  362.     label.destroy()  # Reset all labels
  363.     ques.destroy()
  364.     yes_resp.destroy()
  365.     no_resp.destroy()
  366.  
  367.     grid_lst = init_grid(dims[0], dims[1])  # Reset all grids
  368.     mines_lst = init_mines(grid_lst, dims[2])
  369.     fin_grid = init_spaces(grid_lst, mines_lst, dims[0], dims[1])
  370.  
  371.  
  372. game = tk.Tk()
  373. game.geometry('1920x1080')
  374. game.title('Mine Sweeper')
  375.  
  376. dims = get_dimensions()
  377. grid_lst = init_grid(dims[0], dims[1])
  378. mines_lst = init_mines(grid_lst, dims[2])
  379. fin_grid = init_spaces(grid_lst, mines_lst, dims[0], dims[1])
  380.  
  381. game.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement