«Спёр» – это компьютерная игра-головоломка, в которой необходимо найти все мины на игровом поле. В поиске мин помогают числовые подсказки.

Автором игры «Minesweeper» (Сапёр) является Курт Джонсон, первоначально разрабатывавший его для OS/2. По словам Джонсона, идея игры была позаимствована. Затем игра была несколько дополнена и переписана Робертом Доннером для ОС Windows. В 1990 году она была опубликована в составе набора игр Microsoft Entertainment Pack 1, а с 1992-го года по 2009 год включалась в состав операционной системы Windows. Возможным предшественником Сапёра называется игра «Mined-Out» , написанная Яном Эндрю (Incentive Software) в 1983 году для компьютера ZX Spectrum.

Рис. 1. Игра Minesweeper 92

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)
column = 10                          # столбцы
row = 10                             # строки
btn = []
mines = row * column // 6
playground = [1] * mines + [0] * (row * column - mines)      # виртуальное игровое поле
shuffle(playground)
game_over = False


def play(n):                        # функция обработчик нажатия на кнопку
    global game_over
    if game_over: return
    btn[n].config(fg='black')
    if playground[n] == 1:
        btn[n].config(text='M')
        game_over = True
        tk.title("Game Over")
        return

    btn[n].config(text=playground[n])


def flag(n):
    global game_over
    if game_over: return
    if btn[n].cget('text') == ' ':
        btn[n].config(text='F', fg='red')
    elif btn[n].cget('text') == 'F':
        btn[n].config(text=' ')

tk = Tk()
tk.title("Сапёр")

for i in range(row):
    f = Frame()                     # Фрейм
    f.pack(expand=YES, fill=BOTH)   # Вывод фрейма на экран
    for j in range(column):
        n = i * column + j
        btn += [Button(f)]
        btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[n].config(width=3, height=2, font=('times', 10, 'bold'))
        btn[n].config(text=' ')
        btn[n].config(command=lambda n=n: play(n))
        btn[n].bind("<Button-3>", lambda event, k=n: flag(k))

mainloop()                          # главный цикл программы

Лист. 1.

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)
column = 10                         # столбцы
row = 10                            # строки
btn = []                            # список кнопок
mines = row * column // 8           # количество мин
playground = [1] * mines + [0] * (row * column - mines)      # виртуальное игровое поле
shuffle(playground)
game_over = False                   # признак окончания игры


def play(n):                        # функция обработчик нажатия на кнопку
    global game_over
    if game_over: return            # если game_over == True, игра окончена
    btn[n].config(fg='black')
    if playground[n] == 1:          # если попали на мину
        btn[n].config(text='M')
        game_over = True
        tk.title("Game Over")
        return

    m = 0                           # подсчёт мин у соседей.
    for i in (n-column, n, n+column):
        for j in (-1, 0, 1):
            if i+j >= 0 and i+j < row*column  and i//column == (i+j)//column:
                m += playground[i+j]
    btn[n].config(text = m)


def flag(n):                        # Функция установки/снятия флажка
    global game_over
    if game_over: return
    if btn[n].cget('text') == ' ':
        btn[n].config(text='F', fg='red')
    elif btn[n].cget('text') == 'F':
        btn[n].config(text=' ')

tk = Tk()                           # главное окно программы
tk.title("Сапёр")

for i in range(row):
    f = Frame()                     # Фрейм
    f.pack(expand=YES, fill=BOTH)   # Вывод фрейма на экран
    for j in range(column):
        n = i * column + j
        btn += [Button(f)]
        btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[n].config(width=3, height=2, font=('times', 10, 'bold'))
        btn[n].config(text=' ')
        btn[n].config(command=lambda n=n: play(n))
        btn[n].bind("<Button-3>", lambda event, k=n: flag(k))

mainloop()                          # главный цикл программы

Лист. 2.

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)
column = 10                         # столбцы
row = 10                            # строки
btn = []                            # список кнопок
mines = row * column // 5           # количество мин
playground = [1] * mines + [0] * (row * column - mines)      # виртуальное игровое поле
shuffle(playground)
game_over = False                   # признак окончания игры
first_move = True                   # первый ход


def roomie(n):                      # поиск адресов законных соседей
    R = []
    for i in (n-column, n, n+column):
        for j in (-1, 0, 1):
            if i+j >= 0 and i+j < row*column  and i//column == (i+j)//column:
                R += [i+j]
    return R                        # список адресов соседних кнопок
                

def play(n):                        # функция обработчик нажатия на кнопку
    global game_over, first_move
    if first_move:                  # если певый ход
        first_move = False
        playground[n] = 0           # на мину не попадаем
    if game_over: return            # если game_over == True, игра окончена
    btn[n].config(fg='black')
    if playground[n] == 1:          # если попали на мину
        btn[n].config(text='M')
        game_over = True
        tk.title("Game Over")
        return

    m = 0                           # подсчёт мин у соседей.
    for i in roomie(n):
        m += playground[i]
    btn[n].config(text = m)
    if m == 0:                      # если по соседству мин нет
        btn[n].config(state="disabled")
        for i in roomie(n):         # обход соседей
            if btn[i].cget('text') == ' ':      # если кнопка ещё не проверялась
                play(i)             # рекурсия


