Пример #1
0
    def __init__(self, text: Text, padding: Vector2D = Vector2D(20, 10), position: Vector2D = Vector2D.zero(),
                 color: Color = None,
                 onclick=None):
        super(Button, self).__init__()

        # look
        self.text = text
        self._position = position

        self.padding = padding
        self._size = Vector2D(
            self.text.rect.size[0] + self.padding.x,
            self.text.rect.size[1] + self.padding.y
        )

        self.text.center(Vector2D.center(self.position, self.size))

        # color
        if color is None:
            color = colors.TRANSPARENT
        self._mutable_color = color
        self._original_color = color

        # behaviour
        self.onhover = Hover(DIM_LIGHT, ORIGINAL_COLOR)
        self.onclick = onclick

        if self.onclick is None:
            self.onclick = lambda button: None

        # used to draw
        self.surface = self.make()
Пример #2
0
    def get_viable_neigbours(self):

        vectors = []

        size = Vector2D(len(self.grid), len(self.grid[0]))
        for x in [self.current.x - 1, self.current.x, self.current.x + 1]:
            for y in [self.current.y - 1, self.current.y, self.current.y + 1]:

                # index out of range
                if x < 0 or x > size.x - 1 or y < 0 or y > size.y - 1:
                    continue

                # current pos
                if x == self.current.x and y == self.current.y:
                    continue

                tile = self.grid[x][y]
                state = Tile.int_to_state(tile)

                if state in [Tile.UNVISITED, Tile.NEIGHBOURS, Tile.END]:
                    vectors.append(Vector2D(x, y))

                    # update cost
                    grid_cost = self.costgrid[x][y]
                    calculated_cost = Vector2D(x, y).manhattan(
                        self.current) + Vector2D(x, y).manhattan(self.end)

                    if grid_cost == -1 or grid_cost > calculated_cost:
                        self.costgrid[x][y] = calculated_cost
                        self.visited[tuple([x, y])] = self.current

                    if state != Tile.END:
                        self.grid[x][y] = Tile.state_to_int(Tile.NEIGHBOURS)

        return vectors
Пример #3
0
    def __init__(self,
                 text: Text,
                 size: Vector2D = None,
                 position: Vector2D = Vector2D.zero(),
                 color: Color = None,
                 onclick=None):
        super(Button, self).__init__()

        # look
        self.text = text
        self.size = size
        if self.size is None:
            self.size = Vector2D(100, 35)
        self._position = position

        self.text.center(Vector2D.center(self.position, self.size))

        # color
        if color is None:
            color = colors.TRANSPARENT
        self._mutable_color = color
        self._original_color = color

        # behaviour
        self.onhover = Hover(DIM_LIGHT, ORIGINAL_COLOR)
        self.onclick = onclick

        if self.onclick is None:
            self.onclick = lambda button: None
Пример #4
0
    def generate_bars(self, sizes):
        """
        creates the bars if they aren't already, else updates them

        :param sizes: sizes of bars
        :return:
        """
        bar_width = self.surface.get_rect().size[0] / self.size

        for i, y in enumerate(sizes):

            try:
                bar = self.bars[y]
                bar.position = Vector2D.custom(self.surface,
                                               i * bar_width,
                                               y - 1,
                                               inverty=True)
                continue
            except KeyError:
                bar = Rectangle(Vector2D.custom(self.surface,
                                                i * bar_width,
                                                y - 1,
                                                inverty=True),
                                Vector2D(bar_width, y),
                                color=Color.lerp(y / self.max, colors.RED,
                                                 colors.GREEN, colors.BLUE)
                                if self.color is None else self.color)

                self.bars[y] = bar
