LeetCode en Mendix:Entrez dans le donjon
Si vous venez de suivre cette série pour la première fois, voici un récapitulatif de ce qui s'est passé jusqu'à présent : j'ai pensé que ce serait un défi amusant de prendre des problèmes LeetCode que les développeurs utilisent pour se préparer à des entretiens potentiels - et de les résoudre en utilisant le low-code. Dans notre premier défi - La somme de ses parties – nous avons pris un problème simple comme point de départ et avons utilisé Mendix pour le résoudre. Ensuite, nous avons augmenté la mise et opté pour un défi de difficulté moyenne, dont vous pouvez tout lire dans notre article Les deux tours.
La recherche de la quête parfaite
Il est maintenant temps de relever un défi difficile et c'est là que les choses commencent à devenir un peu délicates.
J'ai passé beaucoup de temps à chercher le bon défi à relever car la plupart des problèmes que j'ai rencontrés n'étaient que des reprises des problèmes antérieurs basés sur des tableaux, bien qu'avec de légères variations pour obtenir plus d'efficacité dans moins de lignes de code. Je pense qu'il est prudent de dire que nous ne pouvons pas vraiment faire cela avec Mendix et ce n’est certainement pas le but de ces articles.
La série de problèmes suivante que j'ai rencontrée concernait les tableaux multidimensionnels. Un concept relativement simple dans les langages de programmation de base et un moyen rapide de stocker des grilles de données. Dans un système basé sur des tables comme Mendix, ce n'est pas aussi élégant. Cependant, un problème m'a sauté aux yeux comme quelque chose qui pourrait être fait de manière pratique et qui était également un concept intéressant. Défi cent soixante-quatorze : « Jeu de donjon ».
Entrez dans le donjon
Les principaux éléments de notre quête :
- Le chevalier courageux et intrépide. 🛡
- Le prisonnier, attendant d'être secouru. ⛓
- Le donjon 🚨
Dans ce défi, nous allons créer un donjon à travers lequel notre brave chevalier doit s'aventurer pour sauver le prisonnier de la dernière salle. Le donjon, par commodité, est une grille carrée de salles et dans chaque salle se trouve l'un des éléments suivants :
- Rien du tout – un zéro et ça ne fait rien.
- Un démon 👿 – un nombre négatif et réduit le score de santé de notre chevalier.
- Un orbe magique 🔮 – un nombre positif et augmente le score de santé de notre chevalier.
Notre courageux chevalier doit se déplacer dans le donjon du coin supérieur gauche au coin inférieur droit en effectuant uniquement des mouvements vers la droite ou vers le bas, car il a une peur morbide d'aller à gauche et vers le haut. J'ai peut-être inventé ce dernier point, c'est juste une règle arbitraire pour ne pas rester coincé dans une boucle.
Notre travail en tant que maître du donjon est de déterminer avec quelle santé minimale notre chevalier doit commencer pour atteindre et survivre à la dernière salle ; en terminant avec un point de santé.
Dans lequel nous créons un donjon
Tout d'abord, nous avons besoin d'un moyen de stocker les données pour représenter le donjon. Quelques options se présentent :
Premièrement, il existe une solution simple qui consiste à avoir une liste directe de pièces. Pour naviguer, il suffit de passer d'une pièce à l'autre en se déplaçant d'une ligne pour un déplacement vers la droite et de n pièces pour un déplacement vers le bas, où n est le nombre de cellules de notre carré. Cela ressemble un peu à de la triche, étant donné que le défi consiste à prendre en compte un tableau multidimensionnel.
Ensuite, il y a plus Mendix Il existe une façon de procéder qui nous permet de conserver chaque pièce dans une liste, avec les index des lignes et des colonnes pour référence, et de stocker un lien de chaque pièce vers celle à sa droite et celle en dessous. Cela facilite le passage d'une pièce à l'autre via des associations. Ce n'est cependant toujours pas une représentation vraiment juste d'un tableau multidimensionnel.
Enfin, et la façon dont nous allons commencer cet exercice est de créer d'abord une entité « Row » pour représenter une ligne de cellules avec un attribut index pour les maintenir dans l'ordre. Ensuite, nous allons créer une entité enfant pour cela appelée « Cell » pour représenter chaque pièce de cette ligne, encore une fois avec un index pour les maintenir dans l'ordre. Cela agira beaucoup plus comme un tableau multidimensionnel dans la pratique. Il ne sera pas aussi efficace de naviguer que le vrai Mendix approche, mais nous essayons de rester aussi proche que possible du brief.
Nous avons notre base de données, alors remplissons-la avec des nombres. Nous ne nous soucions pas de l'efficacité pour cette partie, donc quelques boucles imbriquées feront l'affaire. J'ai également ajouté des attributs à l'entité Dungeon pour la taille de la grille et la valeur maximale de la cellule afin qu'elle puisse être configurée pour différentes plages. Pour l'instant, ils sont tous deux définis par défaut sur 10. Le corps principal du chargement de données ressemble à ceci, simple.
Si nous affichons cela à l'écran et ajoutons un peu de style SASS aux widgets de la galerie, vous obtenez quelque chose qui ressemble beaucoup au donjon de l'exemple :
Dans lequel nous planifions notre itinéraire
Nous devons maintenant traverser le donjon en gardant à l'esprit que notre chevalier ne peut se déplacer que vers la droite et vers le bas. Nous commencerons dans le coin supérieur gauche, à la référence de grille zéro-zéro, et nous vérifierons quelle est la prochaine étape optimale à partir de là. Dans l'exemple ci-dessus, ce serait une étape vers la droite. Nous voulons faire l'étape qui nous donne la valeur respective la plus élevée, qui dans ce cas est zéro. Nous devons également nous rappeler que nous devrons suivre la santé du chevalier et jusqu'où elle descend, il vaut donc probablement la peine d'ajouter un autre attribut à notre donjon pour la santé actuelle et la santé la plus basse.
Notre courageux chevalier commence son voyage dans la première cellule. Ce n'est pas un bon début car il a déjà perdu un point de santé, nous allons donc commencer notre parcours en le plaçant dans la première cellule et en calculant sa santé de départ.
Lorsque nous exécutons ceci, cela mettra à jour la première cellule pour montrer où il se trouve et mettra à jour son score de santé.
Continuons en trouvant un chemin à travers le donjon qui mène à la prochaine meilleure étape. Une façon de procéder consiste à utiliser un appel Microflow récursif qui compare les options à droite et en dessous et choisit celle qui a le meilleur impact sur la santé.
Grâce à cette fonction, nous pouvons tracer ce chemin. Ce n'est pas forcément le meilleur chemin, mais c'est au moins un chemin viable. Nous pouvons également voir quelle est la plus faible baisse de santé, donc commencer avec un point de plus que cela nous donnera une valeur de santé appropriée pour commencer. Pour l'exemple ci-dessous, nous devrions commencer notre chevalier avec 10 points de santé.
Nous avons maintenant un chemin à travers le donjon et un score de santé qui permettra à notre chevalier d'atteindre le prisonnier. Comment savons-nous que c'est le meilleur chemin, celui qui nécessitera le moins de points de santé ? La réponse est que nous ne le savons pas. Pour comprendre cela, nous devons essayer une approche ascendante qui détermine l'étape optimale à chaque point et suit le déficit de santé que le chevalier subira au cours de son voyage.
Dans lequel nous trouvons un meilleur itinéraire
Pour ce faire, nous commencerons par la fin, avec le prisonnier, et nous remonterons la grille. À chaque étape, nous devrons calculer le coût relatif du déplacement de la case dans laquelle nous nous trouvons à la suivante. Prenons un exemple de la grille :
- Nous calculons le coût relatif du passage de 0 en bas à droite à 5 ou -4.
- Passer à -4 va nous coûter 4 points de vie.
- Passer au niveau 5 ne nous coûte pas de santé, en fait, nous gagnons de la santé donc le coût relatif est de 0.
- Enfin, nous calculons le coût de la meilleure étape à partir de la case -2, qui va de -2 à 0, donc le coût final de cette case est de -2.
De Mendix Du point de vue de la méthode, cela signifie que nous allons avoir besoin d'un Microflow pour parcourir la grille, en arrière, ligne par ligne et cellule par cellule. Dans la première étape, nous ajoutons un attribut à chaque cellule dans lequel nous pouvons stocker le coût relatif de la cellule et l'afficher à l'écran.
Ensuite, nous allons obtenir la liste des lignes dont nous avons besoin et configurer une boucle pour parcourir chaque ligne dans un ordre inverse, ce qui signifie que nous aurons besoin d'un index pour suivre la ligne et d'une boucle while pour la maintenir jusqu'à ce que nous arrivions à la première ligne (ou à la dernière ligne, selon la façon dont vous le regardez !).
Comme vous pouvez le voir, nous pouvons également créer quelques listes vides. Une pour collecter les modifications apportées aux cellules à mesure que nous mettons à jour le coût relatif afin de pouvoir effectuer une mise à jour en masse à la fin, et une pour stocker les cellules de l'itération précédente afin de ne pas avoir à effectuer deux récupérations.
C'est à l'intérieur de cette nouvelle boucle que la vraie magie se produit. Nous allons récupérer la liste des cellules pour l'itération de ligne actuelle et parcourir toutes les cellules qu'elle contient. Pour chacune de ces cellules, nous allons vérifier où elle est positionnée dans la grille, car si elle se trouve en bas ou à droite, nous devons la gérer différemment des cellules qui ont deux points de sortie possibles.
Pour chaque cellule, nous devons mettre à jour le coût relatif en fonction du meilleur point de sortie. Dans le cas de la ligne du bas et de la dernière colonne, il s'agit simplement de la cellule à droite ou en dessous ajoutée à la valeur de la cellule actuelle. Dans toutes les autres cellules, il s'agit de la valeur de la cellule actuelle plus la valeur du meilleur point de sortie. Gardez à l'esprit que si la valeur finale est supérieure à zéro, nous réinitialisons simplement la valeur à zéro, car son coût relatif n'est rien. Dans le cas le plus compliqué, nous nous retrouvons avec un calcul comme celui-ci :
Ces boucles nous feront parcourir toute la grille en déplaçant notre coût relatif vers le haut et vers la gauche jusqu'à ce que nous atteignions la première cellule et que nous sortions des deux boucles. À ce stade, nous calculerons la santé de départ minimale nécessaire, qui correspond au coût relatif de la première cellule plus un, et la stockerons contre le donjon.
À ce stade, j'ai également ajouté la possibilité de configurer la taille du donjon et de le régénérer afin de pouvoir le tester sur un donjon plus petit. Cela ressemble maintenant à ceci et vous pouvez voir qu'il semble trouver la bonne réponse !
Dans lequel nous célébrons notre succès
Voilà, c'est tout ! Techniquement, nous avons accompli cette tâche difficile – place aux célébrations ! Je n'ai pas suivi les performances et je doute que ce soit aussi performant que certaines des solutions de code standard, mais c'est assez réactif pour autant que je sache et cela ressemble à une solution élégante. Si nous devions continuer, je voudrais probablement revenir au suivi du chemin optimal et marquer le chemin que notre noble chevalier devrait parcourir à travers ce donjon ignoble pour sauver notre prisonnier en péril ! Si quelqu'un veut voir cela, faites-le moi savoir.
Merci de nous avoir suivis pendant que nous testons différents défis en matière de low-code. Vous avez un problème que vous aimeriez voir résolu ensuite ? N'hésitez pas à nous contacter et à nous faire part de vos suggestions !
















