Форум сайта python.su
поиграйте в игрульку, сделайте замечания по коду,что в нем плохо, а что хорошо, и почему
P.S игра писалась ради структуры кода,в целях обучения,а не самой игры,
import random as rd import tkinter as tk import tkinter.messagebox as mb class MineField: def __init__(self, size, count_mines): """ создает матрицу с минами,и числом мин вокруг каждой ячейки :param size:размер матрицы :param count_mines: количество мин """ self.coords_mines = self.random_coords(0, size, count_mines) self.matrix = self.get_minefield_matrix(size, self.coords_mines) def random_coords(self, begin, end, count): coords = set() while len(coords) != count: coords.add((rd.randint(begin, end - 1), rd.randint(begin, end - 1))) return coords def get_minefield_matrix(self, size, coords_mines): m = [[0 for _ in range(size)] for _ in range(size)] for r, c in coords_mines: m[r][c] = 'm' out = self.calc_target_around_cell(m, 'm') return out def calc_target_around_cell(self, matrix, target): size = len(matrix) for x in range(size): for y in range(size): for i in range(x - 1, x + 2): if size > i >= 0: for j in range(y - 1, y + 2): if size > j >= 0: if matrix[i][j] == target: if matrix[x][y] == target: continue else: matrix[x][y] += 1 return matrix class Button(tk.Button): def __init__(self, r, c, f1, f2, f3): """ создает кнопку tkinter :param r: координата строки в матрице :param c: координата колонки в матрице :param f1: функция для лкм :param f2: функция для скм :param f3: функция для пкм """ self.default_option = { 'text': '', 'width': 3, 'font': 'Arial 10', 'foreground': 'yellow', 'state': 'normal', 'bg': 'SystemButtonFace', 'relief': 'raised' } super().__init__(**self.default_option) self.coord = r, c self.state = '' self.bind('<ButtonRelease - 1>', lambda e: f1(*self.coord)) self.bind('<ButtonRelease - 3>', lambda e: f2(*self.coord)) self.bind('<ButtonRelease - 2>', lambda e: f3(*self.coord)) self.grid(row=r, column=c) def set_color(self, color): self.config(bg=color) def set_text(self, text): self.config(text=text) def set_fg(self, color): self.config(fg=color) def set_default(self): self.config(self.default_option) class MineClearance: def __init__(self, master, size, mines_count): """ контроллер игры сапер :param master: окно для игры :param size: размер :param mines_count:количество мин """ self.size = size self.mines_count = mines_count self.mf = MineField(self.size, self.mines_count) self.btns = self.create_btn_matrix(self.size) self.flags = self.mines_count self.mines_clear = 0 self.master = master self.master.title(f'flags {self.flags}|mines {self.mines_count}') def create_btn_matrix(self, size): matrix = [[Button(r, c, self.open, self.flag, self.multi_open) for c in range(size)] for r in range(size)] return matrix # левая кнопка мыши def open(self, r, c): btn = self.btns[r][c] value = self.mf.matrix[r][c] if btn.state == 'open' or btn.state == 'flag': return if btn.state == 'ask': btn.config(btn.default_option) btn.state = '' btn.state = 'open' if value == 'm': btn.set_color('red') self.game_over() return True elif value == 0: btn.set_color('green') return self.multi_open(r, c) else: btn.set_color('brown') btn.set_text(value) # средняя кнопка мыши def multi_open(self, r, c): for i in range(r - 1, r + 2): if 0 <= i < self.size: for j in range(c - 1, c + 2): if 0 <= j < self.size: if self.open(i, j): return # правая кнопка мыши def flag(self, r, c): btn = self.btns[r][c] value = self.mf.matrix[r][c] if btn.state == 'open': return if btn.state == 'ask': btn.config(btn.default_option) btn.state = '' elif btn.state != 'flag' and self.flags > 0: btn.set_color('yellow') btn.state = 'flag' self.flags -= 1 if value == 'm': self.mines_clear += 1 if self.mines_clear == self.mines_count: self.win() return elif btn.state == 'flag': btn.config(btn.default_option) btn.state = 'ask' btn.set_text('?') btn.set_fg('black') self.flags += 1 if value == 'm': self.mines_clear -= 1 self.master.title(f'flags {self.flags}|mines {self.mines_count}') def win(self): mb.showinfo("Этап пройден", "Вы выйграли") self.__init__(self.master, self.size, self.mines_count + 1) def game_over(self): mb.showinfo("Взрыв", "Вы проиграли") self.__init__(self.master, self.size, self.mines_count) def main(): root = tk.Tk() MineClearance(root, 10, 15) mb.showinfo("Сапер", """ Разминируйте поле, число в ячейке подскажет вам сколько мин вокруг клетки, чтобы открыть клетку левая кнопка мыши устанавливайте флаг на мину правой кнопкой мыши открыть клетки вокруг клетки - средняя кнопка мыши Будте внимательны,прислушивайтесь к интуиции,первые шаги самые опасные """ ) root.mainloop() if __name__ == '__main__': main()
Офлайн
Не очень похоже на сапёр. Видимо, нарушена логика. Так что будем считать, что это код нипойми чего.
В коде встречается несколько моментов где много уровней вложенности. Нужно делать уровни вложенности не более трёх. Самый идеальный уровень вложенности - это ноль, но бывает, что ноль уровней вложенности сделать невозможно, и тогда можно добавить один уровень вложенности. Если же у тебя появляется четвёртый уровень вложенности, то с кодом что-то не то.
Это идеально
оператор
оператор
оператор
оператор
оператор
оператор
оператор
оператор
оператор
оператор
оператор
Отредактировано py.user.next (Март 7, 2021 06:10:11)
Офлайн
ну если в целях (само)обучения то посмотрите как тут http://itnotesblog.ru/note.php?id=10
реализовано и сравните
[code python][/code]
Отредактировано PEHDOM (Март 7, 2021 10:17:03)
Офлайн
py.user.nextЧто именно? У меня (можно сказать) работает.
Не очень похоже на сапёр. Видимо, нарушена логика.
class Button(tk.Button):
class Button(tk.Label):
Офлайн
ramihttps://imageup.ru/img175/3714392/minesweeper.png.htmlpy.user.nextЧто именно? У меня (можно сказать) работает.
Не очень похоже на сапёр. Видимо, нарушена логика.
Отредактировано py.user.next (Март 7, 2021 11:59:16)
Офлайн
py.user.nextУ меня флаги вообще не устанавливаются (или я не знаю как). Игра не завершается.
И ещё там есть такое, что флаги нужно все проставить, даже когда все клетки без мин открыты. Без этого игра ждёт, когда поставишь последний флаг.
чтобы открыть клетку левая кнопка мыши
устанавливайте флаг на мину правой кнопкой мыши
открыть клетки вокруг клетки - средняя кнопка мыши
Офлайн
ramiПравой кнопкой мыши у меня ставятся жёлтые флаги.
У меня флаги вообще не устанавливаются (или я не знаю как).
Офлайн
py.user.nextТипа такого пишут программы? или так слишком заморочно, и отправка сообщений понимается мною буквально
Все классы должны описывать отдельные самостоятельные объекты, которые потом будут создаваться и взаимодействовать друг с другом через отправку сообщений друг другу.
import time class Net: """ это класс Сеть,в которой общаются объекты ее функции - это законы по которым они общаются между собой """ def process(self, data): """ обработка данных объектом :param data: входящие данные :return: обработанные данные, ответ на сообщение """ print(f'данные получены в родительский класс,\n'\ f'переопределите эту функцию в дочернем классе, куда должны придти данные>>>\n{data}') return def event_handler(self, sender, recipient, data): """ обработчик события(кто-то отправил сообщение) :param sender: получатель ответа на сообщение(по умолчанию отправитель) :param recipient: получатель :param data: данные :return: """ new_data = recipient.process(data) if new_data is not None: return sender.send_message(recipient, sender, new_data) def send_message(self, sender, recipient, data): """ отправка сообщения объектом :param sender: получатель ответа на сообщение(по умолчанию отправитель) :param recipient: получатель сообщения :param data: данные :return: """ return recipient.event_handler(sender, recipient, data) class A(Net): def process(self, data): time.sleep(1) if data == 'привет': print('A: привет') return data elif data == 'давай дружить': print('A: сложи 2+2') return 2,2 elif data == 4: print(f'A: верно, это {data}') return else: print("A: Кроме слова привет я больше ничего не понимаю") return "A: Кроме слова привет я больше ничего не понимаю" class B(Net): def process(self, data): time.sleep(1) if data == 'привет': print("B: давай дружить") return 'давай дружить' elif isinstance(data, tuple): print('B: подожди 2 секунды,складываю...') time.sleep(2) a, b = data print(f"В: {a+b}") return a+b else: print("B: я разочарован") return class C(Net): pass a = A() b = B() c = C() while True: s = input(">>>") if s == 'x': a.send_message(a,c,'входные данные для С') break else: b.send_message(b,a,s)
Офлайн
xam1816Вот пример:
Типа такого пишут программы?
>>> class Informer: ... def know_length(self, obj): ... print(obj, 'has length', len(obj)) ... >>> lst = [1, 2, 3, 4, 5] >>> >>> informer = Informer() >>> informer.know_length(lst) [1, 2, 3, 4, 5] has length 5 >>>
Отредактировано py.user.next (Март 10, 2021 02:49:21)
Офлайн
py.user.nextСпасибо за разъяснение,вот что я понял из вашего сообщения.
первый_ответ = адресат.выполнить_действие(аргументы), второй_ответ = адрес_2.преобразовать_данные(первый_ответ)
def сдеалай_что-либо(вот_данные) обрабатываю данные своими методами вернуть измененные_данные
import tkinter as tk import random as rd import tkinter.messagebox as mb class ModelCell: def __init__(self): self.mined = False self.flaged = False self.opened = False class ModelMinefield: def __init__(self, size, count_mines): self.size = size self.count_mines = count_mines self.mines_coords = self._get_random_cords() self.cells = self._get_matrix() self._set_mines_by_coords() self.count_mines_cleared = 0 self.count_flags = self.count_mines def show_cells_in_cmd(self): for row in self.cells: print() for c in row: print("@"if c.mined else "*",end='\t') def _get_random_cords(self): coords = set() while len(coords) != self.count_mines: coords.add((rd.randint(0, self.size - 1), rd.randint(0, self.size - 1))) return coords def _get_matrix(self): matrix = [[ModelCell() for _ in range(self.size)] for _ in range(self.size)] return matrix def _set_mines_by_coords(self): for r, c in self.mines_coords: self.cells[r][c].mined = True def _get_count_mines_around_cell(self, r, c): value = 0 for i in range(r - 1, r + 2): if self.size > i >= 0: for j in range(c - 1, c + 2): if self.size > j >= 0: value += int(self.cells[i][j].mined) return value def get_value_from_cell(self, r, c): cell = self.cells[r][c] if cell.opened: return if not cell.flaged: self.cells[r][c].opened = True if cell.mined: return 'mine' else: return self._get_count_mines_around_cell(r, c) def set_flag(self,r, c): cell = self.cells[r][c] if cell.opened: return None, None elif not cell.flaged and self.count_flags > 0: self.cells[r][c].flaged = True self.count_flags -= 1 if cell.mined: self.count_mines_cleared += 1 if self.count_mines_cleared == self.count_mines: return 'win', self.count_flags return 'flag', self.count_flags elif cell.flaged: self.cells[r][c].flaged = False self.count_flags += 1 if cell.mined: self.count_mines_cleared -= 1 return 'opened', self.count_flags else: return None,None class ViewCell(tk.Label): def __init__(self, r, c, **kw): super().__init__(width=3,bg='grey', relief='raised',fg = 'yellow',font = "Arial 12 bold",**kw) self.grid(row=r, column=c) self.coords = (r, c) def set_color(self, color): self.config(bg=color) def set_text(self, text): self.config(text=text) def set_option_default(self): self.config(text='', bg='grey') def bind_command(self, event, command): self.bind(event, lambda e: command(*self.coords)) class MatrixCell(tk.Frame): def __init__(self, size, **kw): super().__init__(**kw) self.cells = [[ViewCell(r, c, master=self) for c in range(size)] for r in range(size)] self.pack(side='bottom') class ProcessGame: def __init__(self, size, count_mines): self.size = size self.count_mines = count_mines self.mf = ModelMinefield(size, count_mines) self.matrix = MatrixCell(size) self.lbl = tk.Label(text=f'мин = {self.mf.count_mines} | флагов = {self.mf.count_flags}',bg='light green') self.lbl.pack(side='top') for i in range(self.mf.size): for j in range(self.mf.size): self.matrix.cells[i][j].bind_command('<ButtonRelease - 1>',self.on_right) self.matrix.cells[i][j].bind_command('<ButtonRelease - 2>', self.on_middle) self.matrix.cells[i][j].bind_command('<ButtonRelease - 3>', self.on_left) def on_right(self, r, c): cell = self.matrix.cells[r][c] value = self.mf.get_value_from_cell(r, c) if value is None: return if value == 'mine': self.show_mine(cell) self.show_game_over() return True else: if value == 0: self.show_zero(cell) self.on_middle(r, c) else: self.show_value(cell, value) def on_left(self, r, c): cell = self.matrix.cells[r][c] value, count_flags = self.mf.set_flag(r, c) if value is None: return self.lbl['text'] = f'мин = {self.mf.count_mines} | флагов = {count_flags}' if value == 'flag': self.show_flag(cell) elif value == 'opened': cell.set_option_default() elif value == 'win': self.show_flag(cell) self.show_win() def on_middle(self, r, c): for i in range(r - 1, r + 2): if 0 <= i < self.mf.size: for j in range(c - 1, c + 2): if 0 <= j < self.mf.size: if self.on_right(i, j): return def show_mine(self, cell:ViewCell): cell.set_color('red') def show_value(self, cell:ViewCell, value): cell.set_text(value) cell.set_color('brown') def show_zero(self, cell): cell.set_color('green') def show_flag(self, cell): cell.set_color('yellow') def show_win(self): mb.showinfo("Этап пройден", "Вы выйграли") self.matrix.destroy() self.lbl.destroy() self.__init__(self.size + 1,self.count_mines + 5) def show_game_over(self): mb.showinfo("Взрыв", "Вы проиграли") self.matrix.destroy() self.lbl.destroy() self.__init__(self.size, self.count_mines) class MainWindow(tk.Tk): def __init__(self): super().__init__() self.title('Сапер') self.resizable(width=0,height=0) self.config(bg='light green') def main(): window =MainWindow() ProcessGame(10, 10) window.mainloop() if __name__ == '__main__': main()
Офлайн