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()
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
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 = {}
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
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
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
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
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
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
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(']')
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(']')
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
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)
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
def __init__(self, text, size=14, italic=False, 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 = Vector2D(0, 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
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
from core import colors, Switch, Vector2D, Color from widgets import Text, WidgetManager, Button, Hover from grid import GridManager pygame.init() size = width, height = 650, 670 screen = pygame.display.set_mode(size) pygame.display.set_caption('A* visualizer') info = Text('', color=colors.WHITE) manager = WidgetManager([info]) grid = GridManager(Vector2D(40, 40), info) framerate = 0 t0 = time.time() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() grid.event(event) manager.event(event) screen.fill(colors.BLACK) grid.update()
bars_range = range(len(bars.sizes)) # change this as necessary to change sorting algorithm # sorta = CocktailSort(bars.sizes[:]) # sorta = InsertionSort(bars.sizes[:]) # sorta = CycleSort(bars.sizes[:]) # sorta = QuickSort(bars.sizes[:], 0, len(bars.sizes) - 1) sorta = algorithms.MergeSort(bars.sizes[:]) # limit queue size to be safe ac = AlgorithmController(sorta, maxsize=10000) ac.start() # button to control algorithm flow flip_button = Button(Text('', color=colors.WHITE), size=Vector2D(70, 25), color=Color(0, 0, 0, 0), onclick=lambda _: should_sort.flip()) flip_button.position = Vector2D( Vector2D.center(screen.get_rect(), screen.get_rect().size).x - (flip_button.size.x / 2), 0) flip_button.onhover = Hover(BLACK_TEXT_WHITE_BACKGROUND, WHITE_TEXT_TRANSPARENT_BACKGROUND) def fbflip(val): flip_button.text.text = 'RUNNING' if val else 'STOPPED' fbflip(should_sort.get()) should_sort.on_flip = fbflip
pygame.init() size = width, height = 700, 720 screen = pygame.display.set_mode(size, pygame.DOUBLEBUF) # allowed events pygame.event.set_allowed([ pygame.QUIT, pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION, pygame.KEYUP ]) pygame.display.set_caption('A* visualizer') info = Text('', color=colors.WHITE) manager = WidgetManager([info]) grid = GridManager(Vector2D(50, 50), info) framerate = 0 t0 = time.time() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: AppDatabase.database().save() sys.exit() grid.event(event) manager.event(event) screen.fill(colors.BLACK)
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]
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)