Ejemplo n.º 1
0
    def _init_buttons(self, control_frame):
        canvas = tk.Canvas(control_frame,
                           width=300,
                           height=125,
                           bg='#000000',
                           highlightthickness=0)
        canvas.pack()

        args = {'width': 100, 'disabled': True}

        prev = CanvasButton(canvas,
                            text='<< PREV',
                            pos=(92, 30),
                            onpress=self._prev_noodle,
                            **args)
        nxt = CanvasButton(canvas,
                           text='NEXT >>',
                           pos=(200, 30),
                           onpress=self._next_noodle,
                           **args)
        rotate = CanvasButton(canvas,
                              text='ROTATE',
                              pos=(92, 90),
                              onpress=self._rotate_noodle,
                              **args)
        flip = CanvasButton(canvas,
                            text='FLIP',
                            pos=(200, 90),
                            onpress=self._flip_noodle,
                            **args)

        return prev, nxt, rotate, flip
Ejemplo n.º 2
0
    def _show_page(self):
        x, y = 210, 20

        for player in self._paginator.players():
            self._canvas.create_text(x,
                                     y,
                                     text=player.name,
                                     font=settings.fonts['player_name'],
                                     fill='#ffff00')
            self._canvas.create_text(
                x + 220,
                y,
                text=' {} puzzles completed, {} auto-solved'.format(
                    player.puzzles_completed.player_completed,
                    player.puzzles_completed.auto_completed),
                font=settings.fonts['puzzles_completed'],
                fill='#666666')

            y += 50

        CanvasButton(self._canvas,
                     '<< PREV', (345, 250),
                     onpress=self._onprev,
                     disabled=not self._paginator.has_prev_page())
        CanvasButton(self._canvas,
                     'NEXT >>', (445, 250),
                     onpress=self._onnext,
                     disabled=not self._paginator.has_next_page())
Ejemplo n.º 3
0
    def __init__(self, board, oncomplete, noodle_frame, master=None, **kwargs):
        """Initialise a new BoardFrame frame.

        Args:
            board: The Board instance.
            oncomplete: Callback called when the board has been completed. The callback should accept a single
                argument - the Board instance that has been completed.
            master: The parent widget.
            **kwargs: Optional keyword arguments to configure this screen.
        """
        args = {'width': 440, 'height': 420, 'bg': '#000000'}
        kwargs.update(args)
        super().__init__(master, **kwargs)

        self._board = board
        self._oncomplete = oncomplete
        self._noodle_frame = noodle_frame
        self._canvas = tk.Canvas(self, highlightthickness=0, **args)
        self._canvas.pack()
        self._fade = Fade(self._canvas)
        self._hole_pressed = False
        self._holes = []

        self._undo = CanvasButton(self._canvas,
                                  'UNDO', (400, 380),
                                  onpress=self._undo_place_noodle,
                                  disabled=True)
        self._solve = CanvasButton(
            self._canvas,
            'SOLVE', (50, 380),
            onpress=lambda _: Dialog(
                self.master,
                message='If you auto-solve the puzzle, it will not '
                'count towards your completed puzzle total.',
                title='Are you sure?',
                onsubmit=self._solve_puzzle,
                show_cancel=True),
            disabled=True)

        level_text = self._canvas.create_text(
            220,
            130,
            text='Level {}'.format(board.puzzle.level.number),
            font=settings.fonts['gamescreen_intro'],
            fill='#FFFFFF')
        puzzle_text = self._canvas.create_text(
            220,
            200,
            text='Puzzle {}'.format(board.puzzle.number),
            font=settings.fonts['gamescreen_intro'],
            fill='#FFFFFF')

        def draw():
            self._canvas.delete(puzzle_text, level_text)
            self._holes = self._draw_board()
            self._draw_noodles_on_board(fade_duration=100)

        self.after(2000, draw)
