Un sim city pas comme les autres

Alias l'IA qui va gérer nos vies :)

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut à tous !

Je me propose de rédiger un ""petit"" atelier (sur le concept du moins, pas niveau code) qui traite de la gestion d'une ville.
Par là je n'entends pas faire un sim city avec interface graphique, et tout le bousin, mais un petit programme console qui pourra afficher l'évolution de la dite ville.

L'intérêt

Pouvoir aborder avec un sujet simple le concept d'intelligence artificielle, et bien sûr, s'entrainer en POO !

Le concept

Créer pléthore de classe sans utilité pour gérer notre ville.

Cela sous-entend donc :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ville (nom)
|-- rue (nom, taille)
|-- |-- bâtiment (nom, localisation)
|-- |-- |-- habitat
|-- |-- |-- entreprise
|-- personne (nom prénom âge)
|-- |-- habitude (nom, à faire tous les X, action)
|-- |-- interaction
|-- |-- centre d'intérêt
|-- temps
|-- |-- événement
|-- objet (nom)
|-- |-- produit (prix)
|-- behavior tree (ou arbre de comportement)
|-- |-- noeud (sélection par importance de l'ordre d'exécution des enfants)
|-- |-- séquence (exécution des enfants dans l'ordre, gestion des retours (réussite, échec, en cours))
|-- |-- feuille (nom, action)

Effectivement ça représente un sacré packet de classes.

Vous pouvez tout à fait ne pas aimer ma façon de voir les choses et concevoir le truc autrement :)

Les explications

