From d62779cfe8c8fd35d0c9bd783358eae5656c608c Mon Sep 17 00:00:00 2001 From: Hourglass Date: Fri, 5 May 2023 06:13:03 +0200 Subject: [PATCH] feat: astar --- Environment.py | 16 ++++- Grid.py | 3 +- Package.py | 1 - Program.py | 62 +++------------- Shelf.py | 15 ++-- a_star.py | 156 +++++++++++++++++++++++++++++++++++++++++ bfs.py | 2 - main.py | 2 - num_map.py | 30 ++++---- resources/shelf.PNG | Bin 0 -> 1067 bytes resources/texture1.PNG | Bin 0 -> 3616 bytes resources/texture2.PNG | Bin 0 -> 5332 bytes resources/texture3.PNG | Bin 0 -> 7191 bytes resources/texture4.PNG | Bin 0 -> 2634 bytes resources/texture5.PNG | Bin 0 -> 1468 bytes resources/texture6.PNG | Bin 0 -> 2586 bytes 16 files changed, 203 insertions(+), 84 deletions(-) create mode 100644 a_star.py create mode 100644 resources/shelf.PNG create mode 100644 resources/texture1.PNG create mode 100644 resources/texture2.PNG create mode 100644 resources/texture3.PNG create mode 100644 resources/texture4.PNG create mode 100644 resources/texture5.PNG create mode 100644 resources/texture6.PNG diff --git a/Environment.py b/Environment.py index 2c2e166..803943c 100644 --- a/Environment.py +++ b/Environment.py @@ -1,6 +1,8 @@ import pygame + from Shelf import Shelf from Grid import Grid +from num_map import num_matrix HORIZONTAL = 1250 VERTICAL = 750 @@ -15,8 +17,18 @@ class Environment: self.window = window self.grid = Grid(self.window) self.Shelf = Shelf(self.window) + self.image = pygame.image.load('resources/texture5.PNG').convert_alpha() + self.rock = pygame.image.load('resources/texture4.PNG').convert_alpha() + self.dirt = pygame.image.load('resources/texture3.PNG').convert_alpha() def drawEnviroment(self): - self.window.fill(background) + for j in range(0, int(VERTICAL / TILE_SIZE)): + for i in range(0, int(HORIZONTAL / TILE_SIZE)): + if num_matrix[j][i] == 0: + self.window.blit(self.image, (i * TILE_SIZE, j * TILE_SIZE)) + elif str(num_matrix[j][i]) in 'r': + self.window.blit(self.rock, (i * TILE_SIZE, j * TILE_SIZE)) + elif str(num_matrix[j][i]) in 'd': + self.window.blit(self.dirt, (i * TILE_SIZE, j * TILE_SIZE)) self.Shelf.drawShelves() - self.grid.drawGrid() \ No newline at end of file + self.grid.drawGrid() diff --git a/Grid.py b/Grid.py index 7c5e5ed..8941c94 100644 --- a/Grid.py +++ b/Grid.py @@ -1,12 +1,11 @@ import pygame -import numpy as np HORIZONTAL = 1250 VERTICAL = 750 TILE_SIZE = 50 -line_color = (85, 85, 85) +line_color = (0, 0, 0) class Grid: diff --git a/Package.py b/Package.py index 1476216..85974f5 100644 --- a/Package.py +++ b/Package.py @@ -1,4 +1,3 @@ -import numpy as np import pygame import glob2 import random diff --git a/Program.py b/Program.py index c026d99..a84b914 100644 --- a/Program.py +++ b/Program.py @@ -1,8 +1,7 @@ import pygame -import bfs import random +import a_star -from num_map import num_matrix from pygame.locals import * from Forklift import Forklift @@ -11,14 +10,14 @@ VERTICAL = 750 TILE_SIZE = 50 -## 4x6x5 + def handle_turn(initial_state, turn_count): if turn_count % 2 == 0: - commands = bfs.graphsearch(initial_state=initial_state, goal_list=(7, 23)) + commands = a_star.a_star(state=initial_state, goal=(7, 23)) else: row = random.randint(0, 1) * 10 + 2 * random.randint(0, 2) col = random.randint(1, 5) + 6 * random.randint(0, 3) - commands = bfs.graphsearch(initial_state=initial_state, goal_list=(row, col)) + commands = a_star.a_star(state=initial_state, goal=(row, col)) print('I need to go to row: ' + str(row) + ' column: ' + str(col)) return commands @@ -32,69 +31,28 @@ class Program: self.agent.drawForklift() running = True - - currRow = 7 - currCol = 1 - currDirec = 1 - turn_count = 0 - initial_state = bfs.State(row=int(self.agent.y/50), column=int(self.agent.x/50), direction=self.agent.direction) + initial_state = a_star.State(row=int(self.agent.y/50), column=int(self.agent.x/50), + direction=self.agent.direction) while running: - initial_state.row = int(self.agent.y/50) - initial_state.column = int(self.agent.x/50) - initial_state.direction = self.agent.direction - commands = handle_turn(initial_state=initial_state, turn_count=turn_count) - for event in pygame.event.get(): - if event.type == KEYDOWN: - if event.key == K_RIGHT: - if currCol + 1 < 25 and num_matrix[currRow][currCol + 1] == 0: - num_matrix[currRow][currCol] = 0 - currCol = currCol + 1 - num_matrix[currRow][currCol] = -1 - self.agent.moveForkliftRight() - if event.key == K_LEFT: - if currCol - 1 > -1 and num_matrix[currRow][currCol - 1] == 0: - num_matrix[currRow][currCol] = 0 - currCol = currCol - 1 - num_matrix[currRow][currCol] = -1 - self.agent.moveForkliftLeft() - if event.key == K_UP: - if currRow - 1 > -1 and num_matrix[currRow - 1][currCol] == 0: - num_matrix[currRow][currCol] = 0 - currRow -= 1 - num_matrix[currRow][currCol] = -1 - self.agent.moveForkliftUp() - if event.key == K_DOWN: - if currRow + 1 < 15 and num_matrix[currRow + 1][currCol] == 0: - num_matrix[currRow][currCol] = 0 - currRow += 1 - num_matrix[currRow][currCol] = -1 - self.agent.moveForkliftDown() - if event.key == K_ESCAPE: - running = False - elif event.type == pygame.QUIT: - running = False - while commands: pygame.event.poll() step = commands.pop(0) if step == 'rotate_left': self.agent.rotate_forklift_left() - currDirec = self.agent.direction elif step == 'rotate_right': self.agent.rotate_forklift_right() - currDirec = self.agent.direction elif step == 'go': self.agent.forklift_move() - currRow = int(self.agent.y/50) - currCol = int(self.agent.x/50) pygame.time.delay(250) - print('row: ' + str(currRow) + ' col: ' + str(currCol)) print(commands) turn_count += 1 - print(turn_count) pygame.time.delay(2000) + + initial_state.row = int(self.agent.y / 50) + initial_state.column = int(self.agent.x / 50) + initial_state.direction = self.agent.direction diff --git a/Shelf.py b/Shelf.py index 6a609dc..1e224ce 100644 --- a/Shelf.py +++ b/Shelf.py @@ -1,5 +1,6 @@ import pygame -import numpy as np + +from num_map import num_matrix HORIZONTAL = 1250 VERTICAL = 750 @@ -14,12 +15,10 @@ class Shelf: self.color = shelf self.width = 5 * TILE_SIZE self.height = TILE_SIZE + self.image = pygame.image.load('resources/shelf.PNG').convert_alpha() def drawShelves(self): - for j in range(0, 5 * TILE_SIZE, 2 * TILE_SIZE): - for i in range(TILE_SIZE + 1, HORIZONTAL - TILE_SIZE, 6 * TILE_SIZE): - pygame.draw.rect(self.window, shelf, pygame.Rect(i, j, self.width, self.height)) - - for k in range(VERTICAL - 5 * TILE_SIZE, VERTICAL, 2 * TILE_SIZE): - for l in range(TILE_SIZE + 1, HORIZONTAL - TILE_SIZE, 6 * TILE_SIZE): - pygame.draw.rect(self.window, shelf, pygame.Rect(l, k, self.width, self.height)) \ No newline at end of file + for j in range(0, int(VERTICAL / TILE_SIZE)): + for i in range(0, int(HORIZONTAL / TILE_SIZE)): + if str(num_matrix[j][i]) in 's': + self.window.blit(self.image, (i * TILE_SIZE, j * TILE_SIZE)) diff --git a/a_star.py b/a_star.py new file mode 100644 index 0000000..05b0f67 --- /dev/null +++ b/a_star.py @@ -0,0 +1,156 @@ +import heapq + +from num_map import num_matrix + +MAX_ROWS = 15 +MAX_COLS = 25 + +mapping = { + 'd': 10, + 's': 20, + 'r': 999 +} + + +class State: + """ + Directions + UP: 0 + RIGHT: 1 + DOWN: 2 + LEFT: 3 + """ + def __init__(self, row, column, direction): + self.direction = direction + self.row = row + self.column = column + + def rotate_left(self): + return (self.direction - 1) % 4 + + def rotate_right(self): + return (self.direction + 1) % 4 + + def __eq__(self, state: "State"): + return (state.row, state.column, state.direction) == (self.row, self.column, self.direction) + + def __lt__(self, state: "State"): + return (self.row, self.column) < (state.row, state.column) + + def __hash__(self): + return hash((self.row, self.column)) + + +class Node: + def __init__(self, state: "State", parent=None, action=None, cost=1): + self.state = state + self.parent = parent + self.action = action + self.cost = cost + + def __lt__(self, node): + return self.state < node.state + + +def h(state: State, goal: tuple[int, int]): + """ + Heuristics calculating Manhattan distance + """ + x1, y1 = state.row, state.column + x2, y2 = goal + return abs(x1 - x2) + abs(y1 + y2) + + +def f(curr_node: Node, goal: tuple[int, int]): + """ + f(n) = g(n) + h(n) + """ + return curr_node.cost + h(state=curr_node.state, goal=goal) + + +def goal_test(goal_list, state: State): + if (state.row, state.column) == goal_list: + return True + return False + + +def is_valid_move(target_row, target_column): + if 0 <= target_row < MAX_ROWS and 0 < target_column < MAX_COLS: + return True + return False + + +def get_successor(state: "State"): + successors = list() + + rotate_left = State(row=state.row, column=state.column, direction=state.rotate_left()) + rotate_right = State(row=state.row, column=state.column, direction=state.rotate_right()) + + successors.append(('rotate_left', rotate_left)) + successors.append(('rotate_right', rotate_right)) + + if state.direction == 0: + if is_valid_move(target_row=state.row-1, target_column=state.column): + forward = State(row=state.row-1, column=state.column, direction=state.direction) + successors.append(('go', forward)) + elif state.direction == 1: + if is_valid_move(target_row=state.row, target_column=state.column+1): + forward = State(row=state.row, column=state.column+1, direction=state.direction) + successors.append(('go', forward)) + elif state.direction == 2: + if is_valid_move(target_row=state.row+1, target_column=state.column): + forward = State(row=state.row+1, column=state.column, direction=state.direction) + successors.append(('go', forward)) + elif state.direction == 3: + if is_valid_move(target_row=state.row, target_column=state.column-1): + forward = State(row=state.row, column=state.column-1, direction=state.direction) + successors.append(('go', forward)) + + return successors + + +def get_path_from_start(node: Node): + path = [node.action] + + while node.parent is not None: + node = node.parent + if node.action: + path.append(node.action) + + path.reverse() + return path + + +def check_cost(row: int, col: int, action): + if action in ('rotate_left', 'rotate_right'): + return 1 + else: + return mapping.get(num_matrix[row][col], 1) + + +def a_star(state: State, goal: tuple[int, int]): + node = Node(state=state, parent=None, action=None) + + fringe = list() + heapq.heappush(fringe, (f(node, goal), node)) + explored_states = set() + + while fringe: + r, node = heapq.heappop(fringe) + + if goal_test(goal, node.state): + return get_path_from_start(node) + + explored_states.add(node.state) + + for successor in get_successor(node.state): + action, next_state = successor + movement_cost = check_cost(row=next_state.row, col=next_state.column, action=action)+node.cost + child = Node(state=next_state, parent=node, action=action, cost=movement_cost) + + p = f(child, goal=goal) + + if child.state not in explored_states and (p, child) not in fringe: + heapq.heappush(fringe, (p, child)) + elif (r, child) in fringe and r > p: + heapq.heappush(fringe, (p, child)) diff --git a/bfs.py b/bfs.py index b03dfd0..0a1c32a 100644 --- a/bfs.py +++ b/bfs.py @@ -32,8 +32,6 @@ class Node: self.action = action -## Temporarily removed collisons to allow bfs to work without putting in any extra work -## Should be: if 0 <= target_row < MAX_ROWS and 0 < target_column < MAX_COLS and num_matrix[target_row][target_column] not in [1]: def is_valid_move(num_map, target_row, target_column): if 0 <= target_row < MAX_ROWS and 0 < target_column < MAX_COLS: return True diff --git a/main.py b/main.py index ab6f9c2..ae0dc7d 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,3 @@ -import pygame -from pygame.locals import * from Program import Program if __name__ == "__main__": diff --git a/num_map.py b/num_map.py index d39af3c..6f02bea 100644 --- a/num_map.py +++ b/num_map.py @@ -1,15 +1,15 @@ -num_matrix = [[0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0]] +num_matrix = [[0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'd', 0, 0, 'd', 0, 0, 0, 'd', 0, 0, 0, 0, 0, 0], + [0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0], + ['d', 0, 0, 0, 0, 0, 0, 'd', 0, 'd', 0, 0, 0, 0, 0, 0, 0, 'd', 0, 0, 0, 'd', 'd', 'd', 'd'], + [0, 's', 's', 's', 's', 's', 'd', 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0], + [0, 0, 'd', 0, 0, 0, 0, 0, 0, 0, 'd', 0, 0, 0, 0, 'd', 0, 'd', 0, 0, 0, 0, 0, 0, 0], + [0, 'd', 0, 0, 'd', 0, 0, 'd', 0, 0, 0, 'd', 0, 0, 0, 0, 'd', 0, 'd', 'd', 'd', 0, 'r', 'r', 0], + ['d', 0, 'd', 0, 0, 0, 0, 0, 'd', 0, 'd', 0, 0, 'd', 0, 'd', 'd', 'd', 'd', 0, 0, 0, 'r', 0, 0], + [0, 0, 0, 0, 0, 'd', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'd', 0, 0, 0, 0, 'r', 'r', 0], + ['d', 0, 0, 0, 0, 0, 0, 'd', 'd', 0, 0, 'd', 0, 0, 0, 'd', 0, 0, 0, 'd', 0, 0, 0, 0, 0], + [0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'd', 'd', 'd', 0, 0, 'd', 0, 'd', 0, 0], + ['d', 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0], + [0, 0, 0, 0, 0, 0, 0, 0, 'd', 0, 0, 0, 0, 'd', 0, 0, 0, 0, 0, 0, 'd', 0, 0, 0, 0], + [0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0, 's', 's', 's', 's', 's', 0]] diff --git a/resources/shelf.PNG b/resources/shelf.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a2e48420a35a5dbfd2a362e32505daa57ae7c604 GIT binary patch literal 1067 zcmV+`1l0S9P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&1Hef{K~!i%?OI7| zQ&AND-g`-trfD^$YNb|N#jzDpv2`jcMO-+cxKvPFh%OZR7u@t8h`13IT&OE4h`3Nt zivuWF>#$I(D8Y_)$n=KmIVUfnf&PGdOFuYy;UX#h@Vx-} zf)7hQyr3Su{En}GCJ=SZB2(~ubgW&9y=}{h$fHZ@>Ydkk@iC36r~@nfl4X_N>5FW^ z!^z#PINQB}i1b}lx1W5$;IC2ghy&ZUFg%&X--#R?dapCGc@M{Sw&2Wxb&y!{14V8M z#8qrTAm1|z6-mM2q<=uo4KqvC99STt8|F6=rR0^Knp<(3f(jz^nXEguLe#bqp-!)} z@g%~%j!8*Fy!rSu28KqFh&gb51@42~7+T=WP}Bd+gb;ODroqy7lj zQ~DeI=mBq*U~>m#5_vZeca^~8v^Uykm?A`EQ5?hna`-)(!N%srw=h0q@nJqQv=Z-Re1@evf4^lXWG@O#%);ih+{aLGzaUE*W;mOrNvI%VGUh)K(?V=cB0R(Jh-`v!kz$nf$cLd3#HoMqy66$E zZ<>RNh#uJ%>JdgjUPw=5MJ6(tQYqHmcv@!&k%+@`5%@VgEhJ2Y4H`*?MyBxN?+m)y z8fB4Hmnp`YJznL&de(bPy%VP^Fq8R(ZKn;Hw35jQ2d5p}qgh z5)tYbIa-{_c|{|!!j>hrCYa|3M1l2)udtFdNP9~Pn^vW;c~w1@r4n+?!lGVlnyhp)O*qooGKvPMw|egWJ9-R%+f7TG#qMU|?t*YnIhY0+|AyMmpAoe{Pi3r002ovPDHLkV1nVq@9qEq literal 0 HcmV?d00001 diff --git a/resources/texture1.PNG b/resources/texture1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4f274cd180f74c76ce63bc7a06d42d679e6a6ccf GIT binary patch literal 3616 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 B`4|8I literal 0 HcmV?d00001 diff --git a/resources/texture5.PNG b/resources/texture5.PNG new file mode 100644 index 0000000000000000000000000000000000000000..060bad2843b20c329b4aa259528517ddfe45b429 GIT binary patch literal 1468 zcmYk6dpHwn9LFb@M&`0{x}XtiI-N1HatWL3ju;MwlWQW)t>#wIq_teiZBfI}IZ-DJ zdziyaXHup_7qKvzm^v<*m@fH z2~7n66umJ{DBslJc`7b{)Jcof1DT;SO{&9x)7V}dpN1;F?{L*L3!2gGD%}DmWLB!U zc_|d1u0=A-a$k$A;W<6zI^M`K?yvObeZ2znQj7R<3yPH;=8|NAKg5z-I}y3iI-?_w z@rx52@EBuBIOz$Kxfe<7Pl9I+rpP#|c8XT{KnF7gd9HOI<}7w4^e)LV@DM;5O;Rv; z)WFEDJy|xXn1phA%XO}+?~IN8j+lk(?Yq?y)H8y6z4{9NC-+Gm=5r5z7(RaN9fRI^ zDw#(dtE{3j=3n)_r~34iX2~t4`PbEtKi4Jb5q^nniODgDaMLh10`3G8Rh7{Sf^;wu zsEp21FmTK);5Uu?j?UFijnKp(@o0!P6EbUGjD*GD(yuwMnzTd1)me%J23#U!A5Rut za2cxhj*vu!1=|M2@xUye;c|9aJ|v}RNspKyFZJL4y{$z^1&yAzD5jK(L`^AVu70yZ zpl9dTx!l0atOd+b&By;8#Kq+PN%TQ1p)~$Wh;x-FmoBi!e>X+T|4$y#zn|TEWkve;DV5J-^ zZOwtfzb6>5k+(v_6N!rkC{BTXgs%cBPQ$K{qMEMK<@kdcsQugDekqS2F{ExKkLS=+y+pzjm9%++t*rw^;YKXaNVf1a6lDoS@A{T^j z;=+vkkhUJIi^Hqzacjs2&ofdYh0Kv2P|oaY8-%+=^nkvkpLX*mNBF@sY3giY;dwpx zo%3WzX=qZrQPv0OH=x(2RtBIQ-l`}beLC`IjE|!}b>y)ZT`8og8Pip41yNI>Tl2BQ z5XRI@!z{HC5A-cs8Lg?<&X$_gl%_->=Z!|~SZcnUD_7&qrjl9l($F%dyYHlF)c}~_ zfLIr2-Ou;rhk2I9LrP@JnpAJD=jbtJH*_hxG~)?EnA7s6^$vp%Z=u;`31OfexCW2f z5d2H)D=6Bw3g%fM;|mh_s#y>Y=LG8nQNsVVaf6Y@<><}4V@TB47-T5E>HGel)Nl19}smBM&2K_*jK)rI1>cd@h4lnPctyIBN&H3>AAX zEJnecj}+qk!BcDglb>QEbQq6sz=Xqm@$a5qs^0`qOe$Yl%vM}xT4>#QFBdlPVp7ml zB^@7}k%m^6D1TOx68Rt$%LrIfV(;|a*&Oxa{NRc1qVpUC$_uY4ZKS5;j}&sB0$r`F zpJifizxnAcL(*U)|6@pBo}_DeNE1v1ZD8BfO=kP1g~q6*ct$ci@^9^FDnI${+$a6i z14F^@NFls_P^(xqzj%o5PvGy&P4HjKu5aYudLW$b2dK?osUMYe&jegM8k)$*9)1e* z^9K{D+(xw;ktUij@vJHwXstU^kS#HXq2jiHi7GR}Tjr+N(+Ky$&$1sEfN}P8qM<`G F{{eH?uH*m! literal 0 HcmV?d00001 diff --git a/resources/texture6.PNG b/resources/texture6.PNG new file mode 100644 index 0000000000000000000000000000000000000000..31bbf2b47b59d726237df0d9481a5193e7895f09 GIT binary patch literal 2586 zcmX|Dc{mh$8=ZtKWvs)5j4k_hEny@}j9EywF|ucgqzI|Tnq-NYvCYWNSZ5SjB5S2I z*0IDzS(ANVvV}hG?fL$AfA90Yf1T$%=RM~aV`>6F$9A3#005jrA`HxryX#4@Fdx4@ z--(vT?UbK6{3@W7E;N5UFuLnq(*pp?3G4?qnT}^xAH)qm0D#;7q)v_95_xpID?=LS zSw3=D&TPZ;!Z{=Bv5~@`7Ogif@0u-5WoY<(53^=sVP(zwti5~AtL?gzAa1B;emw{l zB@I7Ju;{h#`XQ<#b6ZnR&ZUDIO?N2#HA&0H^NZv8X;O`}gDLBkWrgkS?ZNKC9)&u5 zb%^G~qc=7$t>BC9;~EKc9Y>LDdlthw zy*mecn^LhJ-lLV!xu+ZsidmtoTMM+hb;&w7;R4Q(CmI1@&bs{Y-r^344sA6UBMwS13ORh57n-t#>uWpGQ>BmnO;A%ut%J`L_T_4pnR#WN97>wAW zb)fM3<{{GD1D2eWJ_Xxtv8nGZvBBWwN$V;|zRB?D*y^c@`|Uy-%Sy2@&NuSuow@W}qUn_ST`q|!s10dleTpXj%2ZXB6&WczoaBRk9AhqIK{Qn5 z59Z~d_O+cqk5e3u7Uq=#L%CW_)%wbQbnNucenO$q!IN8^7cVfc?HdrOTp-R>yDT`? ztgTmh+LN)4N==5C!JNOut8|H4oSvL)xSQU^qeL4hXH}qJ{@{rWV&}JH0!Y*uS4=qw zEpHBO$ECO+hsJ5WF@6Umw!g36{tKwK29k{#)fef?ri~;xl8=ggZZ`C*W7!AKZh4t= z8=C0hl^NW*-giQmkiGp%mw?K}`7F<+Z2Wii(T1&Y2QW0k0*kb-^q#EnWkFqp-0)%6 z!EGP68&U1HOV2>TvK zl}8Kp@CUzDNPMDGfd;_<*K!ZILz0ujim@X4$^$@#yg^Z}!eR{QW8Ok{#1+81!N?hrWI^WlXvIKGW)@_jbt%76!_+ult*b#*rN*Yp{-bs6&5zRUM zTBC=*cD|5GVv4QEgB;1vo0b@AdP;qckZiawaA{Vh|2q8H9 zHe^Ib`sLS=P8t0!zBgYW0!^^PaY+bn{@71WE+xWoC}xFl7)+NG)5jGlQVYqobK;Zt zgAg*5N_W_%<_lqJcDuZ++QBaO+->AnmjQB33myCut`iQ1DsdZ27HFe9BV|sf!lC?< zjbu|cmO9zsd3`CxZ0!J#J*P+-J(Uf+epmiy=1wbUag)}k6CR^N=A(wZtzg`on4lyx za6j?uZ95a&G+5@iqZ#=6G7l#Rbh*awK*PO5l-SE)4px8=6HFFHXtyuOg1B90#yaY6 zEvOi^!mF=;YLyHvCWn`YXjzAE(^^G;5Tq$3wPHQ7LdQ2l@*lp#jD49+qpYc`m)g}T zv$4?0h&5kB~p@D!5}J*m%e8<#dMu&r^`H;vs1=tKu*msiT)NC6$xxRr?s z$b)CE+4|X4toGmB88j>qDUre|o$-`BpK9x}m4#&tFi@O%%Vybj&9TZ&hrdM!lWP+J zCDDxKazCfoFbl5E3T$UHEtAkEgq`pWaB|{DEzXZD1KeM1vc+t99tS2V^!H}>{yW@x>!bBq$Hm`jo=$tK slfPQZ-W@hQ+S{0}E4d#a5Bh!TqtC^5KEaJU$NxD15@uphdetfXf8=J?5&!@I literal 0 HcmV?d00001