# Jeux vidéo > Jeux vidéo (Discussions générales) > Le coin des développeurs >  Python débutant, questions diverses

## Tchey

Salut,

Dans mon fichier monjeu.py j'ai ça au début :



```
joueur = {"nom" : "Marcel",
       "niv" : 1,
       "xp" : 0,
       "nivSuiv" : 25,
       "stats" : {
                  "vie" : 30,
                  "atq" : [10, 15]}}
```



```
gobelin = {"nom" : "Gobou",
       "niv" : 1,
       "xp" : 0,
       "nivSuiv" : 25,
       "stats" : {
                  "vie" : 20,
                  "atq" : [4, 6]}}
```

Ensuite un code simple issue d'un tuto internet pour faire une sorte d'arène automatique.

Comment je peux déplacer le joueur et le gobelin dans deux autres fichiers distincts, dans l'idée ensuite d'avoir un bestiaire.py et un joueur.py ?

J'ai tenté de simplement couper/coller les deux bouts dans leur fichier, et de faire import joueur et import gobelin au début de monjeu.py mais ça me retourne une erreur que je ne comprends pas.



```
Traceback (most recent call last):
  File "/home/tchey/Prog/Python/monjeu.py", line 79, in <module>
    commands(joueur, lutin)
  File "/home/tchey/Prog/Python/monjeu.py", line 72, in commands
    takeDmg(player, enemy)
  File "/home/tchey/Prog/Python/monjeu.py", line 53, in takeDmg
    dmg = randint(attacker["stats"]["atq"][0], attacker["stats"]["atq"][1])
TypeError: 'module' object is not subscriptable
```

Le code fonctionne très bien quand dans un seul fichier.

----------


## Nattefrost

Je sais pas si j'ai bien compris mais je vais essayer : tu veux avoir les deux personnages dans deux fichiers distincts que tu importera ensuite dans le fichier "main" ?

Mets tes personnages dans des fonctions (voire des classes, si tu connais la POO), un truc comme ça :
_joueur.py_


```
def get_player():
    joueur = {"nom" : "Marcel",
       "niv" : 1,
       "xp" : 0,
       "nivSuiv" : 25,
       "stats" : {
                  "vie" : 30,
                  "atq" : [10, 15]}}
    return joueur
```

_bestiaire.py_


```
def get_goblin():
    gobelin = {"nom" : "Gobou",
       "niv" : 1,
       "xp" : 0,
       "nivSuiv" : 25,
       "stats" : {
                  "vie" : 20,
                  "atq" : [4, 6]}}

    return gobelin
```

Ensuite dans ton programme main.py tu pourras faire:


```
import bestiaire
import joueur

player = joueur.get_player()
monster = bestiaire.get_goblin()
```

J'espère que je ne répond pas à coté de la plaque :D

----------


## Tchey

C'est farpaitement ça, et en plus ça fonctionne.

Les classes, j'ai des notions de ce que c'est, mais je passe mon tour pour le moment.

Merci

----------


## Nattefrost

Cool  ::): .

----------


## Tchey

J'ai un autre soucis maintenant.

Le joueur attaque en même temps qu l'adversaire IA, et le dégâts sont aléatoires, entre 50% et 100% du score d'attaque.
Parfois ça plante, je ne comprends pas pourquoi. Parfois ça marche aussi... 



```
    PAttack = random.randint(PlayerIG.attack/2, PlayerIG.attack) # le joueur attaque, pour faire entre attack/2 et attack dégâts
    EAttack = random.randint(enemy.attack/2, enemy.attack) # l'adversaire attaque, idem
```




> File "rpgtuto.py", line 127, in attack
>     EAttack = random.randint(enemy.attack/2, enemy.attack)
>   File "/usr/lib/python3.4/random.py", line 218, in randint
>     return self.randrange(a, b+1)
>   File "/usr/lib/python3.4/random.py", line 182, in randrange
>     raise ValueError("non-integer arg 1 for randrange()")
> ValueError: non-integer arg 1 for randrange()


Ah, je crois avoir trouvé, juste après avoir posté j'ai cherché encore un peu et suis tombé sur ça :



```
    PAttack = random.uniform(PlayerIG.attack/2, PlayerIG.attack)
    EAttack = random.uniform(enemy.attack/2, enemy.attack)
```

Et ça arrondi les nombres pour ne pas faire de virgules, qui semble-t-il ne sont pas copines avec les int

Et en passant, finalement comment on fait avec des Class à la place des Def ?

Par exemple ça c'est mon Gobelin :



```
class Gobelin:
    def __init__(self, name):
        self.name = name
        self.maxhealth = 50
        self.health = self.maxhealth
        self.attack = 10
        self.goldgain = 10 # Ce que gagne le joueur en battant cet adversaire
GobelinIG = Gobelin("Gobelin")
```

Et sinon, j'ai aussi ça dans un autre fichier de test, que je n'utilise pas. Quelle serait la meilleure option pour avoir un bestiaire varié et pas trop pénible à gérer ?



```
class Bestiole:
    def __init__(self, nom, atq, viemax, vie, xp, butin, force, agile, intel):
        self.nom = nom
        self.atq = atq
        self.viemax = viemax
        self.vie = vie
        self.xp = xp
        self.butin = butin
        self.force = force
        self.agile = agile
        self.intel = intel

class Lutin(Bestiole):
    def __init__(self):
        Bestiole.__init__(self, "Lutin", [3, 4], 10, 10, 5, 0, 1, 2, 1)

class Nabot(Bestiole):
    def __init__(self):
        Bestiole.__init__(self, "Nabot", [5, 6], 15, 15, 8, 0, 2, 2, 2)
```