Voici un peu comment j'ai procédé : je suis parti sur un ensemble (ici la ville), puis j'y ai ajouté tous les sous ensembles (c'est à dire, rue, bâtiments (et tous les sous types), personnes (comportement …)), puis j'ai "fait" le temps, car c'est quand même important d'avoir un temps pour organiser nos événements !

Ensuite, j'ai rajouté les méthodes d'ajout de sous ensemble à chaque classe, c'est à dire que j'ai ajouté à la classe City la méthode add_building(), et de même pour les bâtiments et les personnes (qui rappelons le, vont avoir un comportement et une liste d'événements)

J'ai aussi ajouté les différents getter (qui prennent ici en argument des string) sur chaque classe. De cette manière il est possible de récupérer un sous ensemble d'une classe (comme une rue dans la ville) en connaissant uniquement son nom.

Ensuite, j'ai commencé le coeur du projet, c'est à dire les méthodes gérant "l'évolution" comme la gestion du capital d'une entreprise, ou de son stock (c'est cette partie qui est selon moi la plus longue mais de loin la plus intéressante !). Ici c'est à vous d'imaginer ce qu'il doit se passer !

Enfin, j'ai simplement tout raccordé par le biais des méthodes evolve de chaque classe :)

Pour ce qui est du behavior tree :

je me suis pas mal aidé de ceci : http://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php

J'ai choisi d'implémenter mes Node avec une fonction play() qui se charge de lancer une action ou d'appeler une autre méthode play() d'un de ces enfants, et ce grâce à une liste de priorité

Mes Leaf héritent de Node et ne peuvent pas avoir d'enfants (donc faut faire gaffe et réécrire les méthodes faisant appel à des enfants pour les bloquer).

Enfin mes Sequences sont aussi des héritiés de Node, mais ici la méthode play appelle ses enfants dans l'ordre.

Les méthodes play() retournent toutes le retour de la feuille qui a été appelée (c'est toujours une feuille qui est appelée si on y regarde bien)

Au boulot !

Personnellement, voici la liste des méthodes que j'ai implémenté pour chaque classe :

Node: get_child_by_name, add_child, remove_child_by_name, play (pour activer le noeud), to_string

Sequence (hérite de noeud) : play (appelle next), next (itère sur les enfants et les exécute)

Leaf (hérite de noeud) : play (retourne un statut spécifique (temporaire))

BehaviorTree : add_child, remove_child_by_name, get_child_by_name, play ; a un attribut tree (qui est un Node)

Interaction : empty (temporaire)

HumanInteraction (hérite d'interaction) : get_participants

HumanObjectInteraction (hérite d'interaction) : empty (temporaire)

Interest : attributs (name, intensity)

Person : attributs (name, surname, age, interests, scheduled events, events stack, behavior tree), handle_event (pour ajouter un événement sur la event stack, qui sera traitée par le behavior tree), add_scheduled_event (pour ajouter un événement programmé), evolve (permet de traiter tous les scheduled events, et appelle play() du behavior tree en lui donnant la event stack)

Time : next (ajoute 1 au temps), attributs (time)

Condition : attributs (key, value, importance)

TriggerEvent : check (vérifie grâce au time s'il doit se lancer ou non), should_last (vérifie s'il doit durer plus que 1 tour), trigger != untrigger (active ou désactive le trigger)

Action : attributs (name)

Habit : check (appelle le check() de son trigger event), start, stop. Peut être lancé plusieurs fois (avec un seul temps de base, donc il faut gérer le concept de jours !)

Event (hérite de Habit) : même méthodes, mais ne peut être appelé qu'une seule fois

Product : attributs (name, price, quality)

QuantifiedProduct (hérite de product) : mêmes attributs, avec la quantité en plus. construct_from_product (prend en paramètre un product et une quantité)

Building : attributs (name, interests_involved), can_interest (prend en paramètre une liste d'intérêts et retourne Vrai ou Faux), evolve (fait "évoluer" le bâtiment)

House (hérite de building) : mêmes attributs, avec un attribut on_street en plus et persons_living_in (liste), quit_the_house (prend une personne en attribut et l'enlève de la liste des habitants actuels (mais la personne vit toujours dedans, elle ne fait qu'en sortir)), has habitant (prend un name en attribut et retourne Vrai ou Faux), get habitant by name, add habitant, remove habitant by name, evolve (fait évoluer la maison)

CommercialBuilding (hérite de building) : attributs (le capital, les produits disponibles, le chef, les employés, hire somebody (pour embaucher quelqu'un), is in deficit (Vrai ou Faux), has product name (prend un name en argument), buy (product, quantity), evolve (vérifie le déficit, achète s'il le faut, embauche …)

Street : attributs (name, size, connected to, persons in, buildings), add person, remove person from name, get building by name, remove building by name, add building, connect to (prend une autre rue en paramètre), evolve (pour faire évoluer la rue)

City : attributs (name, size, streets), add_clock (on ajoute une gestion du temps), has building name / type, has building name / type on street, get street by name, add street, evolve (appelle toutes les méthodes evolve de ses rues)

Concrètement

Pour le moment j'ai une sortie qui ressemble à ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Clara is starting ...
In the city SmallVille :
  Baxbaxwalanuksiwe Street's is connected to the streets Ardakaniz Street's, Qames Street's.
  Ardakaniz Street's is connected to Baxbaxwalanuksiwe Street's.
  Qames Street's is connected to Baxbaxwalanuksiwe Street's.

- - - - - - - - - - 

Evolving - Time is 0
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe played {'status': 0, 'from': 'eat'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 1
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe played {'status': 0, 'from': 'sleep'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 2
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe played {'status': 0, 'from': 'wake up'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 3
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe started 'going to see the boss'
               Patrick Doe played {'status': 1, 'from': 'go to work'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 4
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe started 'going to see the boss'
               Patrick Doe played {'status': 0, 'from': 'eat'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 5
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe played {'status': 0, 'from': 'sleep'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving
- - - - - - - - - - 
Evolving - Time is 6
SmallVille is evolving
   Baxbaxwalanuksiwe Street's is evolving
       A house Building's is evolving
           Patrick Doe is evolving
               Patrick Doe played {'status': 0, 'from': 'wake up'} from his behavior tree
   Ardakaniz Street's is evolving
   Qames Street's is evolving

Avec ce tout petit code de test :) :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
__author__ = 'Folaefolc'
"""
Code par Folaefolc
Licence MIT
"""

import sys
import time
import core


def print_city_streets_and_connections(city: core.town.city.City):
    print("In the city {} :".format(city))
    for street in city.streets:
        print("\t{} is connected".format(street), end=' ')
        if not len(street.connections):
            print("to no other streets")
            continue
        elif len(street.connections) == 1:
            print("to", end=' ')
        else:
            print("to the streets", end=' ')
        for i in range(len(street.connections)):
            print("{}".format(street.connections[i]), end='')
            if i < len(street.connections) - 1:
                print(",", end=' ')
            else:
                print(".")


def main(*args):
    street1 = "Baxbaxwalanuksiwe"
    street2 = "Ardakaniz"
    street3 = "Qames"
    print(core.constants.NAME + " is starting ...")

    the_time = core.life.time.Time()

    a_person = core.life.person.Person("Patrick", "Doe", 0)
    a_person.get_behavior_tree()\
        .add_child(
            core.life.behavior_tree.Sequence("sequence", 0.4)
        ).get_child_by_name(
            "sequence"
        ).add_child(
            core.life.behavior_tree.Leaf("eat")
        ).add_child(
            core.life.behavior_tree.Leaf("sleep")
        ).add_child(
            core.life.behavior_tree.Leaf("wake up")
        ).add_child(
            core.life.behavior_tree.Leaf("go to work")
        )
    a_person.get_behavior_tree()\
        .add_child(
            core.life.behavior_tree.Node("node", 1.0)
        ).get_child_by_name(
            "node"
        ).add_child(
            core.life.behavior_tree.Leaf("first work with high priority", 0.8)
        ).add_child(
            core.life.behavior_tree.Leaf("second work with low priority", 0.1)
        ).add_child(
            core.life.behavior_tree.Leaf("third work with normal priority", 0.5)
        )
    a_person.add_scheduled_event(
        core.life.time.Event(
            "going to see the boss",
            core.life.time.TriggerEvent(
                at=0,
                cond=[
                    core.life.time.Condition("time", 3, 0.5),
                    core.life.time.Condition("end_time", 5, 0.5)
                ]
            ),
            core.life.time.Action(
                name="moving and going to see the boss -action"
            )
        )
    )

    city = core.town.city.City("SmallVille")
    city.add_clock(the_time)\
        .add_street(
            core.town.street.Street(street1)
        ).add_street(
            core.town.street.Street(street2)
        ).add_street(
            core.town.street.Street(street3)
        )
    city.get_street_by_name(street1)\
        .connect_to(city.get_street_by_name(street2))\
        .connect_to(city.get_street_by_name(street3))
    city.get_street_by_name(street1)\
        .add(core.town.buildings.House(
            "A house",
            city.get_street_by_name(street1)
        ))
    city.get_street_by_name(street1)\
        .get_buildind_by_name("A house")\
        .add_settler(a_person)

    print_city_streets_and_connections(city)
    print("\n" + "- " * 10 + "\n")

    while True:
        print("Evolving - Time is {}".format(the_time))
        city.evolve()
        the_time.next()
        time.sleep(0.5)
        print("- " * 10)


if __name__ == '__main__':
    main(*sys.argv[1:] if sys.argv[1:] else [])

Pour participer on fait comment ?

Vous pouvez proposer vos propres classes, vision de l'atelier, code … etc !

Pour les intéressés le code est ici : https://github.com/Loodoor/Clara !

Soyez indulgent c'est mon premier atelier, et je voyais pas trop comment rédiger mieux que ça

Édité par Cithoran

Ma chaine YouTube ! | Seventh, un micro langage communautaire ! | Mon projet : Unamed (en pleine reprogrammation en C++11/SFML2.4) | Mon tuto sur Pygame !

+5 -0

Cette réponse a aidé l'auteur du sujet

Un peu de formatage quand tu présentes les méthodes serait le bienvenu, là ça forme juste un gros paquet illisible.

Sinon j'aime bien l'idée mais je pense que tu pourrais procéder plus doucement. Là tu passes de l'énoncé à la solution d'un seul coup. Une approche pas-à-pas pourrait gagner en attrait et tu devrais en plus te forcer à expliciter la logique de ton raisonnement et donc potentiellement y trouver/corriger des erreurs. :)

Édité par Poliorcetics

Hey, moi c'est polio, et je te souhaite une bonne lecture :p !

+7 -0

Même remarque que pour le Javaquarium, quand le poids des visiteurs se fera trop sentir, pensez à aux modèles à composants.

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+3 -0

Cette réponse a aidé l'auteur du sujet

Quel est le rapport avec Pen of Chaos ? Lui, il fait des aventures débiles pas de la programmation.

Blague idiote à part, je pensais à ça mais à plus bas niveau, à savoir plutôt des choses comme l'Entity Component System. Et pour ce qui est d'aider : allez donc voir le paquet de lien à son sujet dans la banque du forum.

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+1 -1
Staff

Comme tu le dit toi-même, ça fait un sacré paquet de classe. Trop, probablement.

Je vois au moins deux problèmes : la classe ville qui est une classe maitresse, qui contient absolument toute les données du jeu, et les héritages multiples. La classe batiment ne contient pas grand chose, alors qu'en substance, que Clara habite ou travaille dans le batiment ne changez pas grand chose, elle paye un loyer au lieu de gagner un salaire, ça reste de l'argent gagné (personne ne dit qu'il a gagné -500€ en loyer, mais mathématiquement, ça marche). :-° Je pensez que si on voulait aller plus loin, ça deviendrait très vite le bazar.

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+2 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte