lundi 20 juillet 2015

La sérialisation - Cours n°9

La sérialisation


PROBLÉMATIQUE

Je souhaiterais ajouter à mon jeu, un tableau des 5 meilleurs scores et pour faire cela rien de tel que d'utiliser la sérialisation des données qui me permettront de rendre persistant mes scores dans le temps.

Le principe est simple, vous avez une variable python (une liste par exemple) et voulez là garder en mémoire pour là réutiliser plus tard (par exemple au redémarrage du jeu)

Quels outils utiliser avec le langage Python ?

Un seul, on va utiliser le module pickle...

Nous utiliserons le protocole 4, le dernier mise à jour et optimisé pour la version python (>= 3.4)

Création de nos joueurs

Pour avoir un tableau de scores, il nous faut des joueurs et leur score. Pour cela on va créer une liste de scores dont les noms des joueurs sont inconnus et les scores sont nuls.

Code:

from collections import namedtuple

PLAYER_MAX = 5
Player = namedtuple('Player', ['name', 'score'])

def PlayersInit():
    players = []
    for i in range(PLAYER_MAX):
        p = Player(name='', score=0) # initialisation des joueurs au score 0
        players.append(p)
    return players

Voilà une liste de joueurs initialisés comme dit précédemment... J'utilise les namedtuple, objet python simple à comprendre et qui correspond à un objet python que vous connaissez bien, les tuples ! La différence c'est que les namedtuple sont nommés !

Ne vous inquiétez pas trop si vous ne connaissez pas, c'est plus pour vous donner une idée de conception si vous voulez fabriquer un tableau de scores, mais l'enjeu ici est d'expliquer comment sauvegarder et réutiliser ce tableau plus tard, lors d'un redémarrage du jeu par exemple...

Ajout d'un nom de joueur et son score

C'est une mise à jour du tableau, je vais l'appeler update !

Code:

def update(listPlayers, me):
    '''
        listPlayers est la liste des joueurs enregistrée
        me est un joueur, donc un objet de type Player
    '''
   
    for idx, player in enumerate(listPlayers):
        n, s = player.name, player.score
        if me.score > s: # si mon score dépasse l'ancien
            newList = [] # création de la liste updatée
            rightList = listPlayers[idx:]
            del rightList[-1] # suppression du dernier score à droite
            leftList = listPlayers[:idx] # récup des scores avant le score courant
            newList.extend(leftList) # ajout scores avant score courant
            newList.append(me) # ajout score courant
            newList.extend(rightList) # ajout scores après score courant
            listPlayers = newList[:] # copie dans listPlayers
            break # on quitte la boucle
    return listPlayers

Bon c'est plus complexe, mais encore une fois, c'est pour résoudre une problématique ! C'est le principe de décalage, si vous êtes 1er, l'ex premier devient 2ème, etc... et le dernier dégage du tableau !

Création de nouveaux joueurs

Bon là j'ai pas cherché loin, j'ai ajouté 3 joueurs

Code:

Fred = Player(name='Fred', score=50) # Création d'un joueur + score pour test
Dreamus = Player(name='Dreamus', score=35)
Sakarov  = Player(name='Sakarov', score=40)

Je les ai mis dans le désordre pour tester si ma mise en ordre dans le tableau est fonctionnel...

Enregistrement dans le tableau

Code:

listPlayers = update(listPlayers, Fred) # Mise à jour du tableau de scores
listPlayers = update(listPlayers, Dreamus)
listPlayers = update(listPlayers, Sakarov) # on va voir si ça se met bien dans l'ordre décroissant

Persistance des données, ENFIN !!!

Oui vous le souhaitiez tellement fort que j'ai dû éviter des détails lors de l'écriture de ce tutoriel.

On va utiliser le module pickle et ouvrir un fichier, s'il n'existe pas, le fichier sera créé automatiquement.

Le principe ici, est la sauvegarde !

Code:

import pickle

# ... suite du code

def save(path):
    ''' path est le chemin du fichier '''
    with open(path, "wb") as f: # création + ouverture du fichier en mode binaire
        pickle.dump(listPlayers, f, 4) # sauvegarde de l'objet listPlayers dans le fichier f

4 est le numéro de protocole dont je vous ai parlé au tout début du tutoriel.

Non mais tu déconnes Fred, ça peut pas être aussi simple ? Eh bien si, rien de plus simple, on vient de sauvegarder dans le fichier avec le chemin absolu path, le tableau de scores...

Ce qui rend le fichier très moche à lire

fichier.jpg

C'est bien si vous avez des mots de passe à enregistrer, mieux vaut que ça ne soit pas lisibles, n'est-ce pas ? ;)