Ejemplo n.º 4
0
    def __init__(self, onnewplayer, onexistingplayer, onhighscores, master=None, **kwargs):
        """Initialise a HomeScreen frame.

        Args:
            onnewplayer: No-args callback called when the new player button is pressed.
            onexistingplayer: No-args callback called when the existing player button is pressed.
            master: The parent widget.
            **kwargs: Optional keyword arguments to configure this screen.
        """
        args = {
            'width': 800,
            'height': 480,
            'bg': '#000000'
        }
        kwargs.update(args)

        super().__init__(master, highlightthickness=2, **kwargs)

        canvas = tk.Canvas(self, highlightthickness=0, **args)
        canvas.pack()

        canvas.create_text(400, 100, text='Kanoodle', font=fonts['homescreen_kanoodle'],
                           justify='center', fill='#FFFFFF')

        colour_map = OrderedDict()
        colour_map['G'] = Noodle.get(Noodle.designation == 'A').colour
        colour_map['E'] = Noodle.get(Noodle.designation == 'E').colour
        colour_map['N'] = Noodle.get(Noodle.designation == 'C').colour
        colour_map['I'] = Noodle.get(Noodle.designation == 'B').colour
        colour_map['U'] = Noodle.get(Noodle.designation == 'D').colour
        colour_map['S'] = Noodle.get(Noodle.designation == 'F').colour

        x, x_offset = 250, 60
        for char in colour_map:
            canvas.create_text(x, 180, text=char, font=fonts['homescreen_genius'],
                               justify='center', fill=colour_map[char])
            x += x_offset

        canvas.create_text(615, 140, text='2D', font=fonts['homescreen_2d'],
                           justify='center', fill='#FFFFFF')

        args = {
            'width': 170,
        }

        CanvasButton(canvas, 'NEW PLAYER', (305, 280), onpress=lambda _: onnewplayer(), **args)
        CanvasButton(canvas, 'EXISTING PLAYER', (495, 280), onpress=lambda _: onexistingplayer(),
                     disabled=len(Player.active_players()) == 0, **args)
        CanvasButton(canvas, 'HIGH SCORES', (400, 350), onpress=lambda _: onhighscores(),
                     disabled=len(Player.active_players()) == 0, **args)
    def _init_exit(self):
        args = {'width': 800, 'height': 100, 'bg': '#000000'}
        canvas_frame = tk.Frame(self, highlightthickness=0, **args)
        canvas_frame.pack()

        canvas = tk.Canvas(canvas_frame, highlightthickness=0, **args)
        canvas.pack()

        CanvasButton(canvas,
                     'EXIT', (700, 30),
                     onpress=lambda _: self._onexit())
    def _show_page(self):
        x, y = 170, 40

        for player in self._paginator.players():
            self._canvas.create_text(x,
                                     y,
                                     text=player.name,
                                     font=settings.fonts['player_name'],
                                     fill='#ffff00')
            latest_board = player.boards.order_by(Board.id)[-1]
            self._canvas.create_text(x + 220,
                                     y,
                                     text=' Level {}, Puzzle {}'.format(
                                         latest_board.puzzle.level.number,
                                         latest_board.puzzle.number),
                                     font=settings.fonts['puzzles_completed'],
                                     fill='#666666')
            if settings.admin_mode:
                CanvasButton(self._canvas,
                             ' X ', (570, y),
                             onpress=self._create_ondelete_player(player))

            next_puzzle = player.boards[-1].puzzle.next_puzzle()
            button_text = 'SELECT' if next_puzzle is not None else 'COMPLETE'
            CanvasButton(self._canvas,
                         button_text, (640, y),
                         onpress=self._create_onselect_player(player),
                         disabled=next_puzzle is None)
            y += 60

        CanvasButton(self._canvas,
                     '<< PREV', (345, 250),
                     onpress=self._onprev,
                     disabled=not self._paginator.has_prev_page())
        CanvasButton(self._canvas,
                     'NEXT >>', (445, 250),
                     onpress=self._onnext,
                     disabled=not self._paginator.has_next_page())
Ejemplo n.º 7
0
    def __init__(self, board, oncancel, master=None, **kwargs):
        """Initialise a new InfoFrame frame.

        Args:
            board: The Board instance.
            oncancel: Callback called when the Exit button is pressed.
            master: The parent widget.
            **kwargs: Optional keyword arguments to configure this screen.
        """
        frame_args = {
            'width': 800,
            'height': 60,
            'bg': '#000000',
        }
        kwargs.update(frame_args)
        super().__init__(master, highlightthickness=1, **kwargs)

        canvas = tk.Canvas(self, highlightthickness=0, **kwargs)
        canvas.pack()

        canvas.create_text(120,
                           26,
                           text='PLAYER: {}'.format(board.player.name),
                           font=settings.fonts['gamescreen_player'],
                           fill=Noodle.get(Noodle.designation == 'B').colour)
        canvas.create_text(300,
                           26,
                           text='LEVEL: {}'.format(board.puzzle.level.number),
                           font=settings.fonts['gamescreen_status'],
                           fill=Noodle.get(Noodle.designation == 'F').colour)
        canvas.create_text(380,
                           26,
                           text='PUZZLE: {}'.format(board.puzzle.number),
                           font=settings.fonts['gamescreen_status'],
                           fill=Noodle.get(Noodle.designation == 'F').colour)
        CanvasButton(canvas,
                     'EXIT',
                     pos=(715, 26),
                     width=140,
                     height=40,
                     onpress=lambda _: oncancel())