Пример #5
0
    def __init__(self, size: Vector2D, info_text: Text, position=Vector2D(0, 20), padding=Vector2D(0, 0)):

        self.size = size
        self.position = position
        self.padding = padding

        self.info_text = info_text
        self.info_text.text = 'Select start'

        self.tilepadding = Vector2D(0, 0)
        screen_size = Vector2D.tuple(pygame.display.get_surface().get_rect().size)
        space = Vector2D(
            screen_size.x - position.x - padding.x,
            screen_size.y - position.y - padding.y
        )

        self.tilesize = Vector2D(
            int((space.x - (self.size.x * self.tilepadding.x)) / self.size.x),
            int((space.y - (self.size.y * self.tilepadding.y)) / self.size.y),
        )

        self.grid = []
        for x in range(size.x):
            l = [0] * size.y
            self.grid.append(l)

        self.tiles = []
        for x in range(size.x):
            l = [None] * size.y
            self.tiles.append(l)

        self.remake_tiles(self.grid)

        self.drawable = Switch(True)

        self.mouse_left_down = Switch(False)
        self.mouse_left_down_type = None

        self.start = None
        self.end = None

        self.algorithm = None

        def onflip(val):
            if self.algorithm.solution_length == -1:
                self.info_text.text = 'No solution found'
                return

            self.info_text.text = 'Running' if val else f'Found solution of length {self.algorithm.solution_length}'

        self.running = Switch(False, onflip=onflip)

        self.misc = {}
Пример #6
0
    def remake_tiles(self, positions):
        for gridposition in positions:
            x, y = gridposition

            position = Vector2D(
                y * self.tilesize.y + y * self.tilepadding.x + self.position.x + self.padding.x,
                x * self.tilesize.x + x * self.tilepadding.y + self.position.y + self.padding.y,
            )

            tile = Tile(Tile.int_to_state(self.grid[x][y]), gridpos=Vector2D(x, y), position=position,
                        size=self.tilesize)

            self.tiles[x][y] = tile
Пример #7
0
    def update_tiles(self, grid):
        size = Vector2D(len(grid), len(grid[0]))

        for x in range(size.x):
            for y in range(size.y):
                position = Vector2D(
                    y * self.tilesize.y + y * self.tilepadding.x + self.position.x + self.padding.x,
                    x * self.tilesize.x + x * self.tilepadding.y + self.position.y + self.padding.y,
                )

                tile = Tile(Tile.int_to_state(self.grid[x][y]), gridpos=Vector2D(x, y), position=position,
                            size=self.tilesize)

                self.tiles[x][y] = tile
Пример #8
0
    def center(self, position):
        size = self.surface.get_rect().size

        self.position = Vector2D(position.x - (size[0] / 2),
                                 position.y - (size[1] / 2))

        self.autocenter = True
Пример #9
0
    def clean_grid(self, types, to=Tile.UNVISITED):
        """
        replaces all the state types in :param types: with state :param to:

        :param types: state types to replace
        :param to: replacement state
        """

        if Tile.END in types:
            self.end = None
            self.info_text.text = 'Select end'

        if Tile.START in types:
            self.start = None
            self.info_text.text = 'Select start'

        to = Tile.state_to_int(to)

        size = Vector2D(len(self.grid), len(self.grid[0]))
        for x in range(size.x):
            for y in range(size.y):
                tile = self.grid[x][y]

                if Tile.int_to_state(tile) in types:
                    self.grid[x][y] = to
Пример #10
0
    def __init__(self,
                 state,
                 gridpos: Vector2D,
                 size: Vector2D = None,
                 position: Vector2D = Vector2D.zero(),
                 onclick=None):
        super(Tile, self).__init__(Text(''), size, position, state, onclick)

        self.gridpos = gridpos
Пример #11
0
 def print_grid(grid):
     size = Vector2D(len(grid), len(grid[0]))
     for x in range(size.x):
         print('[', end='')
         for y in range(size.y):
             value = grid[x][y]
             print(value, end='')
             if y != size.y - 1:
                 print(', ', end='')
         print(']')
Пример #12
0
    def event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            for widget in self.widgets:

                # left button
                if event.button == 1:
                    if widget.inbound(Vector2D.tuple(event.pos)):
                        clicked = getattr(widget, 'clicked', None)
                        if callable(clicked):
                            clicked()
Пример #13
0
 def print_grid(self):
     size = Vector2D(len(self.tiles), len(self.tiles[0]))
     for x in range(size.x):
         print('[', end='')
         for y in range(size.y):
             value = self.grid[x][y]
             print(value, end='')
             if y != size.y - 1:
                 print(', ', end='')
         print(']')