C'est bien beau mais je fais quoi avec ce fichier maintenant ? On y arrive !

Chargement du tableau de scores au démarrage du jeu

Rien de compliquer, regardez !

Code:

def load(path):
    ''' path est le chemin du fichier '''
    var = None
    if os.path.exists(path): # Si le chemin existe
        try:
            with open(path, 'rb') as f: # on essaye d'ouvrir le fichier
                var = pickle.load(f) # on charge notre liste dans la variable var
        except: pass # Sinon on fait rien, la valeur de var vaut None
    return var

Bon j'ai ajouté des petites choses, histoire que mon jeu ne soit pas interrompu brusquement.

Je l'appelle simplement de cette manière

Code:

listPlayers = load(".../sauvegarde.txt") # chargement des scores
Un bel affichage en prime !

Pour faire beau, niveau affichage, nous allons créer une forme joueur -> score

Code:

def displayScores():
    pattern = "{name} -> {score}" # format de l'affichage
    for player in listPlayers:
        name, score = player
        if name: # S'il y a un nom
            print(pattern.format(name=name, score=score)) # on affiche le score

Et là vous remarquez qu'exceptionnellement pour une fonction, j'ai utilisé print, car elle est réservée à l'affichage !

Le code en entier

Voilà c'est terminé, le code en entier vous permettra de tester et vérifier, n'hésitez pas à me prévenir si vous voyez des erreurs ;)

Code:

from collections import namedtuple
import pickle
import os.path

PLAYER_MAX = 5
Player = namedtuple('Player', ['name', 'score'])

def PlayersInit():
    players = []
    for i in range(PLAYER_MAX):
        p = Player(name='', score=0) # initialisation des joueurs au score 0
        players.append(p)
    return players

def update(listPlayers, me):
    '''
        listPlayers est la liste des objets Player enregistrée
        me est un joueur, donc un objet de type Player
    '''
   
    for idx, player in enumerate(listPlayers):
        n, s = player.name, player.score
        if me.score > s: # si mon score dépasse l'ancien
            newList = [] # création de la liste updatée
            rightList = listPlayers[idx:]
            del rightList[-1] # suppression du dernier score à droite
            leftList = listPlayers[:idx] # récup des scores avant le score courant
            newList.extend(leftList) # ajout scores avant score courant
            newList.append(me) # ajout score courant
            newList.extend(rightList) # ajout scores après score courant
            listPlayers = newList[:] # copie dans listPlayers
            break # on quitte la boucle
    return listPlayers

def save(path):
    ''' path est le chemin du fichier '''
    with open(path, "wb") as f: # création + ouverture du fichier en mode binaire
        pickle.dump(listPlayers, f, 4) # sauvegarde de l'objet listPlayers dans le fichier f
       
def load(path):
    ''' path est le chemin du fichier '''
    var = None
    if os.path.exists(path): # Si le chemin existe
        try:
            with open(path, 'rb') as f: # on essaye d'ouvrir le fichier
                var = pickle.load(f) # on charge notre liste dans la variable var
        except: pass # Sinon on fait rien, la valeur de var vaut None
    return var

def displayScores():
    pattern = "{name} -> {score}" # format de l'affichage
    for player in listPlayers:
        name, score = player
        if name: # S'il y a un nom
            print(pattern.format(name=name, score=score)) # on affiche le score

listPlayers = PlayersInit() # Initialisation du tableau de scores

# Ajout des nouveaux scores
# -------------------------
Fred = Player(name='Fred', score=50) # Création d'un joueur + score pour test
Dreamus = Player(name='Dreamus', score=35)
Sakarov  = Player(name='Sakarov', score=40)
listPlayers = update(listPlayers, Fred) # Mise à jour du tableau de scores
listPlayers = update(listPlayers, Dreamus)
listPlayers = update(listPlayers, Sakarov) # on va voir si ça se met bien dans l'ordre décroissant

save("/home/fred1599/Bureau/sauvegarde.txt") # sauvegarde des scores

listPlayers = load("/home/fred1599/Bureau/sauvegarde.txt") # chargement des scores

print(listPlayers) # Affichage de la liste des scores
# [Player(name='Fred', score=50), Player(name='Sakarov', score=40), Player(name='Dreamus', score=35), Player(name='', score=0), Player(name='', score=0)]

displayScores() # bel affichage des scores
# Fred -> 50
# Sakarov -> 40
# Dreamus -> 35

Merci de m'avoir lu et bonne journée...
Images jointes


from Hackademics : Forum de hacking – hackers white hat – cours de securite informatique, apprendre langage python, tutoriels de reverse engineering http://ift.tt/1CLfoHq
via IFTTT

Aucun commentaire:

Enregistrer un commentaire