----------


## Nattefrost

La fonction _randint_ du module _random_ prend comme son nom l'indique un integer (deux en fait). Parfois  ton expression _PlayerIG.attack/2_ vaut un nombre à virgule (float), d'ou l'interpréteur qui te pourrit la tronche.

Pour info en python3 (pas en py2) :


```
>>>10/3
3.3333333333333335
>>>10//3
3
```

Hier je t'ai conseillé de faire des fonctions (je savais pas si connaissais les classes) mais en réalité les classes sont mieux adaptées, c'est + réutilisable.

Le chemin que tu prend pour le bestiaire est viable, pour avoir quelque chose de plus varié je _randomiserai_ les valeurs de leurs attributs et je rajouterai des choses spécifiques à certains monstres (l'héritage, que tu utilise, te le permet), du genre une créature aura un trait particulier exemple: une harpie vole et sans arme de jet un gnome ne peut pas la toucher.

Une autre solution que j'envisage pour l'un de mes projets est de mettre les monstres dans des fichiers texte (json/yaml/xml/ini au choix) sur le filesystem, les joueurs peuvent ainsi modifier/ajouter des créatures. Tout dépend de ce que tu veux faire.

----------


## Tchey

Là j'ai seulement 250-300 lignes, je débute vraiment tout juste. J'ai repris mon "apprentissage de la programmation" hier après 3 mois de rien.
J'avais a peu près compris la création d'interface simple avec TKinter et j'avais fait ça : http://jeux1d100.net/dradro/ mais c'est une coquille vide.

Maintenant, j'apprends à faire un jaune d'oeuf pour mettre dedans.

En suivant et croisant quelques séries de vidéos tutorielles, j'ai un pseudojeu textuel en arène, avec une sélection aléatoire d'adversaire parmi 5, un gain d'or par combattant abattu, une boutique pour acheter des potions (seulement pour +health) et des armes (seulement +attack pour le moment). Là je tente de greffer un système d'xp et de gain de niveau automatique pour augmenter la santé et l'attaque.

Je n'utilise pas l'héritage, j'ai juste un bout de code de bestiaire, mais justement ne sachant pas l'utiliser encore, il est dans un coin. 

Là j'ai 5 class Lutin, Gobelin, Orc, Orgre, Troll, sur le modèle du Gobelin posté juste au dessus, copiée/collée avec des différences de vie, attaque... mais c'est tout.

----------


## Nattefrost

La solution copier-coller et changer les valeurs fonctionne mais utiliser des classes et l'héritage serait plus élégant et pratique à long terme. Si ça t'intéresse voilà un tuto très complet (et très long) sur la programmation orientée objet en python.

Je sors un peu du cadre technique mais ça dépend du temps que tu peux/veux y investir, est-ce qu'apprendre à programmer est plus important que de sortir un jeu dans ton esprit? (vraie question)

Y a tellement à apprendre que tu risque de te plonger dans des tutos mais ne pas avancer sur ton projet. Parfois faut y aller et produire quelque chose, même si c'est moche (aussi bien visuellement qu'au niveau du code) et qu'à terme on se rend compte que c'est une galère à maintenir.

Hier j'écoutais ça, tu connais ptetre cette émission (anglais seulement) http://www.roguelikeradio.com/2016/0...practices.html et un gars qui au départ n'a pas de background en programmation a fait un jeu (ultima ratio regum). Ce jeu c'est un seul fichier python de 400k lignes de code. N'importe quel programmeur avec du bon sens te dirai que c'est une hérésie qu'il faut le foutre au bucher (même son éditeur de texte plante parfois, fichier trop gros). Mais en attendant il a sorti son truc et en est content.

----------


## Tchey

Je connais bien ce projet, j'ai suivi le tout début du développement, j'avais posté le 6e ou 7e commentaire sur son ancien blog à l'époque ! Cependant, même s'il n'a pas de formation informatique, il a je crois un niveau maitrise ou doctorat dans un domaine mathématique et dans un article il confirme que ça l'a énormément aidé à "écrire dans sa tête" avant de passer au clavier. Moi, j'ai un bac littéraire.

400 000 lignes... Je préfère apprendre à trier dès maintenant.

Pour la vraie question, les deux ! Apprendre à programmer, et programmer un jeu, m'intéressent depuis "toujours", je n'ai simplement pas mis cet intérêt en avant dans ma vie, au profit d'autres trucs. 

J'avais parcouru le guide que tu suggères, en début d'année. A la fois intéressant et indigeste, comme la majorité des guides. Pour moi, dès que l'on commence à manipuler "en vrai", tout devient plus clair, et on est confronté aux différentes situations à mesure que l'on progresse. Je préfère toucher à tous les boutons et voir ce qui arrive, avant de lire le manuel. Heureusement que je ne travaille pas dans une usine de slim.

----------


## Nattefrost

Nous sommes donc dans le même cas, j'ai un bac L et je me suis orienté plus tard vers l'informatique, qui est aujourd'hui mon métier.
Pour les guides oui faut toujours essayer ce que les guides proposent, et même plus : c'est là que ça devient intéréssant en fait, quand tu essaie d'adapter un bout de tutoriel à ce que tu veux ou voudrais faire.