Пример #14
0
    def __init__(self, text, size=14, italic=False, position=Vector2D.zero(), color: Color = colors.BLACK, font: Font = Roboto.MEDIUM):
        super(Text, self).__init__()

        self._text = text
        self._color = color

        self.font = font.get(size, italic)
        self.surface = self.font.render(text, True, color)
        self.position = position
        self.autocenter = False
Пример #15
0
    def __init__(self, grid):
        self.grid = grid

        self.start = None
        self.end = None
        self.walls = []

        self.queue = []
        self.parent = {}
        self.gcost = {}

        self.path = ()

        self.current = None

        self.costgrid = []

        # analysis
        size = Vector2D(len(self.grid), len(self.grid[0]))
        for x in range(size.x):
            self.costgrid.append([-1] * size.y)

            for y in range(size.y):
                tile = self.grid[x][y]

                if Tile.int_to_state(tile) == Tile.START:
                    self.start = Vector2D(x, y)
                    self.costgrid[x][y] = 0

                elif Tile.int_to_state(tile) == Tile.END:
                    self.end = Vector2D(x, y)

                elif Tile.int_to_state(tile) == Tile.WALL:
                    self.walls.append(Vector2D(x, y))

        self.current = self.start
        self.gcost[tuple(self.current)] = 0

        self.solution_found = False
        self.solution_length = 0

        self.heuristic_modifier = 1.2
Пример #16
0
    def _update_change(self, bar_width, sizes, color):
        for i, y in sizes:
            bar = self.bars[y]
            bar.position = Vector2D.custom(self.surface,
                                           i * bar_width,
                                           y - 1,
                                           inverty=True)

            # highlight the bar
            bar.color = color
            self.previous_changed.append(y)
Пример #17
0
    def text(self, text):
        self._text = text

        prev_rect = self.surface.get_rect()
        self.surface = self.font.render(self.text, True, self.color)

        # size changes depending on amount of text so position is changed
        self.position = Vector2D(
            self.position.x +
            (prev_rect.size[0] - self.surface.get_rect().size[0]) / 2,
            self.position.y)
Пример #18
0
    def update(self):
        mouse_pos = Vector2D.tuple(pygame.mouse.get_pos())

        for widget in self.widgets:

            mouse_is_over = widget.inbound(mouse_pos)

            if not widget.hover and mouse_is_over:
                widget.enter()

            if widget.hover and not mouse_is_over:
                widget.exit()
Пример #19
0
    def remake_tiles(self, grid):
        """
        recreates the whole tile grid for :param grid:

        :param grid: blueprint for recreation
        :return: None
        """
        size = Vector2D(len(grid), len(grid[0]))

        for x in range(size.x):
            for y in range(size.y):
                position = Vector2D(
                    y * self.tilesize.x + y * self.tilepadding.x + self.position.x + self.padding.x,
                    x * self.tilesize.y + x * self.tilepadding.y + self.position.y + self.padding.y,
                )

                tile = Tile(Tile.int_to_state(self.grid[x][y]), gridpos=Vector2D(x, y), position=position,
                            padding=Vector2D.zero())

                tile.size = self.tilesize

                self.tiles[x][y] = tile
Пример #20
0
    def update(self):
        if self.running.get():
            try:
                affected = self.algorithm.next()
                self.update_tiles(affected)
            except StopIteration:
                self.running.set(False)

            # not further actions allowed
            # when algorithms is running
            return
        else:
            # get current mouse position
            mouse_pos = Vector2D.tuple(pygame.mouse.get_pos())

            # get tile in mouse position position
            tile = self.tile(mouse_pos)
            if tile is None:
                return

            # update tile to indicate hover
            if not tile.hover:
                tile.enter()

            # revert previous hover previous hover tile
            try:
                inbound = self.misc['over']
                if tile.position != inbound.position:
                    inbound.exit()
            except KeyError:
                pass

            self.misc['over'] = tile

        keys = pygame.key.get_pressed()
        if keys[pygame.K_LALT]:
            for key in key_map.keys():
                # save
                if keys[key]:
                    value = key_map[key]
                    self.update_grid()
                    self.save(value)
                    break
        else:
            for key in key_map.keys():
                # load
                if keys[key]:
                    value = key_map[key]
                    self.load(value)
                    break
