Python procédural en POO
desir_indecis -
Bonjour,
J'ai un code python écrit en procédural je veux le convertir en orienté objet. Est-ce que quelqu'un peut m'aider ?
import sys, pygame pygame.init() BLACK=0,0,0 BLUE=0,0,255 GREEN=0,255,0 WHITE=255,255,255 size = width, height = 660, 460 FRAMES_PER_SECOND = 10 clock = pygame.time.Clock() screen = pygame.display.set_mode(size) def draw_Barre_verticale(left,h): pygame.draw.rect(screen, BLUE, pygame.Rect(left, 0, 10, h)) def draw_Barre_horizontale(top,w): pygame.draw.rect(screen, BLUE, pygame.Rect(0, top, w, 10)) def draw_chariot(X,Y, Ref): pygame.draw.rect(screen, GREEN, pygame.Rect(X-20+5, Y-20+5, 40, 40)) font = pygame.font.SysFont("arial", 10) texte_x = pygame.font.Font.render(font, Ref, True, (0,0,0)) screen.blit(texte_x, dest=(X, Y)) def trouver_case_vide(): for j in range(5): for i in range(5): if LL[j][i]=='': return i,j #si aucune vide return None,None def retour_pos_init(): global X, Y, deltaX, deltaY if X>X0: X=X-deltaX if X<X0: X=X0 if Y<Y0: Y=Y-deltaY if Y>Y0: Y=Y0 def draw_magasin(): for j in range(5): for i in range(5): pygame.draw.rect(screen, WHITE, pygame.Rect(Xmin+i*120, Ymin+j*80, 120, 80),width=2) if LL[j][i]!='': font = pygame.font.SysFont("arial", 10) texte_x = pygame.font.Font.render(font, LL[j][i], True, (0,255,255)) screen.blit(texte_x, dest=(Xmin+i*120+5, Ymin+(4-j)*80+5)) def aller_pos_desiree(Xd,Yd): global X, Y, deltaX, deltaY if X < Xd : X=X+deltaX if X > Xd: X=Xd if Y > Yd : Y=Y+deltaY if Y < Yd: Y=Yd LL=[] # liste de listes contenant les ref des produits stockés NC,NL=5,5 #magasin de 5 colonnes 5 lignes for i in range(NC): L=[] for j in range(NL): L.append('') # au debut magasin vide aucun stock donc Ref '' LL.append(L) #on initialise certaines cases avec des refs avec des refs for i in range(5): for j in range(3): LL[i][j]="Ref"+str(i)+str(j) for i in range(4): LL[i][3]="Ref"+str(i)+str(j) for i in range(4): LL[i][4]="Ref"+str(i)+str(j) # dans le magasin on a mnt des cases vides et des cases pleines #limits de deplacement des barres Xmin=40;Xmax=width # barre verti Ymin=0; Ymax=height-40 #barre horizontale #vitesse de deplac: 2 pixels par 1/FRAMES_PER_SECOND =1/10sec deltaX=2;deltaY=-2 #position de repos X0,Y0=20,height-20 #barre vert à X0=20 et barre horiz à Y0=height-20 #init a la pos de repos des barres X=X0;Y=Y0 #trouver une case vide qui sera désignée par NumC,NumL numéros de colonne et de ligne NumC, NumL=trouver_case_vide() #si ca return None aucune case vide print(NumC,NumL) #affichage en position initiale draw_Barre_verticale(X0,height) draw_Barre_horizontale(Y0,width) pygame.display.update() clock.tick(FRAMES_PER_SECOND) #position desiree #NumC entre 0 et 4 et NumL entre 0 et 4 #NumC=2; NumL=3 Xdesiree=NumC*120+Xmin+60 Ydesiree=(4-NumL)*80+Ymin+40 # NumL=0 en bas de l'ecran compt=0 #compteur de temps #au debut on fait un chargement d'un produit de Ref XR123 par exemple #puis on fait un déchargement du meme produit #et le cycle recommence chargement=True # tru --> chargement , false --> dechargement Ref="XR123" # Ref contiendra la reference du produit à charger ou qui sera déchargé Chariot=Ref #Chariot contient la ref du produit dans le chariot while True: #print(LL) for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() #print(X,Y) if compt==0: #compt=0 debut du demi cycle on fait un chargement ou dechargement if chargement: Chariot=Ref #chariot contient le produit else: Chariot="" #retour chariot vide aller_pos_desiree(Xdesiree,Ydesiree) if (X,Y) ==(Xdesiree, Ydesiree): #arrivee a pos desiree compt=compt+1 #temporisation par comptage #print(compt) if chargement and compt==1: #chargement LL[NumL][NumC]=Chariot ; Chariot='' #placement du produit à la case if not chargement and compt==1:#dechargement Chariot=LL[NumL][NumC]; LL[NumL][NumC]='' #retrait du produit de la case if compt==50: #fin de temporisation 50*1/FRAMES_PER_SECOND =50/10=5s #après 5sec retour à pos initiale retour_pos_init() if X==X0 and Y==Y0 : compt=-50 if chargement: chargement=False #baseculment du chargement/dechargement else: chargement=True if compt<0: compt=compt+1 #tempo par comptage de -50 à 0 #print(compt) screen.fill(BLACK) draw_magasin() draw_Barre_verticale(X, height) draw_Barre_horizontale(Y,width) draw_chariot(X,Y,Chariot) pygame.display.update() clock.tick(FRAMES_PER_SECOND)
- Python procédural en POO
- Citizen code python avis - Accueil - Outils
- Python est introuvable. exúcutez sans argument pour procúder ó l ✓ - Forum Python
- Mot secret python pix ✓ - Forum Python
- Ce programme est écrit en python il construit un mot secret ✓ - Forum Python
- Python par la pratique : 101 exercices corrigés pdf - 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.