- Python procédural en POO
- Citizen code python avis - Accueil - Outils
- Trouver la position d'un élément dans une liste python ✓ - Forum Python
- Python est introuvable. exúcutez sans argument pour procúder ó l ✓ - Forum Python
- [PyCharm] Pas d'interpréteur python ✓ - Forum Python
3 réponses
D'après toi, quels sont les objets que tu manipules?
Quels sont leurs attributs et/ou propriétés?
Pourquoi des variables globales?
C'est déjà un début de réflexion.
Ceci ne répond pas à ta question, mais en tant que "one-liner" invétéré, je n'ai pas pu résister.
Voici ton initialisation en simplifié:
NC,NL=5,5 #magasin de 5 colonnes 5 lignes
LL = [[""] * NC for _ in range(NL)]
Si vraiment seules les deux dernière colonnes de la dernière ligne sont vides, on peut faire plus simple.
Un exemple amélioré de ton code lequel si j'ai bien saisi représente un magasin automatique à la manière du stockage d'un entrepôt.
import pygame as pg import math import random FPS = 60 SCREEN_WIDTH = 660 SCREEN_HEIGHT = 460 SCREEN_COLOR = pg.Color(0, 0, 0, 0) AREA_BG_COLOR = pg.Color(0, 0, 0, 0) AREA_BORDER_COLOR = pg.Color(0, 255, 0, 0) AREA_ADRESS_COLOR = pg.Color(0, 255, 255, 0) AREA_PRODUCT_COLOR = pg.Color(255, 255, 0, 0) AREA_QUANTITY_COLOR = pg.Color(0, 255, 255, 0) CART_BAR_SIZE = 20 CART_BAR_BG_COLOR = pg.Color(0, 0, 255, 160) CART_BAR_FG_COLOR = pg.Color(128, 128, 255, 255) CURSOR_SIZE = CART_BAR_SIZE * 2 CURSOR_BG_COLOR = pg.Color(0, 0, 128) CURSOR_FG_COLOR = pg.Color(128, 128, 128) # CART_CURSOR_SPEED = 4 CART_CURSOR_SPEED = 12 # CART_TRANSFERT_SPEED = 5 CART_TRANSFERT_SPEED = 15 CART_WAIT_DELAY = 25 class Point: __slots__ = ('x', 'y') def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return f'x: {self.x}, y: {self.y}' class Area(pg.sprite.Sprite): width = 120 height = 80 def __init__(self, x, y, adress): super().__init__() self.__adress = adress self.image = pg.Surface((self.width, self.height)).convert() self.rect = self.image.get_rect() self.image.fill(AREA_BORDER_COLOR) pg.draw.rect(self.image, AREA_BG_COLOR, self.rect.inflate(-2, -2)) self.font = pg.font.SysFont('mono', 15) self.image.blit( self.font.render(self.__adress, True, AREA_ADRESS_COLOR), (3, 3) ) self.rect.topleft = x, y self._product = None self._quantity = 0 self._rect_product = pg.Rect( 5, self.rect.height / 3, self.width - 10, self.height / 3 - 4 ) self._rect_quantity = pg.Rect( 5, self.rect.h / 3 * 2, self.rect.w - 10, self.rect.h / 3 - 4 ) def _draw_product(self): self.image.fill(AREA_BG_COLOR, self._rect_product) text_surf = self.font.render(self._product, True, AREA_PRODUCT_COLOR) self.image.blit(text_surf, self._rect_product) def _draw_quantity(self): self.image.fill(AREA_BG_COLOR, self._rect_quantity) text_surf = self.font.render( str(self._quantity), True, AREA_QUANTITY_COLOR ) self.image.blit(text_surf, self._rect_quantity) @property def adress(self): return self.adress @property def product(self): return self._product @property def quantity(self): return self._quantity def put(self, product, quantity): assert self._quantity == 0, "Can't change product, stock is not to 0" self._product = product self._quantity = quantity self._draw_product() self._draw_quantity() def pick(self, quantity): assert ( self._quantity >= quantity ), f"Can't pick more than {self._quantity} units" self._quantity -= quantity self._draw_quantity() def add(self, quantity): # assert ( # self._quantity + quantity > self._quantity_max # ), f"Can't contains more than {self._quantity_max} units" self._quantity += quantity self._draw_quantity() class CartBar(pg.sprite.Sprite): def __init__(self, x, y, width, height): super().__init__() self.image = pg.Surface((width, height), pg.SRCALPHA).convert_alpha() self.rect = self.image.get_rect() self.image.fill(CART_BAR_BG_COLOR) self.rect.topleft = x, y self.font = pg.font.SysFont('mono', 15, True) class HorizontalCartBar(CartBar): def __init__(self): y = SCREEN_HEIGHT - CURSOR_SIZE + CART_BAR_SIZE / 2 super().__init__(0, y, SCREEN_WIDTH, CART_BAR_SIZE) self._label = "" def label(self, text): if self._label != text: self._label = text self.image.fill(CART_BAR_BG_COLOR) text = self.font.render(text.upper(), True, CART_BAR_FG_COLOR) rect = text.get_rect() y = self.rect.h / 2 for x in (CURSOR_SIZE + 50, SCREEN_WIDTH - 50 - rect.w): self.image.blit(text, text.get_rect(midleft=(x, y))) class VerticalCartBar(CartBar): def __init__(self): x = (CURSOR_SIZE - CART_BAR_SIZE) / 2 super().__init__(x, 0, CART_BAR_SIZE, SCREEN_HEIGHT) self._label = "" def label(self, text): if self._label != text: self._label = text self.image.fill(CART_BAR_BG_COLOR) x = self.rect.w / 2 text = self.font.render(text.upper(), True, CART_BAR_FG_COLOR) text = pg.transform.rotate(text, -90) rect = text.get_rect() for y in ( CURSOR_SIZE + rect.h / 2, SCREEN_HEIGHT - CURSOR_SIZE - rect.h, ): self.image.blit(text, text.get_rect(center=(x, y))) class CartCursor(pg.sprite.Sprite): def __init__(self): super().__init__() self.image = pg.Surface( (CURSOR_SIZE, CURSOR_SIZE), pg.SRCALPHA ).convert() self.rect = self.image.get_rect() self.image.fill(CURSOR_BG_COLOR) self.rect.topleft = 0, SCREEN_HEIGHT - CURSOR_SIZE self.font = pg.font.SysFont('mono', 15, True) def quantity(self, quantity): self.image.fill(CURSOR_BG_COLOR) text = self.font.render(str(quantity), True, CURSOR_FG_COLOR) center = self.rect.w / 2, self.rect.h / 2 self.image.blit(text, text.get_rect(center=center)) # Forklift class Cart: def __init__(self, store, *groups): self.store = store self.hbar = HorizontalCartBar() self.vbar = VerticalCartBar() self.cursor = CartCursor() for group in groups: group.add(self.hbar, self.vbar, self.cursor) self._moving = False self._action = 0 def _set_route(self): def get_points(start, end, step): dist = math.sqrt((start.x - end.x) ** 2 + (start.y - end.y) ** 2) numbers = int(dist / step) d = Point((end.x - start.x) / numbers, (end.y - start.y) / numbers) points = [ Point(start.x + d.x * i, start.y + d.y * i) for i in range(numbers) ] points.append(end) return points dest = Point(*self.store.get_pos(self._product)) self._route = get_points( self.cursor.rect, dest, CART_CURSOR_SPEED * (30 / FPS) ) def _set_work(self, work, product, quantity): self._moving = True self._work = work self._product = product self._quantity = quantity self._i = 0 self._action = 1 self._set_route() self.cursor.quantity(self._quantity) self.hbar.label(self._product) self.vbar.label(self._work.__name__) def pick(self, product, quantity): if self._moving: raise RuntimeWarning("Can't pick product, cart is moving") self._set_work(self.store.pick, product, quantity) def put(self, product, quantity): if self._moving: raise RuntimeWarning("Can't put product, cart is moving") self._set_work(self.store.put, product, quantity) def update(self): if self._action in (1, 4): try: point = self._route[self._i] self.cursor.rect.topleft = point.x, point.y self.hbar.rect.y = point.y + 10 self.vbar.rect.x = point.x + 10 self._i += 1 except IndexError: if self._action == 1: self._i = 0 self._action = 2 else: self._action = 0 self._moving = False elif self._action == 2: self._i += 1 if not self._i % int(CART_TRANSFERT_SPEED * (30 / FPS)): self._work(self._product, 1) self._quantity -= 1 self.cursor.quantity(self._quantity) if not self._quantity: self._action = 3 self._i = 0 self._route.reverse() elif self._action == 3: # délai d'attente self._i += 1 if self._i == int(25 / (30 / FPS)): self._i = 0 self._action = 4 @property def moving(self): return self._moving # Warehouse ? class Store: def __init__(self, width, height, x, y, *groups): self.groups = groups self._stock = tuple( Area( x + i * (Area.width + 3), y + j * (Area.height + 3), f'{chr(65 + j)}{i + 1}', ) for j in range(height) for i in range(width) ) for group in groups: group.add(self._stock) def pick(self, product, quantity): for area in self._stock: if area.product == product: try: area.pick(quantity) except AssertionError: raise ValueError() return raise ValueError(f"product {product} not in stock") def put(self, product, quantity): for area in self._stock: if area.product == product: area.add(quantity) return for area in self._stock: if area.product is None: area.put(product, quantity) return for area in self._stock: if area.quantity == 0: area.put(product, quantity) return raise ValueError(f"Can't add product in stock, no free area") @property def products(self): return tuple(area.product for area in self._stock) def get_quantity(self, product): for area in self._stock: if area.product == product: return area.quantity raise ValueError(f"product {product} not in store") def get_avalaible_products(self): return tuple(area.product for area in self._stock if area.quantity) def get_pos(self, product): for area in self._stock: if area.product == product: return area.rect.midtop class App: def __init__(self): pg.init() self.screen = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) self.screen.convert() self.screen.fill(SCREEN_COLOR) pg.display.update() self.display_group = pg.sprite.LayeredUpdates() self.store = Store(5, 5, 40, 5, self.display_group) for i in range(1, 26): quantity = random.randint(1, 20) self.store.put(f'produit {i}', quantity) self.cart = Cart(self.store, self.display_group) # Tests self.ACTION_EVENT = pg.USEREVENT pg.time.set_timer(self.ACTION_EVENT, 2000) def _random_action(self): work = (self.cart.pick, self.cart.put)[random.randrange(2)] if work == self.cart.pick: products = self.store.get_avalaible_products() product = random.choice(products) quantity = random.randint(1, min(self.store.get_quantity(product), 20)) else: products = self.store.products product = random.choice(products) quantity = random.randint(1, 20) work(product, quantity) def _clear(self, surf, rect): surf.fill(SCREEN_COLOR, rect) def run(self): clock = pg.time.Clock() running = True while running: for evt in pg.event.get(): if evt.type == pg.QUIT: running = False elif evt.type == self.ACTION_EVENT: if not self.cart.moving: self._random_action() self.cart.update() self.display_group.update() self.display_group.clear(self.screen, self._clear) rects = self.display_group.draw(self.screen) pg.display.update(rects) clock.tick(FPS) pg.quit()
Pas mal de choses peuvent être améliorées, entre autres :
- Créer une (ou plusieurs) classe dérivée d'Exception afin de gérer les exceptions de l'application.
- Ajouter des méthodes à la class Store, par exemple une méthode donnant les produits en pénurie, une autre donnant le produit stocké à telle adresse, etc.
- Changer la couleur du chariot (barre, curseur) en fonction de l'action effectuée, alimentation ou prélèvement.
- Ajouter une quantité de stockage max. dans les zones, et gérer le cas lorsqu'il est tenté d'ajouter plus de marchandises que la zone peut reçevoir.
- Revoir la façon dont sont créées les zones, ie: s'arranger pour que ce soit plus configurable.
- Certainement revoir le nom des classes Store et Cart, après c'est sans doute plus simple à écrire que Warehouse et Forklift...
- Et de fil en aiguille, d'autres idées viennent, etc, etc.