Ejemplo n.º 8
0
class BoardFrame(tk.Frame):
    """The frame of the GameScreen that contains the board."""
    def __init__(self, board, oncomplete, noodle_frame, master=None, **kwargs):
        """Initialise a new BoardFrame frame.

        Args:
            board: The Board instance.
            oncomplete: Callback called when the board has been completed. The callback should accept a single
                argument - the Board instance that has been completed.
            master: The parent widget.
            **kwargs: Optional keyword arguments to configure this screen.
        """
        args = {'width': 440, 'height': 420, 'bg': '#000000'}
        kwargs.update(args)
        super().__init__(master, **kwargs)

        self._board = board
        self._oncomplete = oncomplete
        self._noodle_frame = noodle_frame
        self._canvas = tk.Canvas(self, highlightthickness=0, **args)
        self._canvas.pack()
        self._fade = Fade(self._canvas)
        self._hole_pressed = False
        self._holes = []

        self._undo = CanvasButton(self._canvas,
                                  'UNDO', (400, 380),
                                  onpress=self._undo_place_noodle,
                                  disabled=True)
        self._solve = CanvasButton(
            self._canvas,
            'SOLVE', (50, 380),
            onpress=lambda _: Dialog(
                self.master,
                message='If you auto-solve the puzzle, it will not '
                'count towards your completed puzzle total.',
                title='Are you sure?',
                onsubmit=self._solve_puzzle,
                show_cancel=True),
            disabled=True)

        level_text = self._canvas.create_text(
            220,
            130,
            text='Level {}'.format(board.puzzle.level.number),
            font=settings.fonts['gamescreen_intro'],
            fill='#FFFFFF')
        puzzle_text = self._canvas.create_text(
            220,
            200,
            text='Puzzle {}'.format(board.puzzle.number),
            font=settings.fonts['gamescreen_intro'],
            fill='#FFFFFF')

        def draw():
            self._canvas.delete(puzzle_text, level_text)
            self._holes = self._draw_board()
            self._draw_noodles_on_board(fade_duration=100)

        self.after(2000, draw)

    def _draw_board(self):
        x, y = 115, 38
        x_incr, y_incr = 29, 49
        hole_ids = []
        hole_ids.extend(self._draw_row(x, y, 4))
        x -= x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 5))
        x -= x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 6))
        x += x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 5))
        x -= x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 6))
        x += x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 5))
        x += x_incr
        y += y_incr
        hole_ids.extend(self._draw_row(x, y, 4))

        for index, hole_id in enumerate(hole_ids):
            if settings.show_board_numbers:
                x1, y1, x2, y2 = self._canvas.bbox(hole_id)
                centre = x1 + ((x2 - x1) // 2), y1 + ((y2 - y1) // 2)
                self._canvas.create_text(centre,
                                         text=str(index),
                                         fill='#ffffff')
            self._canvas.tag_bind(hole_id, '<ButtonPress-1>',
                                  self._create_on_hole_press(index, hole_id))

        return hole_ids

    def _draw_row(self, tl_x, tl_y, num):
        holes_ = []
        for i in range(num):
            hole_id = self._canvas.create_oval(tl_x,
                                               tl_y,
                                               tl_x + 55,
                                               tl_y + 55,
                                               outline='#000000',
                                               fill='#000000',
                                               width=2)
            self._fade.fadein(hole_id,
                              '#4d4d4d',
                              elements=['outline'],
                              duration=1000)
            holes_.append(hole_id)
            tl_x += 56
        return holes_

    def _draw_noodles_on_board(self, fade_duration=0, oncomplete=None):
        self._clear_board()

        for i, board_noodle in enumerate(self._board.noodles, start=3):

            def draw(i, n):
                if fade_duration == 0:
                    i = 0

                self.after(
                    i * 600,
                    lambda: self._draw_noodle(n, n.position, fade_duration))

                if i == len(self._board.noodles) + 2:

                    def draw_complete():
                        self._noodle_frame.board_initialised()
                        self._undo.disable(
                            len(self._board.noodles) <= len(
                                self._board.puzzle.noodles)
                            or self._board.auto_completed)
                        if oncomplete:
                            oncomplete()

                    self.after(i * 700, draw_complete)

            draw(i, board_noodle)

    def _clear_board(self):
        for hole_id in self._holes:
            self._canvas.itemconfig(hole_id, fill='#000000')

        for item in self._canvas.find_all():
            if self._canvas.type(item) == 'image':
                self._canvas.delete(item)

    def _draw_noodle(self, noodle, position, fade_duration=0):
        last_position = position
        try:
            colour = noodle.colour
        except AttributeError:
            colour = noodle.noodle.colour
        try:
            image = NOODLE_IMAGES[noodle.designation]
        except AttributeError:
            image = NOODLE_IMAGES[noodle.noodle.designation]

        def show_image(item):
            x1, y1, x2, y2 = self._canvas.bbox(item)

            def show():
                self._canvas.itemconfig(item, fill='#4d4d4d')
                self._canvas.create_image(
                    x1 + settings.image_offsets['x'] + ((x2 - x1) // 2),
                    y1 + settings.image_offsets['y'] + ((y2 - y1) // 2),
                    image=image)

            return show

        self._fade.fadein(self._holes[last_position],
                          colour,
                          duration=fade_duration,
                          onfaded=show_image(self._holes[last_position]))
        self._canvas.itemconfig(self._holes[last_position],
                                outline='#4d4d4d',
                                width=2)

        for part in noodle.parts:
            last_position = holes.find_position(last_position, part)
            self._fade.fadein(self._holes[last_position],
                              colour,
                              duration=fade_duration,
                              onfaded=show_image(self._holes[last_position]))
            self._canvas.itemconfig(self._holes[last_position],
                                    outline='#4d4d4d',
                                    width=2)

    def _create_on_hole_press(self, hole_index, hole_id):
        def _on_hole_press(_):
            if not self._hole_pressed and self._canvas.itemcget(
                    hole_id, 'fill') == '#000000':
                noodle, selected_part = self._noodle_frame.accept()

                if selected_part is None:
                    # No noodle selected in NoodleSelectionFrame
                    self._noodle_frame.reject(noodle)
                    return

                self._hole_pressed = True

                try:
                    root_index = self._board.place(noodle,
                                                   position=hole_index,
                                                   part_pos=selected_part)
                except PositionUnavailableException:
                    self._reject_place_noodle(noodle, hole_id)
                else:
                    self._commit_place_noodle(noodle, hole_id, root_index)

                    if self._board.completed:
                        self._oncomplete(self._board)

        return _on_hole_press

    def _reject_place_noodle(self, noodle, hole_id):
        self._noodle_frame.reject(noodle)
        self._canvas.itemconfig(hole_id, outline=REJECT_COLOUR, width=4)
        self._canvas.tag_raise(hole_id)

        def revert():
            self._canvas.itemconfig(hole_id, outline='#4d4d4d', width=2)
            self._hole_pressed = False

        self.after(500, revert)

    def _commit_place_noodle(self, noodle, hole_id, root_index):
        self._canvas.itemconfig(hole_id, outline=HIGHLIGHT_COLOUR, width=4)
        self._canvas.tag_raise(hole_id)

        def commit():
            self._draw_noodle(noodle, root_index, fade_duration=40)
            self._hole_pressed = False
            self._undo.disable(
                len(self._board.noodles) <= len(self._board.puzzle.noodles)
                or self._board.auto_completed)

        self.after(500, commit)

    def _undo_place_noodle(self, _):
        num_board_noodles = len(self._board.noodles)
        num_puzzle_noodles = len(self._board.puzzle.noodles)

        if num_puzzle_noodles < num_board_noodles < 7:
            noodle = self._board.undo()
            self._undo.disable(
                len(self._board.noodles) <= len(self._board.puzzle.noodles))
            self._solve.disable(False)

            if noodle:
                self._noodle_frame.reject(noodle)
                self._draw_noodles_on_board()

    def _solve_puzzle(self):
        self._board.solve()
        self._solve.disable(True)

        for hole_id in self._holes:
            self._canvas.itemconfig(hole_id, fill='#000000')

        puzzle_noodles = [
            noodle.noodle for noodle in self._board.puzzle.noodles
        ]

        self._clear_board()

        for noodle in self._board.noodles:
            if noodle.noodle in puzzle_noodles:
                self._draw_noodle(noodle, noodle.position)

        def draw_remaining():
            for noodle in self._board.noodles:
                if noodle.noodle not in puzzle_noodles:
                    self._draw_noodle(noodle,
                                      noodle.position,
                                      fade_duration=100)
            self.after(4000, lambda: self._oncomplete(self._board))

        self.after(2000, draw_remaining)

        while True:
            try:
                self._noodle_frame.accept()
            except IndexError:
                break