Si tu veux vraiment t'y mettre, apprend la POO, au fur et à mesure que tu apprend, met en application ces choses dans ton projet. A terme tu vas revenir sur certains bouts de code en disant que c'est mal codé et moche mais c'est comme ça qu'on progresse. Apprend l'héritage et sers-t-en dans ton projet, faut y voir une opportunité d'apprendre de nouveaux concepts.
Avec le temps t'aura de moins en moins besoin d'expérimenter avant de lire le manuel (mais ça reste important d'essayer) et certains passages de documentation couleront de source en les lisant.

----------


## ducon

Chope le bouquin (deuxième édition, fais gaffe) de Sébastien Chazallet, il est vraiment bien mais parfois plein de petites coquilles sans gravité.

----------


## Tchey

Question !

J'ai un dictionnaire avec des clefs et plusieurs valeurs par clefs.
Quatre armures tissu, cuir, carbone, plastacier, et un trois valeurs PROtection, ENCombrement, JeTonS. Les nombres sont au pif pour le moment, pas important.



```
armures =   {"tissu":{"PRO":2, "ENC":3, "JTS":20},
            "cuir":{"PRO":4, "ENC":6, "JTS":40},
            "carbone":{"PRO":8, "ENC":9, "JTS":80},
            "plastacier":{"PRO":16, "ENC":12, "JTS":160}}
```

Si je fais un simple print (armures) ça donne ça :



```
{'plastacier': {'ENC': 12, 'JTS': 160, 'PRO': 16}, 'cuir': {'ENC': 6, 'JTS': 40, 'PRO': 4}, 'carbone': {'ENC': 9, 'JTS': 80, 'PRO': 8}, 'tissu': {'ENC': 3, 'JTS': 20, 'PRO': 2}}
```

En cherchant pour avoir l'affichage sur plusieurs lignes, je n'ai trouvé qu'un résultat peu acceptable. 



```
    for armureType in armures:
        print (armureType)
        for y in armures[armureType]:
            print (y,':',armures[armureType][y])
```

Déjà, le dictionnaire ne prend pas l'ordre en compte, j'aime pas.
Ensuite c'est bien ligne par ligne, mais trop du coup.



```
plastacier
ENC : 12
JTS : 160
PRO : 16
cuir
ENC : 6
JTS : 40
PRO : 4
carbone
ENC : 9
JTS : 80
PRO : 8
tissu
ENC : 3
JTS : 20
PRO : 2
```

Comment je peux avoir un résultat qui s'affiche ainsi :



```
Tissu : ENC 3      PRO 2      JTS 20
Cuir : ENC 6      PRO 4      JTS 40
etc.
```

Question bonus, est-ce que le dictionnaire est une bonne option pour faire ça ?

----------


## ducon

Essaie OrderedDict dans un des modules qui va bien.
Ensuite, rien ne t’empêche de trier tes clés avec :



```
for armure in sorted(Armures.keys()):
  bla
```

En Python 3, tu peux utiliser end="" si tu veux continuer à écrire sur la même ligne.

----------


## Tchey

Merci,

Je parviens à plusieurs solutions, mais aucune ne me satisfait, car le résultat est laid, visuellement, avec des {'symboles': qui alourdissent la lecture. J'ai lu une quinzaine de pages en anglais et français sans pour le moment trouver ce qui me convient. Je pense maintenant qu'il ne faut pas que je cherche à imprimer le dictionnaire, mais plutôt à imprimer ligne par ligne.

Mon écran ressemble à ça pour le moment. C'est tout écrit "à la main", en fonction des dictionnaires d'armes et de serum...



Ah et aussi notamment, la première option adaptée d'un tuto me trie bien par key (carbone, cuir , plastacier, tissu), mais la seconde me sort une erreur que je ne comprends pas vraiment.

    for key, value in sorted(armures.items(), key=lambda item: (item[1], item[0])):
TypeError: unorderable types: dict() < dict()




```
print ("Tri par key")
for key in sorted(armures.keys()):
     print ("%s: %s" % (key, armures[key]))

print ('Tri par value:')
    for key, value in sorted(armures.items(), key=lambda item: (item[1], item[0])):
    print ("%s: %s" % (key, value))
```

A part ça, je pense que je suis bon pour m'inscrire sur un site spécialisé, diantre.

----------


## Nattefrost

Pour l'ordre tu a essayé OrderedDict comme le dit ducon?
>>>from collections import OrderedDict

Pour le choix d'objet un entier plutôt que le nom à entrer ce serait pas plus simple pour l'utilisateur ? ;p
Pour ton erreur ton modèle de donnée c'est quoi? Un dictionnaire avec des strings en clef ? Et en valeur y a quoi des listes, objets, d'autres dict?

----------


## ducon

Les valeurs sont des dictionnaires, c’est pour ça que ça merde.

----------


## Tchey

J'ai laissé de côté l'affichage de l'inventaire pour le moment, mais je prends note.

Question, est-ce que je fais bien mes sous-espèces, via l'héritage ?

J'ai par exemple

class Personnage: #tout personnage animé
  def blabla

class Monstre(Personnage): #tout monstre, qui est aussi un personnage animé
  def blabla

class Gobelin(Monstre): #un Gobelin qui est un Monstre qui...

class MortVivant(Monstre): 
  def blabla

class Necro(Gobelin): #un Necro qui est un Gobelin qui....
  def blabla

class Necro(MortVivant):
  def blabla

Est-ce que Necro est un problème ? Un nécro est Gobelin, l'autre est MortVivant, c'est "bien" ?

J'ai lu plusieurs articles du genre "héritage vs composition" mais pour le moment je n'ai pas bien compris la composition.

----------


## Blitz

C'est typiquement le problème avec quand il n'y a pas d'*héritage* multiple, on se retrouve potentiellement avec du code dupliqué (comme dans ton cas, deux entités morte-vivantes qui n'héritent pas de la même classe de base):


C'est le problème que tente de résoudre l'*Entity Component System* en utilisant la composition à fond:


Ces deux méthodes ont des avantages/inconvénients. A toi de voir laquelle te va le mieux.
L'ECS et ses variantes sont à la mode, mais pleins de jeux sont encore développés avec un système d'héritage classique et ça marche bien.

_source des images: Understanding Component-Entity-Systems_

----------


## Louck

La mode, surtout pour des gros projets, c'est le CES/ECS étant donné que tu pourras réutiliser les composants que tu as développés pour de futur projet. Mais cela implique de devoir prendre du temps à en préparer certaines et à les formaliser. Pour un débutant en code, cela risque d'être un peu compliqué.

Sinon poses toi la question de ce que représente la classe Necro: est ce que ce n'est qu'un changement de certains attributs, un sprite différent, etc... Car tu sembles utiliser la même classe pour hériter deux classes totalement différente.
Pour ca tu as une autre solution, c'est le pattern Decorator. En gros, tu ajoutes une liste de "modificateur" à ton entité: Après avoir mis à jour ton entité, tu fais appel à toutes ces modificateurs pour modifier certaines propriétés de ton objet (sprite différent, modification d'une attribut, etc...).