Пример #21
0
    def update(self):
        mouse_pos = Vector2D.tuple(pygame.mouse.get_pos())

        for widget in self.widgets:

            try:
                mouse_is_over = widget.inbound(mouse_pos)
            except NotImplementedError:
                continue

            if not widget.hover and mouse_is_over:
                widget.enter()

            if widget.hover and not mouse_is_over:
                widget.exit()
Пример #22
0
    def update(self):
        if self.running.get():
            try:
                affected = self.algorithm.next()
                self.remake_tiles(affected)
            except StopIteration:
                self.running.set(False)
        else:
            mouse_pos = Vector2D.tuple(pygame.mouse.get_pos())

            for tile in self.all_tiles():
                inbound = tile.inbound(mouse_pos)

                if not tile.hover and inbound:
                    tile.enter()

                if tile.hover and not inbound:
                    tile.exit()
Пример #23
0
    def clean_grid(self, types, to=Tile.UNVISITED):
        if Tile.END in types:
            self.end = None
            self.info_text.text = 'Select end'

        if Tile.START in types:
            self.start = None
            self.info_text.text = 'Select start'

        to = Tile.state_to_int(to)

        size = Vector2D(len(self.grid), len(self.grid[0]))
        for x in range(size.x):
            for y in range(size.y):
                tile = self.grid[x][y]

                if Tile.int_to_state(tile) in types:
                    self.grid[x][y] = to
Пример #24
0
    def event(self, event):
        """
        event handler

        :param event: event in consideration
        :return: None
        """
        if event.type == pygame.MOUSEBUTTONDOWN:
            for widget in self.widgets:

                # left button
                if event.button == 1:

                    try:
                        if widget.inbound(Vector2D.tuple(event.pos)):
                            clicked = getattr(widget, 'clicked', None)
                            if callable(clicked):
                                clicked()
                    except NotImplementedError:
                        continue
Пример #25
0
    def get_viable_neigbours(self) -> List[Vector2D]:
        """
        :return: vectors of all the viable neighbours(tiles that you can move to) of the current positon (self.current)
        """
        vectors = []

        size = Vector2D(len(self.grid), len(self.grid[0]))
        for x in [self.current.x - 1, self.current.x, self.current.x + 1]:
            for y in [self.current.y - 1, self.current.y, self.current.y + 1]:

                # index out of range
                if x < 0 or x > size.x - 1 or y < 0 or y > size.y - 1:
                    continue

                # current pos
                if x == self.current.x and y == self.current.y:
                    continue

                tile = self.grid[x][y]
                state = Tile.int_to_state(tile)

                if state in [Tile.UNVISITED, Tile.NEIGHBOURS, Tile.END]:
                    vectors.append(Vector2D(x, y))

                    # update grid cost / path cost
                    grid_cost = self.costgrid[x][y]

                    g = self.g(self.current) + self.distance(
                        self.current, Vector2D(x, y))
                    if grid_cost == -1:
                        self.gcost[(x,
                                    y)] = self.g(self.current) + self.distance(
                                        self.current, Vector2D(x, y))
                    else:
                        if self.gcost[(x, y)] > g:
                            self.gcost[(x, y)] = g

                    # update cost
                    calculated_cost = self.g(Vector2D(x, y)) + self.h(
                        Vector2D(x, y)) * self.heuristic_modifier

                    if grid_cost == -1 or grid_cost > calculated_cost:
                        self.costgrid[x][y] = calculated_cost
                        self.parent[(x, y)] = self.current

                    if state != Tile.END:
                        self.grid[x][y] = Tile.state_to_int(Tile.NEIGHBOURS)

        return vectors
