Пример #1
0
class Interface():
    def __init__(self):
        self.window = Tk()
        self.window.title = "Game of Life"
        self.window.geometry("1100x950")
        self.window.config(background='brown')
        # Init variables.
        self.variables()
        # Init frames.

        self.frame = Frame(self.window, bg='red')
        self.frame_sim = Frame(self.frame, bg='green', border=1)
        self.frame_time = Frame(self.frame_sim, bg="yellow", border=1)
        # Create all of widgets.
        self.create_widgets()
        # Pack.
        self.frame.pack(expand=YES)
        self.frame_sim.grid(pady=40, row=0, column=1, sticky=N)
        self.frame_time.pack(expand=YES)
        # Core.
        self.core = GameOfLife(113, 113)
        # Save shape

    def quit(self):
        self._save_shapes()
        self.window.quit()

    def load_shapes(self):
        _json = "shapes.json"
        with open(_json, "r") as f:
            json_content = json.load(f)
        for key, v in json_content.items():
            self.SHAPES[key] = [tuple(i) for i in v]

    def _save_shapes(self):
        _json = "shapes.json"
        with open(_json, "w") as f:
            json.dump(self.SHAPES, f, indent=4)

    def variables(self):
        self.SHAPES = {}
        self.load_shapes()
        self.size = 8
        self.cellule_canvas = 904 / self.size
        # Main liste of alive cells.
        self.cells = []
        # Sub-lists for born and dead cell for update self.cells.
        self.dead_cells = []
        self.new_cells = []

    def create_widgets(self):
        # Labels.
        self.create_title()
        # Buttons.
        self.create_start_button()
        self.create_next_button()
        self.create_prev_button()
        self.create_add_custom_button()
        self.create_remove_custom_button()
        self.create_quit_button()
        # CheckButton.
        self.check_value = BooleanVar()
        self.create_check_grid()
        # Canvas.
        self.create_canvas()
        # ComboBox.
        self.create_combobox()

    def create_title(self):
        self.title = Label(self.frame, text="Welcome to cell life")
        self.title.grid(row=0, column=1, sticky=N)

    def create_start_button(self):
        self.start_button = Button(self.frame_sim,
                                   text="Start/Pause",
                                   command=self.startEvolution)
        self.start_button.pack()

    def create_prev_button(self):
        self.prev_button = Button(self.frame_time, text="<")
        self.prev_button.grid(padx=3, row=0, column=0)

    def create_next_button(self):
        self.next_button = Button(self.frame_time, text=">")
        self.next_button.grid(padx=3, row=0, column=1)

    def create_add_custom_button(self):
        self.start_button = Button(self.frame_sim,
                                   text="Add this shape",
                                   command=self.add_custom)
        self.start_button.pack()

    def create_remove_custom_button(self):
        self.start_button = Button(self.frame_sim,
                                   text="Remove selected shape",
                                   command=self.remove_custom)
        self.start_button.pack()

    def add_custom(self):
        new_shape = self.cells[:]
        shape_index = len(self.SHAPES) - 4
        if shape_index < 9:
            name = f"Custom n°{shape_index+1}"
            self.SHAPES[name] = new_shape
            self.update_combobox()

    def remove_custom(self):
        selected = self.combo.get()
        if "Custom" in selected:
            self.SHAPES.pop(selected)
            self.update_combobox()

    def create_quit_button(self):
        self.quit_button = Button(self.frame_sim,
                                  text="Quit",
                                  command=self.quit)
        self.quit_button.pack(side=BOTTOM)

    def create_check_grid(self):
        self.show_grid = Checkbutton(self.frame_sim,
                                     variable=self.check_value,
                                     command=self.update_canvas)
        self.show_grid.pack()

    def create_canvas(self):
        self.canvas = Canvas(self.frame,
                             width=(self.size * self.cellule_canvas + 2),
                             height=(self.size * self.cellule_canvas + 2))
        self.canvas.config(bg='white', bd=1, highlightthickness=1)
        self.canvas.grid(row=0, column=0)
        self.canvas.bind("<Button-1>", self.mouse_click)

    def create_combobox(self):
        combo_shapes = list(self.SHAPES.keys())
        self.combo = ttk.Combobox(self.frame_sim,
                                  state="readonly",
                                  values=combo_shapes)
        self.combo.current(0)
        self.combo.pack()
        # Each combobox event update self.cells.
        self.combo.bind("<<ComboboxSelected>>", self.set_combo)

    def update_combobox(self):
        combo_shapes = list(self.SHAPES.keys())
        self.combo.config(values=combo_shapes)
        self.combo.pack()

    def set_combo(self, event):
        """ Methode called by a change on ComboBox.
        self.cell is clear for set this choice. """
        # et current ComboBox value.
        choice = self.combo.get()
        self.cells.clear()
        # Update self.cells
        for pos in self.SHAPES[choice]:
            self.manage_cells(pos)
        self.update_canvas()

    def _draw_grid(self):
        """ Methode who draw lines and rows in accordance to self.size. """
        width = int(self.canvas['width'])
        height = int(self.canvas['height'])
        # Increment 2px for see the first line on canvas limits.
        stepX = 2
        while stepX < width + self.size:
            self.canvas.create_line(stepX,
                                    0,
                                    stepX,
                                    height,
                                    width=1,
                                    fill='grey')
            stepX += self.size
        stepY = 2
        while stepY < height + self.size:
            self.canvas.create_line(0,
                                    stepY,
                                    width,
                                    stepY,
                                    width=1,
                                    fill='grey')
            stepY += self.size

    def mouse_click(self, event):
        """ Methode for add ou remove a cell directly by a mouse click in canvas. """
        # Increment de 3px for increase accuracy.
        mouseX = event.x - 3
        mouseY = event.y - 3
        # Divid by size of cellule for translate in position in cellule case.
        cellX = int(mouseX / self.size)
        cellY = int(mouseY / self.size)
        click_pos = (cellY, cellX)
        self.manage_cells(click_pos)

    def manage_cells(self, pos):
        """ Check if cell in arg already exists for sort cell. """
        if pos not in self.cells:
            self.new_cells.append(pos)
        else:
            self.dead_cells.append(pos)
        self.update_cells()

    def update_cells(self):
        # On ajoute toutes les nouvelles cellules.
        for cell in self.new_cells:
            if cell not in self.cells:
                self.cells.append(cell)
        # Supprime de self.cells toutes celles qui sont mortes.
        for cell in self.dead_cells:
            self.cells.remove(cell)
        self.new_cells.clear()
        self.dead_cells.clear()
        # Met a jours le canvas.
        self.update_canvas()

    def update_canvas(self, event=None):
        """
        Methode who erase canvas.
        Draw grid if CheckButton is True.
        Then draw all cell in self.cells.
        """
        # Clear canvas before.
        self.canvas.delete('all')
        # Draw grid if check button is checked.
        if self.check_value.get():
            self._draw_grid()
        self.draw_cells()

    def draw_cells(self):
        """ Itere self.cells for draw each cell. """
        # Dessine chaque cellule de self.cells.
        for cell in self.cells:
            self.draw_cell(cell)

    def draw_cell(self, pos):
        """ Draw a square with self.size and position in arg tuple(y, x)."""
        pos_x = (pos[1] * self.size + 2)
        pos_y = (pos[0] * self.size + 2)
        self.canvas.create_rectangle(pos_x,
                                     pos_y,
                                     pos_x + self.size,
                                     pos_y + self.size,
                                     fill='black')

    def startEvolution(self, event=None):
        self.core._start_pos(self.cells)
        for i in range(100):
            self.cells = self.core.evolution(self.cells)
            self.update_cells()
            if len(self.cells) == 0:
                break
            self.canvas.update()
            sleep(0.09)