----------


## Nattefrost

Il y a de l'héritage multiple en python, cependant en tant que débutant je ne te conseille pas à ( Tchey )de s'y frotter, faut déjà avoir bien compris la POO classique. 
Je trouve la solution du décorateur que propose Louck plus élégante. Des articles sur les décorateurs python par ici http://sametmax.com/comprendre-les-d...-pas-partie-1/ et par là https://zestedesavoir.com/tutoriels/.../6-decorators/.

----------


## Tchey

Hm, merci.

D'façon j'en suis pas encore là, c'était juste une question "pour plus tard".

Là, je bloque depuis deux jours sur un truc. Je suppose que c'est lié à l'organisation de mon code, je dois "co-importer" des modules, mais si je le fais, ça ne marche pas, et si je ne le fais pas, bah ça ne marche pas.
J'ai essentiellement 3 modules.py

mutantversus.py avec le coeur du jeu et les "lieux" avec des def go_...():
avatar.py avec le personnage et les actions possibles avec des def do_...():
bestiary.py avec les bestioles 

Le soucis est que certains go_ vont vers des do_ et que certains do_ vont vers des go_ et je ne sais pas comment résoudre ça.

J'ai ouvert un github pour y voir plus clair. La branche Master est désuète pour le moment. La branche alpha c'était un test de pull car je ne connais pas GitHub.
C'est la branch PreAlpha qui est "à jour", plus ou moins. 
Y'a plein de bouts en commentaire car je fais des essais sur différents bidules, et c'est probablement plein de fautes ou de trucs qui cloche, m'enfin, j'ai une marge de progression comme ça !

http://github.com/Jeux1d100/MutantVersus/tree/PreAlpha

J'ai ouvert un reddit aussi, où j'ai posé des questions équivalentes : http://www.reddit.com/r/learnpython/..._organization/

Si vous voulez jeter un oeil... Si ça se trouve c'est tout con, mais comme je suis tout con moi-même...

----------


## Nattefrost

Quand tu as un probleme, si tu peux copier coller l'erreur que l'interpreteur te crache au visage ça peut aider parfois  ::P: 

Là j'ai telechargé ta branche preAlpha et si je fais 

```
% python3 mutantversus.py
```

 et que je suis les instructions, je mange cette erreur : 


```
Traceback (most recent call last):
  File "mutantversus.py", line 306, in <module>
    main()
  File "mutantversus.py", line 52, in main
    avatar_creation_name()
  File "mutantversus.py", line 70, in avatar_creation_name
    go_hub()
  File "mutantversus.py", line 123, in go_hub
    select_challenger()
  File "mutantversus.py", line 169, in select_challenger
    go_arena()
  File "mutantversus.py", line 179, in go_arena
    print ("            %s (%i/%i)   vs   %s (%i/%i)" % (avatar_active.name, avatar_active.health, avatar_active.maxhealth, challenger.name, challenger.health, challenger.maxhealth))
AttributeError: 'tuple' object has no attribute 'name'
```

C'est bien ça le soucis ?
Si oui j'ai pas l'impression que ce soit un problème d'import, plutot que ta structure de donnée est un tuple et pas un objet donc la notation object.attribute ne fonctionne pas.

----------


## Tchey

Non, j'ai cette erreur seulement "parfois", faudra aussi que je regarde pourquoi...

J'ai mis à jour PreAlpha.

Mon soucis, par exemple ici :



```
note : *aide* ouvre une page d'aide.

  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                           
      Vous êtes kILO, le zum' du jour.                                       
                                                                           
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                           
      a - combattre dans l'arène                                           
      b - entrer dans la boutique                                          
      m - développer une mutation                                          
      x - préparer une expédition                                          
      i - accéder à l'inventaire                                           
      s - voir votre statut                                                  
                                                                           
      q - quitter MutantVersus                                             
                                                                           
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   Votre choix -> X
   Appuyez sur Entrée pour continuer...
A l'aventure ouep
Traceback (most recent call last):
  File "mutantversus.py", line 323, in <module>
    main()
  File "mutantversus.py", line 53, in main
    avatar_creation_name()
  File "mutantversus.py", line 71, in avatar_creation_name
    go_hub()
  File "mutantversus.py", line 124, in go_hub
    go_expedition_prepare()
  File "mutantversus.py", line 270, in go_expedition_prepare
    expedition.ExpeditionPrepare.expedition_prepare()
  File "/home/tchey/Prog/Python/expedition.py", line 10, in expedition_prepare
    go_hub()
NameError: name 'go_hub' is not defined
tchey@tchey-NEW ~/Prog/Python $
```

