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
- \R python ✓ - Forum Python
- Ce programme est écrit en python il construit un mot secret ✓ - Forum Python
- Citizen code python solution - 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.