def flag(n):                        # Функция установки/снятия флажка
    global game_over
    if game_over: return
    if btn[n].cget('text') == ' ':
        btn[n].config(text='F', fg='red')
    elif btn[n].cget('text') == 'F':
        btn[n].config(text=' ')


tk = Tk()                           # главное окно программы
tk.title("Сапёр")

for i in range(row):
    f = Frame()                     # Фрейм
    f.pack(expand=YES, fill=BOTH)   # Вывод фрейма на экран
    for j in range(column):
        n = i * column + j
        btn += [Button(f)]
        btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[n].config(width=3, height=2, font=('times', 10, 'bold'))
        btn[n].config(text=' ')
        btn[n].config(command=lambda n=n: play(n))
        btn[n].bind("<Button-3>", lambda event, k=n: flag(k))

mainloop()                          # главный цикл программы

Лист. 3.

#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width:$

# Minesweeper 24
# This is my version of the game, known as Minesweeper.
#
# Created on december 26, 2024.
# Author of this program code : Diorditsa A.
# I am grateful to Maxim Dubinin for sharing some of his ideas on how to implement this game
#
# minesweeper24.py is distributed in the hope that it will be useful, but
# WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
# MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See. See the GNU General Public License for more information.
# You can get a copy of the GNU General Public License
# by link http://www.gnu.org/licenses/

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)
column = 10                         # столбцы
row = 10                            # строки
btn = []                            # список кнопок
mines = row * column // 5           # количество мин
playground = [1] * mines + [0] * (row * column - mines)      # виртуальное игровое поле
shuffle(playground)
game_over = False                   # признак окончания игры
first_move = True                   # первый ход


def roomie(n):                      # поиск адресов законных соседей
    R = []
    for i in (n-column, n, n+column):
        for j in (-1, 0, 1):
            if i+j >= 0 and i+j < row*column  and i//column == (i+j)//column:
                R += [i+j]
    return R                        # список адресов соседних кнопок
                

def play(n):                        # функция обработчик нажатия на кнопку
    global game_over, first_move
    if first_move:                  # если певый ход
        first_move = False
        playground[n] = 0           # на мину не попадаем
    if game_over: return            # если game_over == True, игра окончена
    if btn[n].cget('text') != ' ':  # сюда уже ходили
        return                      # и за одно, граница рекурсии
    btn[n].config(fg='black')
    if playground[n] == 1:          # если попали на мину
        btn[n].config(text='M', bg='red')
        game_over = True
        tk.title("Game Over You Rip")
        for i in range(row*column): # открываем все мины
            if playground[i] == 1:
                if i != n:
                    if btn[i].cget('text') != 'F':
                        btn[i].config(text='M', bg='yellow')
                    else:
                        btn[i].config(bg='yellow')
        return

    m = 0                           # подсчёт мин у соседей.
    for i in roomie(n):
        m += playground[i]
    btn[n].config(text = m)
    if m == 0:                      # если по соседству мин нет
        btn[n].config(state="disabled")
        for i in roomie(n):         # обход соседей
            play(i)                 # рекурсия


def flag(n):                        # Функция установки/снятия флажка
    global game_over
    if game_over: return
    if btn[n].cget('text') == ' ':
        btn[n].config(text='F', fg='red')
    elif btn[n].cget('text') == 'F':
        btn[n].config(text=' ')
    you_win = True                  # проверяем состояние победы
    for i in range(row*column):
        if playground[i] == 1:      # если под кнопкой мина
            if btn[i].cget('text') != 'F':  # если над миной нет флага
                you_win = False
                break
        if btn[i].cget('text') == 'F':  # если на кнопке флаг
            if playground[i] != 1:      # если под флагом мины нет
                you_win = False
                break
    if you_win == True:             # Победа
        tk.title("Game Over You Win")
        game_over = True


def new_game():                     # новая игра
    global playground, game_over, first_move
    playground = [1] * mines + [0] * (row * column - mines)      # виртуальное игровое поле
    shuffle(playground)
    game_over = False               # признак окончания игры
    first_move = True               # первый ход
    for i in range(row*column):
        btn[i].config(text=' ', fg='black', state="normal")
        btn[i].config(bg=btn_bg)
        tk.title("Сапёр")


tk = Tk()                           # главное окно программы
tk.title("Сапёр")

ng = Button(text='New Game', command=new_game)  # кнопка "Новая игра"
ng.pack(expand=YES, side=TOP)
btn_bg = ng.cget('bg')              # цвет кнопки по умолчанию

for i in range(row):
    f = Frame()                     # Фрейм
    f.pack(expand=YES, fill=BOTH)   # Вывод фрейма на экран
    for j in range(column):
        n = i * column + j
        btn += [Button(f)]
        btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[n].config(width=3, height=2, font=('times', 10, 'bold'))
        btn[n].config(text=' ')
        btn[n].config(command=lambda n=n: play(n))
        btn[n].bind("<Button-3>", lambda event, k=n: flag(k))

mainloop()                          # главный цикл программы

Лист. 4. Игра Сапёр 24.

Рис. 2. Игра Minesweeper 24 на Python.