dans mutantversus.py je fais 
import expedition

car quand je fais mon choix "x" ça me fait aller dans mon module expedition.py



```
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

class ExpeditionPrepare:
    def expedition_prepare():
        print ("A l'aventure ouep")
        time.sleep(2)
        go_hub()
```

Une fois que l'expédition est terminée, elle doit me mener à go_hub() qui se trouve dans mutantversus.py mais non, ça plante, parce que je ne sais pas comment "revenir".

 Si je fais import mutantversus au début, puis mutantversus.go_hub() le programme plante à l'expédition.



```
   Votre choix -> x
   Appuyez sur Entrée pour continuer...
Traceback (most recent call last):
  File "mutantversus.py", line 12, in <module>
    import expedition
  File "/home/tchey/Prog/Python/expedition.py", line 4, in <module>
    import mutantversus
  File "/home/tchey/Prog/Python/mutantversus.py", line 323, in <module>
    main()
  File "/home/tchey/Prog/Python/mutantversus.py", line 53, in main
    avatar_creation_name()
  File "/home/tchey/Prog/Python/mutantversus.py", line 71, in avatar_creation_name
    go_hub()
  File "/home/tchey/Prog/Python/mutantversus.py", line 124, in go_hub
    go_expedition_prepare()
  File "/home/tchey/Prog/Python/mutantversus.py", line 270, in go_expedition_prepare
    expedition.ExpeditionPrepare.expedition_prepare()
AttributeError: 'module' object has no attribute 'ExpeditionPrepare'
```

J'ai un message similaire pour go_arena / do_attack par exemple, ou pour tout autre "croisement de module".

----------


## Nattefrost

Ton fichier s'appelle expedition, ta classe s'appelle ExpeditionPrepare, il faut l'instancier (tu n'a pas mis le constructeur). D'ailleurs si tu n'a qu'une fonction dans une classe, c'est probablement qu'une classe n'est pas nécéssaire, une bête fonction ferait l'affaire. A voir si tu vas y rajouter des choses.


Dans ton expedition.py tu n'importe pas mutantversus, la fonction go_hub() en fait partie.

----------


## Tchey

Oui, expedition.py est amenée à évoluer. J'ai fait ce module pour illustrer rapidement mon soucis principalement.

Et justement par rapport à ce que tu dis :




> Dans ton expedition.py t*u n'importe pas mutantversus*, la fonction go_hub() en fait partie.


Comment faire ? car :




> Une fois que l'expédition est terminée, elle doit me mener à go_hub() qui se trouve dans mutantversus.py mais non, ça plante, parce que je ne sais pas comment "revenir".
> 
> Si je fais import mutantversus au début, puis mutantversus.go_hub() le programme plante à l'expédition.


Où est-ce que je dois importer mutantversus dans expedition.py pour que ça ne plante pas ?

J'ai aussi essayé ça : 



```
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# import mutantversus #si je le place là ça plante après avoir choisi l'option "x"
import time

class ExpeditionPrepare:
    def expedition_prepare():
        from mutantversus import go_hub
        print ("A l'aventure ouep")
        time.sleep(2)
        mutantversus.go_hub()
```

----------


## ducon

C’est normal s’il n’y a ni __new__ ni __init__ déclarées dans ta classe ?

----------


## Nattefrost

C'est une classe dite statique, normalement ça fonctionne


```
>>> class Greeter:
>>>     def greet():
>>>         print("Hello")
>>> Greeter.greet()
Hello
```

----------


## Tchey

Hm, ça ne répond pas à mon questionnement, ou alors je suis complètement à côté de la plaque, ou alors je m'exprime très mal.

expedition.py



```
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# import mutantversus => ça ne fonctionne pas, le programme retourne au tout début
import time

class ExpeditionPrepare:
    def expedition_prepare():
        # from mutantversus import go_hub => ça ne fonctionne pas non plus
        print ("A l'aventure ouep")
        time.sleep(2)
        mutantversus.go_hub()
```

version tronquée de mutantversus.py



```
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
import random
import time

import avatar
import bestiary
import equipment
import expedition

def go_hub():
    os.system("clear")
    print ("note : *aide* ouvre une page d'aide.\n")
    print ("  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print ("                                                                           ")
    print ("      Vous êtes %s, le zum' du jour.                                       " % (ego.name))
    print ("                                                                           ")
    print ("  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print ("                                                                           ")
    print ("      a - combattre dans l'arène                                           ")
    print ("      b - entrer dans la boutique                                          ")
    print ("      m - développer une mutation                                          ")
    print ("      x - préparer une expédition                                          ")
    print ("      i - accéder à l'inventaire                                           ")
    print ("      s - voir votre statut                                                ")
    print ("                                                                           ")
    print ("      q - quitter MutantVersus                                             ")
    print ("                                                                           ")
    print ("  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")
    option = input(Colour.DARKCYAN + "   Votre choix -> " + Colour.END).lower()
    if option == "a":
        select_challenger()
    elif option == "b":
        go_store()
    elif option == "m":
        go_mutation_prepare()
    elif option == "x":
        go_expedition_prepare()
    elif option == "i":
        go_inventory()
    elif option == "s":
        go_stats()
    elif option =="aide":
        go_help()
    elif option == "q":
        sys.exit()
    else:
        print("Ce choix n'est pas valide")
        go_hub()
```

