Pour résoudre le problème if web , vous pouvez créer un moteur de règles dans lequel chaque règle spécifique est codée indépendamment. Un raffinement supplémentaire dans ce sens consisterait à créer un langage spécifique au domaine (DSL) pour créer les règles. Toutefois, un DSL seul déplace uniquement le problème d’une base de code (principale) à une autre (DSL). Sans structure, la DSL ne sera pas mieux lotie que le langage natif (Java, C #, etc.), nous y reviendrons dès que nous aurons trouvé une approche structurelle améliorée.
Le problème fondamental est que vous rencontrez un problème de modélisation. Chaque fois que vous rencontrez des situations combinatoires comme celle-ci, cela indique clairement que votre abstraction de modèle décrivant la situation est trop grossière. Vous combinez probablement des éléments qui doivent appartenir à différents modèles dans une même entité.
Si vous continuez à décomposer votre modèle, vous finirez par dissoudre complètement cet effet combinatoire. Cependant, lorsque vous empruntez ce chemin, il est facile de vous perdre dans votre conception, créant ainsi un désordre encore plus grand. Le perfectionnisme n’est pas nécessairement votre ami.
Les machines à états finis et les moteurs de règles ne sont qu'un exemple de la manière dont ce problème peut être décomposé et rendu plus gérable. L'idée principale ici est qu'un bon moyen d'éliminer un problème combinatoire tel que celui-ci est souvent de créer un dessin et de le répéter ad-nauseam à des niveaux d'abstraction imbriqués jusqu'à ce que votre système fonctionne de manière satisfaisante. Semblable à la façon dont les fractales sont utilisées pour créer des motifs complexes. Les règles restent les mêmes, que vous regardiez votre système avec un microscope ou avec une vue à vol d'oiseau.
Exemple d'application de ceci à votre domaine.
Vous essayez de modéliser la façon dont les vaches se déplacent sur un terrain. Bien que votre question manque de détails, je suppose que votre grande quantité de ifs inclut un fragment de décision tel que, if cow.isStanding then cow.canRun = true
mais vous vous perdez à mesure que vous ajoutez des détails de terrain, par exemple. Donc, pour chaque action que vous souhaitez entreprendre, vous devez vérifier tous les aspects auxquels vous pouvez penser et répéter ces vérifications pour la prochaine action possible.
Nous avons d’abord besoin de notre conception répétable, qui dans ce cas sera un FSM pour modéliser les états changeants de la simulation. La première chose à faire est donc de mettre en œuvre un FSM de référence, en définissant une interface d' état , une interface de transition et peut-être un contexte de transition.qui peut contenir des informations partagées à mettre à la disposition des deux autres. Une implémentation FSM de base bascule d'une transition à une autre, quel que soit le contexte. C'est ici qu'un moteur de règles entre en jeu. Le moteur de règles résume proprement les conditions à remplir pour que la transition se produise. Un moteur de règles peut être aussi simple qu'une liste de règles, chacune ayant une fonction d'évaluation retournant un booléen. Pour vérifier si une transition doit se produire, nous parcourons la liste des règles et, si l'une d'entre elles est évaluée comme étant fausse, la transition n'a pas lieu. La transition elle-même contiendra le code de comportement permettant de modifier l'état actuel du FSM (et d'autres tâches possibles).
Maintenant, si je commence à implémenter la simulation en tant que grand FSM unique au niveau de DIEU, je me retrouve avec BEAUCOUP d'états possibles, de transitions, etc. Maintenant, une règle effectue un test sur une information spécifique du contexte (qui contient à peu près tout le contenu) et chaque corps IF se trouve quelque part dans le code de transition.
Entrez la répartition des fractales: la première étape serait de créer un FSM pour chaque vache dans lequel les états sont les états internes de la vache (debout, courir, marcher, pâturage, etc.) et les transitions entre eux seraient influencés par l'environnement. Il est possible que le graphique ne soit pas complet. Par exemple, le pâturage n'est accessible qu'à partir de l'état permanent. Toute autre transition est dissoute car simplement absente du modèle. Ici, vous séparez efficacement les données dans deux modèles différents, la vache et le terrain. Chacun avec son propre ensemble de propriétés. Cette répartition vous permettra de simplifier la conception globale de votre moteur. Désormais, au lieu d’avoir un seul moteur de règles qui décide tout, vous disposez de plusieurs moteurs de règles plus simples (un pour chaque transition) qui déterminent des détails très spécifiques.
Comme je réutilise le même code pour le FSM, il s’agit essentiellement d’une configuration du FSM. Rappelez-vous quand nous avons mentionné plus tôt DSL? C’est là que le DSL peut faire beaucoup de bien si vous avez beaucoup de règles et de transitions à écrire.
Aller plus loin
Maintenant, DIEU n'a plus à gérer toute la complexité de la gestion des états internes de la vache, mais nous pouvons aller plus loin. La gestion du terrain, par exemple, reste complexe. C'est ici que vous décidez où la ventilation est suffisante. Si, par exemple, dans votre DIEU vous finissez par gérer la dynamique du terrain (herbe longue, boue, boue sèche, herbe courte, etc.), vous pouvez répéter le même schéma. Rien ne vous empêche d’intégrer une telle logique dans le terrain lui-même en extrayant tous les états de terrain (herbe longue, herbe courte, boueuse, sèche, etc.) dans un nouveau FSM de terrain avec des transitions entre les états et peut-être de simples règles. Par exemple, pour arriver à l'état boueux, le moteur de règles doit vérifier le contexte pour rechercher des liquides, sinon ce n'est pas possible. Maintenant, DIEU est encore plus simple.
Vous pouvez compléter le système de FSM en les rendant autonomes et en leur donnant chacun un fil. Cette dernière étape n'est pas nécessaire, mais elle vous permet de modifier dynamiquement l'interaction du système en modifiant la manière dont vous déléguez votre prise de décision (lancement d'un FSM spécialisé ou simplement retour d'un état prédéterminé).
Rappelez-vous comment nous avons mentionné que les transitions pourraient aussi faire "d'autres tâches possibles"? Explorons cela en ajoutant la possibilité pour différents modèles (FSM) de communiquer les uns avec les autres. Vous pouvez définir un ensemble d'événements et autoriser chaque FSM à enregistrer un écouteur pour ces événements. Ainsi, si, par exemple, une vache entre dans un hex de terrain, il peut enregistrer des écouteurs pour les changements de transition. Ici, cela devient un peu délicat, car chaque FSM est implémenté à un très haut niveau sans aucune connaissance du domaine spécifique qu’il héberge. Cependant, vous pouvez y parvenir en demandant à la vache de publier une liste d'événements et la cellule peut s'enregistrer si elle voit les événements auxquels elle peut réagir. Une bonne hiérarchie de famille d’événement est un bon investissement.
Vous pouvez pousser plus loin encore en modélisant les niveaux de nutriments et le cycle de croissance de l'herbe, avec… vous l'aurez deviné… un FSM d'herbe intégré dans le propre modèle du terrain.
Si vous poussez l’idée suffisamment loin, DIEU n’a que très peu à faire car tous les aspects sont assez autogérés, ce qui vous permet de consacrer plus de temps à des activités plus pieuses.
résumer
Comme indiqué ci-dessus, le FSM n’est pas la solution, c’est juste un moyen d’illustrer que la solution à un tel problème ne se trouve pas dans le code mais à la manière dont vous modélisez votre problème. Il existe probablement d'autres solutions possibles et probablement bien meilleures que celles proposées par mon FSM. Cependant, l’approche "fractale" reste un bon moyen de gérer cette difficulté. Si cela est fait correctement, vous pouvez allouer dynamiquement des niveaux plus profonds là où cela compte tout en donnant des modèles plus simples là où cela compte moins. Vous pouvez mettre en file d'attente les modifications et les appliquer lorsque les ressources deviennent plus disponibles. Dans une séquence d'action, il peut ne pas être très important de calculer le transfert d'éléments nutritifs d'une vache à l'herbe. Vous pouvez cependant enregistrer ces transitions et appliquer les modifications ultérieurement ou simplement approximer avec une supposition éclairée en remplaçant simplement les moteurs de règles ou peut-être en remplaçant complètement l'implémentation de FSM par une version naïve plus simple pour les éléments qui ne sont pas dans le champ direct de intérêt (cette vache à l’autre bout du champ) à permettre des interactions plus détaillées pour obtenir le focus et une plus grande part des ressources. Tout cela sans jamais revoir le système dans son ensemble; comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin. comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin. comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin.
Je donnerais un exemple de code, mais c’est tout ce que je peux me permettre de faire maintenant.