Пример #26
0
    def tile(self, coord) -> Union[Tile, None]:
        """
        :returns: tile depending on value

        in case of tuple :return: tile in pixel positon (x, y)
        """

        # finding tile
        position = Vector2D.tuple(coord)

        x = (position.y - self.position.y - self.padding.y) / (self.tilesize.y + self.tilepadding.y)
        y = (position.x - self.position.x - self.padding.x) / (self.tilesize.x + self.tilepadding.x)

        ix = math.floor(x)
        iy = math.floor(y)

        # out of bounds
        if ix < 0 or ix >= self.size.x or iy < 0 or iy >= self.size.y:
            return

        return self.tiles[ix][iy]
Пример #27
0
 def all_tiles(self):
     size = Vector2D(len(self.tiles), len(self.tiles[0]))
     for x in range(size.x):
         for y in range(size.y):
             yield self.tiles[x][y]
Пример #28
0
    def draw(self, surface):
        size = Vector2D(len(self.tiles), len(self.tiles[0]))

        for x in range(size.x):
            for y in range(size.y):
                self.tiles[x][y].draw(surface)
Пример #29
0
    def event(self, event):
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_SPACE:
                if not self.drawable.get():
                    easygui.msgbox('Press either Left Ctrl or Left Shift to clear the current grid'
                                   '\nLeft Ctrl: Everything excluding walls'
                                   '\nLeft Shift: Everything including walls', 'Clear grid', ok_button='CLOSE')
                    return

                self.update_grid()

                if self.start is None or self.end is None:
                    easygui.msgbox('Starting point or End point not specified', 'Missing inputs', 'CLOSE')
                    return

                # lock input and start the a* algorithm
                self.drawable.set(False)

                self.algorithm = AStarAlgorithm(self.grid)
                self.running.set(True)

            if event.key == pygame.K_LSHIFT:
                if self.running.get():
                    return

                self.update_grid()
                self.clean_grid([Tile.VISITED, Tile.START, Tile.END, Tile.PATH, Tile.NEIGHBOURS, Tile.WALL])
                self.update_tiles(self.grid)
                self.drawable.set(True)

            if event.key == pygame.K_LCTRL:
                if self.running.get():
                    return

                self.update_grid()
                self.clean_grid([Tile.VISITED, Tile.START, Tile.END, Tile.PATH, Tile.NEIGHBOURS])
                self.update_tiles(self.grid)
                self.drawable.set(True)

        if event.type == pygame.MOUSEBUTTONDOWN:

            # left
            if event.button == 1:
                self.mouse_left_down.set(True)

                if self.drawable.get():
                    # for all tiles check and initiate drawing
                    for tile in self.all_tiles():
                        if tile.inbound(Vector2D.tuple(event.pos)):
                            currentstate = tile.state
                            if currentstate == Tile.WALL:
                                self.mouse_left_down_type = Tile.UNVISITED
                            elif currentstate == Tile.UNVISITED:
                                self.mouse_left_down_type = Tile.WALL

                            if self.mouse_left_down_type is not None:
                                tile.state = self.mouse_left_down_type

            # right
            if event.button == 3:
                if self.drawable.get():

                    if self.start is None or self.end is None:
                        for tile in self.all_tiles():
                            if tile.inbound(Vector2D.tuple(event.pos)):

                                if self.start is None:
                                    self.start = tile
                                    tile.state = Tile.START

                                    self.info_text.text = 'Select end'
                                else:
                                    self.end = tile
                                    tile.state = Tile.END
                                    self.info_text.text = 'Ready'

                    else:
                        print('Start and end has been selected')

        if event.type == pygame.MOUSEBUTTONUP:
            # left
            if event.button == 1:
                self.mouse_left_down.set(False)
                self.mouse_left_down_type = None

        if event.type == pygame.MOUSEMOTION:
            # left
            if self.mouse_left_down.get():

                if self.drawable.get():
                    # for all tiles draw / change state
                    for tile in self.all_tiles():
                        if tile.state == Tile.START or tile.state == Tile.END:
                            continue

                        if tile.inbound(Vector2D.tuple(event.pos)):
                            if self.mouse_left_down_type is not None:
                                tile.state = self.mouse_left_down_type
Пример #30
0
 def position(self, value):
     self._position = value
     self.text.center(Vector2D.center(self.position, self.size))