Quand je choisi "x" je pars dans expedition.py, puis depuis expedition.py je suis sensé revenir vers mutantversus.py mais je ne sais pas comment faire.
Je prends l'expédition en exemple, mais j'ai un soucis similaire pour plusieurs autres éléments.

Tout le code est sur mon github branch PreAlpha : http://github.com/Jeux1d100/MutantVersus/tree/PreAlpha

----------


## Nattefrost

Ha mais ça y est je crois que j'ai fait tilt grâce à ta phrase.



> # import mutantversus => ça ne fonctionne pas, le programme retourne au tout début


Quand tu fais un import en python, le code que tu importe est éxécuté. A la fin de mutantversus.py tu as un main() donc au moment de l'import ce main est éxécuté et tu 'retourne au tout début'.
Pour éviter ce comportement mets l'éxécution de main() comme ceci : 


```
if __name__ == '__main__':
	main()
```

Cela n'éxécute le main() que dans le cas d'un appel depuis la command-line : python3 mutantversus.py mais pas dans le cas d'un import.

----------


## Tchey

Pas trop touché à la chose dernièrement, mais c'truc m'a bien aidé : 




> if __name__ == '__main__':
> 	main()


Je me suis remis un peu à tkinter, et je coince. Je veux des "onglets" qui affichent les différentes pages de l'interface (boutique, arène, feuille de perso...). J'ai posté sur openclassrooms : http://openclassrooms.com/forum/suje...fficher-page-2
Pour le moment je n'ai pas trouvé comment faire malgré les conseils et indications des gens par là-bas.

Je plante autant que mon code... M'faudrait un prof derrière mon épaule, mais j'ai pas ça.

----------


## Nattefrost

Pour avoir plusieurs onglets ils faut utiliser ttk qui est une librairie qui contient des widgets rajoutés ne faisant pas partie du set natif de widgets de tcl/tk.


```
from tkinter import ttk
```

