Téléchargé 2 fois
Vote des utilisateurs
4
0
Détails
Licence : Non renseignée
Mise en ligne le 1er juillet 2016
Plate-formes :
Linux, Windows
Langue : Français
Référencé dans
Navigation
LazLightsOut : une implémentation du jeu Lights Out avec Lazarus
LazLightsOut : une implémentation du jeu Lights Out avec Lazarus
Bonjour
Je vous propose un petit casse-tête amusant datant des années 90, sous forme d'un jeu électronique et transcrit plusieurs fois sous forme d'un programme de jeu. Il s'agit d'éteindre des ampoules en respectant quelques règles.
Les sources sont complets, les dépendances se limitent aux composants standards de la LCL, l'exécutable inclus est un binaire pour Linux 64 bits (Debian). La migration vers une autre plate forme supportant Lazarus ne devrait pas poser de problème.
Je l'ai développé pour le loisir et aussi pour mettre à disposition un exemple d'implémentation d'un jeu simple.
Je vous propose un petit casse-tête amusant datant des années 90, sous forme d'un jeu électronique et transcrit plusieurs fois sous forme d'un programme de jeu. Il s'agit d'éteindre des ampoules en respectant quelques règles.
Les sources sont complets, les dépendances se limitent aux composants standards de la LCL, l'exécutable inclus est un binaire pour Linux 64 bits (Debian). La migration vers une autre plate forme supportant Lazarus ne devrait pas poser de problème.
Je l'ai développé pour le loisir et aussi pour mettre à disposition un exemple d'implémentation d'un jeu simple.
Salut
Ca y est, c'est corrigé, ça roule sous Windows (testé sous XP), un exécutable Win 32bit est dorénavant fourni.
L'erreur provenait de l'appel à Update au lieu de Repaint pour rafraîchir la grille.
:edit:Les actions ne sont donc pas incriminées, cela me semblait bizarre aussi
@+
Ca y est, c'est corrigé, ça roule sous Windows (testé sous XP), un exécutable Win 32bit est dorénavant fourni.
L'erreur provenait de l'appel à Update au lieu de Repaint pour rafraîchir la grille.
:edit:Les actions ne sont donc pas incriminées, cela me semblait bizarre aussi
@+
Bonjour,
Ce n'est pas grave : le code source est livré avec des éléments qui faussent la compilation. Il suffit de supprimer les fichiers LazLightsOut.lps et LazLightsOut.res. Alors, tout rentre dans l'ordre.
Cordialement,
Gilles
PS : ces fichiers seront recréés automatiquement et... correctement .
Ce n'est pas grave : le code source est livré avec des éléments qui faussent la compilation. Il suffit de supprimer les fichiers LazLightsOut.lps et LazLightsOut.res. Alors, tout rentre dans l'ordre.
Cordialement,
Gilles
PS : ces fichiers seront recréés automatiquement et... correctement .
Bon ben maintenant, essaie avec un côté de 15 ampoules !
Je l'ai développé et compilé avec Lazarus 1.6+FPC 3.0, qu'est ce qui te laisse penser que je l'ai fait avec une ancienne version ?
J'ai employé un énumérateur pour accéder aux voisines d'une ampoule car j'avais en vue d'implémenter plus tard des voisinages plus complexes, l'unification d'accès par un itérateur qui masque le détails des accès était donc pertinente. Mais dans le programme actuel, c'est plutôt un luxe ; cela simplifie une partie du code mais n'est pas indispensable.
Les énumérateurs c'est sympa mais ils peuvent être délicats à écrire, car il faut isoler le code de l'itération dans une classe, ce qui n'est pas toujours évident. Je préférerais pouvoir définir des générateurs (comme dans Python), ils sont plus simples à mettre en œuvre, une simple itération dans une procédure suffit souvent, pas besoin de créer une classe pour cela.
J'ai voulu une interface un peu originale offrant une certaine cohérence mais n'étant pas graphiste, je me suis limité à des choix simples.
La généricité est la possibilité de paramétrer des types, ainsi une classe pourra être conçue de manière incomplète en spécifiant des types formels et inconnus dans le corps de la classe générique.
L'emploi du type générique est la spécialisation (terminologie FPC) qui consiste à spécifier les paramètres types effectifs.
Classiquement, les types génériques sont employés pour définir des types conteneurs comme des listes par exemple. L'avantage est que l'on écrit une unique fois le code de la classe, celle-ci devient un patron (au sens de la couture) pour une inifinité de classes. C'est le compilateur qui se charge de dupliquer le code issu de la spécialisation.
Pour illustrer cela, mon programme met en oeuvre la classe suivante :
C'est une liste d'objets dont le type (unique) est inconnu dans le source de la classe mais qui est référencé par un nom, ici T. Je voulais une liste d'ampoules donc, plutôt que créer un nouveau type, tout coder et gagner peut-être de bons moments de débogage, j'ai préféré exploiter le type générique en le spécialisant :
conclusion : une ligne de code et je profite du typage statique, c'est tout bénef.
Attention:
- coder un type générique demande un soin particulier pour rendre ensuite parfaitement service.
- les différences entre les classes et les autres types peuvent introduire des difficultés supplémentaires, qui sont un peu atténuées avec l'ajout récent de la fonction (intrinsèque) Default dans la version 3.0 que j'attendais avec impatience.
- les syntaxes supportant la généricité de Delphi et de FPC sont différentes, ce qui amène une rupture supplémentaire entre les deux langages. C'est tant mieux pour FPC qui trace ainsi sa propre route et n'est plus une pâle copie de D7.
Je pense que ceux qui veulent écrire du code compilable dans les 2 langages auront un travail de plus en plus compliqué, la question sera de savoir si cela en vaut la peine.
J'espère avoir éclairci quelques points. Merci de l'intérêt que vous portez à ce sujet.
Cdlt
Je l'ai développé et compilé avec Lazarus 1.6+FPC 3.0, qu'est ce qui te laisse penser que je l'ai fait avec une ancienne version ?
J'ai employé un énumérateur pour accéder aux voisines d'une ampoule car j'avais en vue d'implémenter plus tard des voisinages plus complexes, l'unification d'accès par un itérateur qui masque le détails des accès était donc pertinente. Mais dans le programme actuel, c'est plutôt un luxe ; cela simplifie une partie du code mais n'est pas indispensable.
Les énumérateurs c'est sympa mais ils peuvent être délicats à écrire, car il faut isoler le code de l'itération dans une classe, ce qui n'est pas toujours évident. Je préférerais pouvoir définir des générateurs (comme dans Python), ils sont plus simples à mettre en œuvre, une simple itération dans une procédure suffit souvent, pas besoin de créer une classe pour cela.
J'ai voulu une interface un peu originale offrant une certaine cohérence mais n'étant pas graphiste, je me suis limité à des choix simples.
La généricité est la possibilité de paramétrer des types, ainsi une classe pourra être conçue de manière incomplète en spécifiant des types formels et inconnus dans le corps de la classe générique.
L'emploi du type générique est la spécialisation (terminologie FPC) qui consiste à spécifier les paramètres types effectifs.
Classiquement, les types génériques sont employés pour définir des types conteneurs comme des listes par exemple. L'avantage est que l'on écrit une unique fois le code de la classe, celle-ci devient un patron (au sens de la couture) pour une inifinité de classes. C'est le compilateur qui se charge de dupliquer le code issu de la spécialisation.
Pour illustrer cela, mon programme met en oeuvre la classe suivante :
Code : | Sélectionner tout |
TFPGObjectList<T> = class(TFPSList)
Code : | Sélectionner tout |
TBulbList = specialize TFPGObjectList<TBulb>;
Attention:
- coder un type générique demande un soin particulier pour rendre ensuite parfaitement service.
- les différences entre les classes et les autres types peuvent introduire des difficultés supplémentaires, qui sont un peu atténuées avec l'ajout récent de la fonction (intrinsèque) Default dans la version 3.0 que j'attendais avec impatience.
- les syntaxes supportant la généricité de Delphi et de FPC sont différentes, ce qui amène une rupture supplémentaire entre les deux langages. C'est tant mieux pour FPC qui trace ainsi sa propre route et n'est plus une pâle copie de D7.
Je pense que ceux qui veulent écrire du code compilable dans les 2 langages auront un travail de plus en plus compliqué, la question sera de savoir si cela en vaut la peine.
J'espère avoir éclairci quelques points. Merci de l'intérêt que vous portez à ce sujet.
Cdlt
Les fichiers .lps sont des fichiers XML qui contiennent des informations relatives à ton environnement. Il est inutile, voire nuisible, de les lier au projet que tu diffuses : par exemple, le tien montre que tu travailles avec Lazarus 1.2.2 et FPC 2.6.4. Cela peut expliquer les erreurs rencontrées avec d'autres systèmes .
J'ai installé la version 2.6 sur Linux (Mint 17 et Ubuntu 16.04) sans problème : au moins, je dispose du compilateur FPC 3.0.0.
Pour ce qui est de la portabilité, elle ne s'applique pas dans ce cas puisque ces fichiers te sont propres.
Cordialement,
Gilles
J'ai installé la version 2.6 sur Linux (Mint 17 et Ubuntu 16.04) sans problème : au moins, je dispose du compilateur FPC 3.0.0.
Pour ce qui est de la portabilité, elle ne s'applique pas dans ce cas puisque ces fichiers te sont propres.
Cordialement,
Gilles
Bonsoir à tous,
Merci à e-ric pour ce jeu.
Je crois que j'ai gagné !
Merci.
Merci à e-ric pour ce jeu.
Je crois que j'ai gagné !
Merci.
Salut
En fait je n'en sais rien. . C'est de l'humour, bien sûr...
Le jeu est généré aléatoirement, la solution est donc connue dès le départ, il suffit de conserver les ampoules obtenues lors du tirage aléatoire.
Cdlt
Je trouve aussi ce projet très intéressant à plusieurs titres. Une chose que j'aimerais bien savoir, c'est comment le programme trouve la solution.
Le jeu est généré aléatoirement, la solution est donc connue dès le départ, il suffit de conserver les ampoules obtenues lors du tirage aléatoire.
Cdlt
J'avais deux indices :
Étrange, non ? Mais ce n'était que simple curiosité...
Cordialement,
Gilles
- le premier, très subjectif, est ta signature
- le second est le fichier .lps qui trahit ton travail : (extrait)
Code : | Sélectionner tout |
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 | <Unit8> <Filename Value="/usr/share/lazarus/1.2.0/lcl/interfaces/gtk2/gtk2widgetset.inc"/> <TopLine Value="2818"/> <CursorPos X="22" Y="2828"/> <UsageCount Value="3"/> </Unit8> <Unit9> <Filename Value="/usr/share/lazarus/1.2.0/lcl/lclintf.pas"/> <UnitName Value="LCLIntf"/> <UsageCount Value="3"/> </Unit9> <Unit10> <Filename Value="/usr/share/fpcsrc/2.6.4/rtl/inc/systemh.inc"/> <TopLine Value="648"/> <CursorPos X="64" Y="596"/> <UsageCount Value="10"/> </Unit10> <Unit11> <Filename Value="/usr/share/fpcsrc/2.6.4/rtl/linux/system.pp"/> <UnitName Value="System"/> <TopLine Value="119"/> <CursorPos X="6" Y="140"/> <UsageCount Value="3"/> </Unit11> <Unit12> <Filename Value="/usr/share/fpcsrc/2.6.4/rtl/inc/system.inc"/> <TopLine Value="547"/> <CursorPos X="43" Y="576"/> <UsageCount Value="3"/> </Unit12> <Unit13> <Filename Value="/usr/share/lazarus/1.2.2/lcl/grids.pas"/> <UnitName Value="Grids"/> <CursorPos Y="14"/> <UsageCount Value="3"/> </Unit13> <Unit14> <Filename Value="/usr/share/lazarus/1.2.2/lcl/graphics.pp"/> <UnitName Value="Graphics"/> <TopLine Value="411"/> <CursorPos X="14" Y="425"/> <UsageCount Value="6"/> </Unit14> <Unit15> <Filename Value="/usr/share/fpcsrc/2.6.4/rtl/objpas/fgl.pp"/> <TopLine Value="263"/> <CursorPos X="10" Y="272"/> <UsageCount Value="21"/> </Unit15> |
Cordialement,
Gilles
et pourtant seuls Laz1.6 est installé sur ma Debian. Mais il est vrai que j'ai commencé le projet avec une ancienne version de Laz.
Ah oui, effectivement, je n'ai pas mis à jour ma signature, je vais le faire.
@+
Ah oui, effectivement, je n'ai pas mis à jour ma signature, je vais le faire.
@+
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.