(valable en python3 uniquement, en python2 c'est pas le même namespace)

Ensuite utiliser le widget notebook de ttk http://infohost.nmt.edu/tcc/help/pub...-Notebook.html
Ca permet d'avoir des onglets et de naviguer de l'un à l'autre


L'idée c'est que chaque onglet contient une Frame dans laquelle ben tu mets ce que tu veux, c'est une frame comme une autre quoi  ::):

----------


## Tchey

C'est un peu l'équivalent de pprint, pretty print, pour tkinter, il semble. Mouais. ttk fait certes du "plus joli", sauf qu'il n'a pas toutes les options de tkinter.

Je ne veux pas faire  des "vrais onglets", je veux seulement une série de boutons en haut, qui font chacun paraitre une frame différente. Jusqu'à présent, je suis perdu dans comment y parvenir, malgré les différentes exemples trouvés sur internet. J'arrive à afficher une frameA avec un bouton pour aller dans une frameB, mais pas à avoir ma ligne de boutons.



Là j'ai mes boutons en haut, et je veux que la grande zone grise affiche la frame correspondante. Pour le moment j'en suis à un code confus qui ne fonctionne pas. 



```
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

coulbg = "dark grey"
coultxt = "black"
winx = "1024"
winy = "576"

import tkinter
from tkinter import ttk
from tkinter.filedialog import *

class InterGeneric(tkinter.Tk): # this class manages the pages, and the upper part of the interface with the tabs to swith pages

    def __init__(self, *args, **kwargs):
        tkinter.Tk.__init__(self, *args, **kwargs)
        self.minsize(width=winx, height=winy)
        self.grid()
        self.resizable(True, True)
        container = tkinter.Frame(self)
        container.grid()

        self.frames = {}
        for F in (PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            frame.grid(row=1, column=0, sticky="nsew")

        self.show_frame("PageOne", self)

    def show_frame(self, page_name, controller):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()
        self.update()
        self.geometry(self.geometry())
        self.controller = controller
        self.columnconfigure(0, weight=6)
        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)

        frame_up = tkinter.Frame(self, bg="green", height=50, borderwidth=0)  # upper part of the window, with all buttons in a green frame
        frame_up.grid(column=0, row=0, sticky="we")

        but_cfg = dict(borderwidth=1, fg='grey', bg='black', activeforeground='grey99', activebackground='black')

        but_one = Button(frame_up, text="-> Page One", command=lambda: controller.show_frame("PageOne"), **but_cfg)
        but_one.grid(column=0, row=0, padx=10, pady=10, sticky="nsew")  # button to go to PageOne

        but_two = Button(frame_up, text="-> Page Two", command=lambda: controller.show_frame("PageTwo"), **but_cfg)
        but_two.grid(column=1, row=0, padx=10, pady=10, sticky="nsew")  # button to go to PageTwo


        frame_upq = tkinter.Frame(self, bg="purple", height=50, borderwidth=0)  # frame top right with Quit button
        frame_upq.grid(column=2, row=0, sticky="we")

        but_quitter = Button(frame_upq, text="-> Quit", command=self.quit, **but_cfg)
        but_quitter.grid(column=0, row=0, padx=10, pady=10, sticky="e") # button to quit

        for i in range(2):
            frame_up.grid_columnconfigure(i, weight=1)
        frame_up.grid_rowconfigure(0, weight=1)

        frame_upq.grid_columnconfigure(0, weight=1)
        frame_upq.grid_rowconfigure(0, weight=1)

class PageOne(tkinter.Frame):

    def __init__(self, parent, controller):
        tkinter.Frame.__init__(self, parent)
        self.controller = controller
        frame_pageone = tkinter.Frame(self, bg="blue", height=200)  # should be PageOne full of blue

class PageTwo(tkinter.Frame):

    def __init__(self, parent, controller):
        tkinter.Frame.__init__(self, parent)
        self.controller = controller
        frame_pagetwo = tkinter.Frame(self, bg="red", height=200)  # should be PageTwo full of red

if __name__ == "__main__":
    app = InterGeneric()
    app.title("DraDro_160524.01")
    app.mainloop()
```

----------


## Nattefrost

ttk a toutes les options de tkinter (si tu parle des couleurs notamment) mais tu ne peux pas les set comme ceci :


```
b = tk.Button(root, text='COUCOU TCHEY',bg='black',fg='yellow').pack()
```

A la place il faut creer des styles ttk qui s'appliquent sur les widgets que tu veux. On perd en simplicite mais c'est plus propre. J'ai tres peu utilise les styles donc je me garderai de te donner des conseils sur comment les utiliser. http://infohost.nmt.edu/tcc/help/pub...yle-layer.html

----------


## Tchey

Salut ici,

Je bute sur un truc. 

J'ai une classe Container qui gère l'inventaire, avec .add et .remove notamment. Je cherche à faire des bestioles avec des morceaux, composées de pattes, trompes, becs..., et pour gérer ça je pense faire comme un équipement dans un JDR classique, sauf que arme, armure... c'est des membres et organes.

Pour une bestiole, ou le joueur, ça va, ça marche. Mais quand je veux plusieurs bestioles chacune avec son "inventaire", je ne sais pas comment faire.



```
class Fauna(Character):
    def __init__(self, name, desc, nerf, fluide, chimie, gaz):
        Character.__init__(self, name)

        self.name = name
        self.desc = desc
```

Mes trois bestioles avec chacune un inventaire de "composants"



```
muscae = Fauna("Muscae", "* Une mouche grosse comme une main.", 1, 1, 1, 1)
muscae.compo = Container("", "")
muscae.compo.add(patte_at)
muscae.compo.add(patte_at)
muscae.compo.add(patte_pt)
muscae.compo.add(patte_pt)

rodentia = Fauna("Rodentia", "* Un lapin aux oreilles percées.", 2, 1, 1, 1)
rodentia.compo = Container("", "")
rodentia.compo.add(patte_at)
rodentia.compo.add(patte_at)
rodentia.compo.add(patte_pt)
rodentia.compo.add(patte_pt)

caninae = Fauna("Caninae", "* Un chien sauvage, affaibli par la faim et la maladie.", 2, 2, 1, 1)
caninae.compo = Container("", "")
caninae.compo.add(patte_at)
caninae.compo.add(patte_at)
caninae.compo.add(patte_pt)
caninae.compo.add(patte_pt)
caninae.compo.add(queue_courte)

FAUNA = (muscae, rodentia, caninae)
```

Ensuite je veux afficher une sorte de bestiaire



```
for i in FAUNA: 
    print ("   {} ".format(i.name) + Colour.PURPLE + "{}".format(i.desc) + Colour.END)
    print ("      matorg : " + Colour.RED + "{}".format(i.matorg) + Colour.END + " (n{} f{} c{} g{})".format(i.nerf, i.fluide, i.chimie, i.gaz))
    print ("")
    for name, item in i.compo:
        print ("   compo : ", end="")
        print (Colour.DCYAN + "[{} x{}] ".format(item.name, item.qtt) + Colour.END, end="")
```

Ça me sort quelque chose que je ne comprends pas. Le total des membres ou organes ne correspond pas, et je ne sais pas "comment ça compte" pour arriver à ça.



```
 Muscae * Une mouche grosse comme une main.
      matorg : 5 (n1 f1 c1 g1)
   compo : [Patte At x4]    compo : [Patte Pt x4] 

   Rodentia * Un lapin aux oreilles percées.
      matorg : 8 (n2 f1 c1 g1)
   compo : [Patte At x4]    compo : [Patte Pt x4] 

   Caninae * Un chien sauvage, affaibli par la faim et la maladie.
      matorg : 11 (n2 f2 c1 g1)
   compo : [Patte At x4]    compo : [Queue courte x1]    compo : [Patte Pt x4]
```

Du coup, comment je dois procéder, et est-ce une "bonne" façon de gérer la composition des bestioles (dans l'idée de les démembrer, de faire des mutants, etc), ou alors pas du tout arrêtons le massacre ou autre ?

Merci d'avoir lu

----------


## Patate

Je connais pas trop les containers en python, mais compo.qtt devrais te donner le nombre de membres. Et non item.qtt qui lui est un des membres de compo. Maintenant pour dissocier les types de membres pour les compter je ne sais pas trop en python. J'espère ne pas me tromper sur la question.

----------


## Hideo

Ca fait longtemps que j'ai pas regardé du python mais ce que dit patate me parait cohérent.

Tu utilises quoi pour développer, un IDE ou un éditeur de texte et tu compiles a la main ?
Pour ce genre de cas, c'est souvent très utile de pouvoir utiliser les BreakPoint qui te permettent de suivre pas à pas l’exécution de ton programme et d'avoir la valeur de toutes tes variables à l'instant T.
Très utile dans ces cas la ou une variable ne représente pas toujours ce que l'on pense.

----------


## cosmicsoap

Plop !
Je suis une quiche en prog (niveau de départ -42) et j'ai commencé à bouffer des tutos pour en apprendre les bases.

Alors autant les boucles et les tests ça va mais les fonctions et ces foutues variables globales ou locales il y a un truc que je ne chope pas du tout.

Quand on est dans une fonction, pour faire ressortir les variables on peut utiliser global (mais c'est à éviter) ou se servir de variables temporaires.

Comme je ne parviens pas à mes fins je me suis fabriqué un exercice simple avec une histoire de pommes, en dur ça donne ça :



```
# toto a un panier qu'il rempli de pommes
# lorsqu'il a 10 pommes il vide son panier dans une caisse et recommence
# il arrête de remplir son panier lorsqu'il a 10 caisses de pommes

panier = 0
caisse = 0
pommes = 0

# boucle globale
print("toto apple")
while pommes < 100:
    # remplissage du panier
    # si le panier a dix pommes toto met les pommes dans une caisse et vide le panier
    if panier >= 10:
        caisse += 1
        pommes = pommes + panier
        panier = 0
        print("toto a rempli une caisse, il y a désormais", caisse, "caisses de pommes")
        print("il y a", panier, "pommes dans le panier")

    # sinon on met une pomme dans le panier
    else:
        panier += 1
        print("toto cueille une pomme, son panier contient désormais", panier, "pommes")

# on termine lorsque toto a 100 pommes dans 10 caisses
print("C'est fini, Toto a", pommes, "pommes dans ", caisse, "caisses")
```

Jusque là tout va bien.
Mais si je veux utiliser des fonctions ça me spawn des erreurs (*NameError: name 'pommes_temp' is not defined*), ce qui signifie que je n'ai à priori pas compris quelque chose.

exemple :


```
# toto a un panier qu'il rempli de pommes
# lorsqu'il a 10 pommes il vide son panier dans une caisse et recommence
# il arrête de remplir son panier lorsqu'il a 10 caisses de pommes

# l'idée est d'utiliser des fonctions pour otenir le résultat

panier = 0
caisse = 0
pommes = 0

def panier_plein():
    # fonction qui ajoute des pommes au panier et qui vérifie qu'il n'y en a pas trop
    if panier >= 10:
        caisse_temp = caisse + 1
        pommes_temp = pommes + panier
        panier_temp = 0
        print("toto a rempli une caisse, il y a désormais", caisse, "caisses de pommes")
        print("il y a", panier, "pommes dans le panier")
        # on renvoie les variables pour les utiliser
        return caisse_temp, pommes_temp, panier_temp
    # si le panier n'est pas plein on va remplir le panier avec une autre fonction
    else:
        remplissage()

def remplissage():
    panier_temp = panier +1
    print("toto cueille une pomme, son panier contient désormais", panier, "pommes")
    # on renvoie la variable
    return panier_temp

# boucle globale
print("toto apple 2 - avec fonction")
while pommes < 100:
    panier_plein()
    # on intègre l'ensemble des variables retournées
    pommes = pommes_temp
    panier = panier_temp
    caisse = caisse_temp

# on termine lorsque toto a 100 pommes dans 10 caisses
print("C'est fini, Toto a", pommes, "pommes dans ", caisse, "caisses")
```

Bref, c'est pas gagné.
Help me !  ::cry::

----------


## ducon

Pourquoi utiliser des fonctions ?
Ton premier script marche, non ?

----------


## cosmicsoap

Et bien pour apprendre !

D'autant qu'une fonction sert à accomplir des tâches répétitives.
Une fois que j'aurais chopé le coup,je pourrais demander à Toto de ramasser toutes sortes de fruits et de légumes afin de l'exploiter comme un toto !
 ::rolleyes::

----------


## madgic

Tu retournes des valeurs mais tu ne les récupères pas.

Quand tu fais

    panier_plein()
    # on intègre l'ensemble des variables retournées
    pommes = pommes_temp
    panier = panier_temp
    caisse = caisse_temp

Tu ne récupère pas les valeurs renvoyé panier_plein et pommes_temp est inconnu puisqu'elle existe que dans ta fonction.

Pour récupéré les valeurs, il faut faire :

caisse, pommes, panier = panier_plein()

----------


## cosmicsoap

Ah ?  ::blink:: 
*bruit de cerveau qui fume*

Ok donc, si je comprends bien on applique une fonction à quelque chose et pour récup la variable c'est de la forme


```
ma_variable = ma_super_fonction()
```

C'est bien ça ?
 ::huh::

----------


## madgic

> Ah ? 
> *bruit de cerveau qui fume*
> 
> Ok donc, si je comprends bien on applique une fonction à quelque chose et pour récup la variable c'est de la forme
> 
> 
> ```
> ma_variable = ma_super_fonction()
> ```
> ...


Oui c'est ça. Et dans ta fonction tu retournes la variable en faisant un return + le nom de ta variable (ou une valeur)

Et tu peux mettre des paramètres à tes fonctions



```
def sum(nb):
    nb = nb + 1
    return nb

toto = 10
toto = sum(toto)
```

Tu déclares une variable, toto, et tu l'initialise à 10 puis tu la passe en paramètre à sum. Dans sum tu augmente de 1 la variable passée en paramètres puis tu la retourne et tu la récupère. Maintenant toto vaut 11.

----------


## cosmicsoap

Quand je pense que je croyais naïvement que je pouvais me servir d'une fonction comme une boite magique  :^_^: 

Faut que je travaille ça.
Thx.
 :;):

----------

